# # 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