157 lines
4.9 KiB
Python
157 lines
4.9 KiB
Python
#
|
|
# Code under the MIT license by Alexander Pruss
|
|
#
|
|
|
|
from mc import *
|
|
import mcpi.settings
|
|
import cmath
|
|
import time
|
|
import sys
|
|
|
|
ESCAPE = 256
|
|
if len(sys.argv) < 2:
|
|
SIZE = 640 if not mcpi.settings.isPE else 400
|
|
else:
|
|
SIZE = int(sys.argv[1])
|
|
|
|
if len(sys.argv) < 3:
|
|
formula = lambda z,c : z * z + c
|
|
else:
|
|
formula = eval('lambda z,c : '+sys.argv[2])
|
|
|
|
black = WOOL_BLACK
|
|
#palette = ( WOOL_WHITE, WOOL_ORANGE, WOOL_MAGENTA, WOOL_LIGHT_BLUE,
|
|
# WOOL_YELLOW, WOOL_LIME, WOOL_PINK, WOOL_GRAY, WOOL_LIGHT_GRAY,
|
|
# WOOL_CYAN, WOOL_PURPLE, WOOL_BLUE, WOOL_BROWN, WOOL_GREEN,
|
|
# WOOL_RED, 152 )
|
|
|
|
|
|
# palette generated by solving traveling salesman problems in RGB space
|
|
#palette = (WOOL_WHITE,WOOL_LIGHT_GRAY,WOOL_LIGHT_BLUE,WOOL_CYAN,WOOL_LIME,WOOL_YELLOW,WOOL_ORANGE,152,WOOL_RED,WOOL_BROWN,WOOL_GREEN,WOOL_GRAY,WOOL_BLUE,WOOL_PURPLE,WOOL_MAGENTA,WOOL_PINK)
|
|
palette = (WOOL_WHITE,HARDENED_CLAY_STAINED_WHITE,WOOL_PINK,WOOL_MAGENTA,WOOL_PURPLE,HARDENED_CLAY_STAINED_LIGHT_BLUE,HARDENED_CLAY_STAINED_CYAN,HARDENED_CLAY_STAINED_PURPLE,HARDENED_CLAY_STAINED_LIGHT_GRAY,HARDENED_CLAY_STAINED_MAGENTA,HARDENED_CLAY_STAINED_PINK,HARDENED_CLAY_STAINED_RED,WOOL_RED,REDSTONE_BLOCK,HARDENED_CLAY_STAINED_ORANGE,WOOL_ORANGE,HARDENED_CLAY_STAINED_YELLOW,WOOL_YELLOW,WOOL_LIME,HARDENED_CLAY_STAINED_LIME,HARDENED_CLAY_STAINED_GREEN,WOOL_GREEN,HARDENED_CLAY_STAINED_GRAY,WOOL_BROWN,HARDENED_CLAY_STAINED_BROWN,WOOL_GRAY,HARDENED_CLAY_STAINED_BLUE,WOOL_BLUE,WOOL_CYAN,WOOL_LIGHT_BLUE,WOOL_LIGHT_GRAY)
|
|
|
|
def escapeTime(c):
|
|
i = 0
|
|
z = c
|
|
try:
|
|
while abs(z) < 2 and i < ESCAPE:
|
|
i = i + 1
|
|
z = formula(z,c)
|
|
return i
|
|
except:
|
|
return -1
|
|
|
|
#
|
|
# we could of course just do for x in range(0,size): for y in range(0,size): yield(x,y)
|
|
# but it will make users happier if we start at the player
|
|
#
|
|
|
|
def loopGenerator(size, cenX, cenY):
|
|
yield (cenX, cenY)
|
|
for r in range(1,size):
|
|
# right line segment
|
|
if cenX+r < size:
|
|
y = cenY - r
|
|
if y < 0:
|
|
y = 0
|
|
while y < cenY + r and y < size:
|
|
yield (cenX+r, y)
|
|
y += 1
|
|
# top line segment
|
|
if cenY+r < size:
|
|
x = cenX + r
|
|
if x >= size:
|
|
x = size - 1
|
|
while cenX - r < x and 0 <= x:
|
|
yield (x, cenY+r)
|
|
x -= 1
|
|
# left line segment
|
|
if 0 <= cenX-r:
|
|
y = cenY + r
|
|
if y >= size:
|
|
y = size - 1
|
|
while cenY - r < y and 0 <= y:
|
|
yield (cenX-r, y)
|
|
y -= 1
|
|
# bottom line segment
|
|
if 0 <= cenY-r:
|
|
x = cenX - r
|
|
if x < 0:
|
|
x = 0
|
|
while x < cenX + r and x < size:
|
|
yield(x, cenY - r)
|
|
x += 1
|
|
|
|
def pollZoom():
|
|
global lastHitEvent
|
|
events = mc.events.pollBlockHits()
|
|
if len(events) == 0:
|
|
return lastHitEvent != None
|
|
lastHitEvent = events[-1]
|
|
return True
|
|
|
|
def toComplex(x,y):
|
|
return complex((x - centerMC.x) * scale + centerCx.real,
|
|
(y - centerMC.z) * scale + centerCx.imag)
|
|
|
|
def draw():
|
|
count = 0
|
|
for (x,y) in loopGenerator(SIZE, SIZE/2, SIZE/2):
|
|
mcX = x + centerMC.x - SIZE/2
|
|
mcY = y + centerMC.z - SIZE/2
|
|
c = toComplex(mcX, mcY)
|
|
|
|
esc = escapeTime(c)
|
|
if esc < 0:
|
|
block = AIR
|
|
elif esc < ESCAPE:
|
|
block = palette[esc % len(palette)]
|
|
else:
|
|
block = black
|
|
mc.setBlock(mcX, centerMC.y, mcY,block)
|
|
if count >= 1000:
|
|
if pollZoom():
|
|
break
|
|
else:
|
|
count = 0
|
|
else:
|
|
count += 1
|
|
|
|
def formatComplex(z):
|
|
return "%.2g+%.2gi" % (z.real,z.imag)
|
|
|
|
def getInfo():
|
|
return ( "Center: "+formatComplex(centerCx)+", range from "+
|
|
formatComplex(toComplex(centerMC.x - SIZE/2, centerMC.z - SIZE/2))+" to "+
|
|
formatComplex(toComplex(centerMC.x + SIZE/2 - 1, centerMC.z + SIZE/2 - 1)) )
|
|
|
|
mc = Minecraft()
|
|
centerMC = mc.player.getPos()
|
|
centerMC.ifloor()
|
|
adjustedPlayer = centerMC.clone()
|
|
adjustedPlayer.y += 1
|
|
centerCx = complex(0,0)
|
|
scale = 4. / SIZE
|
|
lastHitEvent = None
|
|
|
|
while True:
|
|
mc.player.setPos(adjustedPlayer)
|
|
mc.postToChat(getInfo())
|
|
draw()
|
|
mc.postToChat("Rendered")
|
|
while not pollZoom():
|
|
time.sleep(0.25)
|
|
if ( lastHitEvent.pos.y != centerMC.y or
|
|
lastHitEvent.pos.x < centerMC.x - SIZE / 2 or
|
|
lastHitEvent.pos.x >= centerMC.x + SIZE / 2 or
|
|
lastHitEvent.pos.z < centerMC.z - SIZE / 2 or
|
|
lastHitEvent.pos.z >= centerMC.z + SIZE / 2 ):
|
|
mc.postToChat("resetting")
|
|
centerCx = complex(0,0)
|
|
scale = 4. / SIZE
|
|
else:
|
|
mc.postToChat("zooming")
|
|
centerCx = toComplex(lastHitEvent.pos.x,lastHitEvent.pos.z)
|
|
scale /= 2
|
|
lastHitEvent = None
|