def transform_image_side(img, blockID=None): """Takes an image and shears it for the left side of the cube (reflect for the right side)""" if blockID in (44, ): # step block # make the top half transparent # (don't just crop img, since we want the size of # img to be unchanged mask = img.crop((0, 8, 16, 16)) n = Image.new(img.mode, img.size, (38, 92, 255, 0)) composite.alpha_over(n, mask, (0, 0, 16, 8), mask) img = n if blockID in (78, ): # snow # make the top three quarters transparent mask = img.crop((0, 12, 16, 16)) n = Image.new(img.mode, img.size, (38, 92, 255, 0)) composite.alpha_over(n, mask, (0, 12, 16, 16), mask) img = n # Size of the cube side before shear img = img.resize((12, 12)) # Apply shear transform = numpy.matrix(numpy.identity(3)) transform *= numpy.matrix("[1,0,0;-0.5,1,0;0,0,1]") transform = numpy.array(transform)[:2, :].ravel().tolist() newimg = img.transform((12, 18), Image.AFFINE, transform) return newimg
def transform_image_side(img, blockID=None): """Takes an image and shears it for the left side of the cube (reflect for the right side)""" if blockID in (44,): # step block # make the top half transparent # (don't just crop img, since we want the size of # img to be unchanged mask = img.crop((0,8,16,16)) n = Image.new(img.mode, img.size, (38,92,255,0)) composite.alpha_over(n, mask,(0,0,16,8), mask) img = n if blockID in (78,): # snow # make the top three quarters transparent mask = img.crop((0,12,16,16)) n = Image.new(img.mode, img.size, (38,92,255,0)) composite.alpha_over(n, mask,(0,12,16,16), mask) img = n # Size of the cube side before shear img = img.resize((12,12)) # Apply shear transform = numpy.matrix(numpy.identity(3)) transform *= numpy.matrix("[1,0,0;-0.5,1,0;0,0,1]") transform = numpy.array(transform)[:2,:].ravel().tolist() newimg = img.transform((12,18), Image.AFFINE, transform) return newimg
def chunk_render(self, img=None, xoff=0, yoff=0, cave=False): """Renders a chunk with the given parameters, and returns the image. If img is given, the chunk is rendered to that image object. Otherwise, a new one is created. xoff and yoff are offsets in the image. For cave mode, all blocks that have any direct sunlight are not rendered, and blocks are drawn with a color tint depending on their depth.""" blocks = self.blocks pseudo_ancildata_blocks = set([85]) left_blocks = self.left_blocks right_blocks = self.right_blocks if cave: # Cave mode. Actually go through and 0 out all blocks that are not in a # cave, so that it only renders caves. # Places where the skylight is not 0 (there's some amount of skylight # touching it) change it to something that won't get rendered, AND # won't get counted as "transparent". blocks = blocks.copy() blocks[self.skylight != 0] = 21 blockData = get_blockdata_array(self.level) blockData_expanded = numpy.empty((16,16,128), dtype=numpy.uint8) # Even elements get the lower 4 bits blockData_expanded[:,:,::2] = blockData & 0x0F # Odd elements get the upper 4 bits blockData_expanded[:,:,1::2] = blockData >> 4 tileEntities = get_tileentity_data(self.level) if self.world.useBiomeData: biomeColorData = textures.getBiomeData(self.world.worlddir, self.chunkX, self.chunkY) # in the 32x32 block of biome data, what chunk is this?l startX = self.chunkX % 32 startY = self.chunkY % 32 # Each block is 24x24 # The next block on the X axis adds 12px to x and subtracts 6px from y in the image # The next block on the Y axis adds 12px to x and adds 6px to y in the image # The next block up on the Z axis subtracts 12 from y axis in the image # Since there are 16x16x128 blocks in a chunk, the image will be 384x1728 # (height is 128*12 high, plus the size of the horizontal plane: 16*12) if not img: img = Image.new("RGBA", (384, 1728), (38,92,255,0)) for x in xrange(15,-1,-1): for y in xrange(16): imgx = xoff + x*12 + y*12 imgy = yoff - x*6 + y*6 + 128*12 + 16*12//2 imgy += 12 for z in xrange(128): imgy -= 12 blockid = blocks[x,y,z] # the following blocks don't have textures that can be pre-computed from the blockid # alone. additional data is required. # TODO torches, redstone torches, crops, ladders, stairs, # levers, doors, buttons, and signs all need to be handled here (and in textures.py) ## minecart track, crops, ladder, doors, etc. if blockid in textures.special_blocks: # also handle furnaces here, since one side has a different texture than the other ancilData = blockData_expanded[x,y,z] try: if blockid in pseudo_ancildata_blocks: pseudo_ancilData = self.generate_pseudo_ancildata(x,y,z,blockid) ancilData = pseudo_ancilData t = textures.specialblockmap[(blockid, ancilData)] except KeyError: t = None else: t = textures.blockmap[blockid] if not t: continue if self.world.useBiomeData: # 16 : number of blocks in a chunk (in one direction) # 32 : number of chunks in a region (and biome file) in one direction # so 16 * 32 == 512 : number of blocks in biome file, in one direction if blockid == 2: #grass index = biomeColorData[ ((startY*16)+y) * 512 + (startX*16) + x] c = textures.grasscolor[index] # only tint the top texture t = textures.prepareGrassTexture(c) elif blockid == 18: # leaves index = biomeColorData[ ((startY*16)+y) * 512 + (startX*16) + x] c = textures.foliagecolor[index] t = textures.prepareLeafTexture(c) # Check if this block is occluded if cave and ( x == 0 and y != 15 and z != 127 ): # If it's on the x face, only render if there's a # transparent block in the y+1 direction OR the z-1 # direction if ( blocks[x,y+1,z] not in transparent_blocks and blocks[x,y,z+1] not in transparent_blocks ): continue elif cave and ( y == 15 and x != 0 and z != 127 ): # If it's on the facing y face, only render if there's # a transparent block in the x-1 direction OR the z-1 # direction if ( blocks[x-1,y,z] not in transparent_blocks and blocks[x,y,z+1] not in transparent_blocks ): continue elif cave and ( y == 15 and x == 0 and z != 127 ): # If it's on the facing edge, only render if what's # above it is transparent if ( blocks[x,y,z+1] not in transparent_blocks ): continue elif (left_blocks == None and right_blocks == None): # Normal block or not cave mode, check sides for # transparentcy or render if it's a border chunk. if ( x != 0 and y != 15 and z != 127 and blocks[x-1,y,z] not in transparent_blocks and blocks[x,y+1,z] not in transparent_blocks and blocks[x,y,z+1] not in transparent_blocks ): continue elif (left_blocks != None and right_blocks == None): if ( # If it has the left face covered check for # transparent blocks in left face y != 15 and z != 127 and (left_blocks[15,y,z] if x == 0 else blocks[x - 1,y,z]) not in transparent_blocks and blocks[x,y+1,z] not in transparent_blocks and blocks[x,y,z+1] not in transparent_blocks ): continue elif (left_blocks == None and right_blocks != None): if ( # If it has the right face covered check for # transparent blocks in right face x != 0 and z != 127 and blocks[x-1,y,z] not in transparent_blocks and (right_blocks[x,0,z] if y == 15 else blocks[x,y + 1,z]) not in transparent_blocks and blocks[x,y,z+1] not in transparent_blocks ): continue elif ( # If it's a interior chunk check for transparent blocks # in the adjacent chunks. z != 127 and (left_blocks[15,y,z] if x == 0 else blocks[x - 1,y,z]) not in transparent_blocks and (right_blocks[x,0,z] if y == 15 else blocks[x,y + 1,z]) not in transparent_blocks and blocks[x,y,z+1] not in transparent_blocks # Don't render if all sides aren't transparent ): continue # Draw the actual block on the image. For cave images, # tint the block with a color proportional to its depth if cave: # no lighting for cave -- depth is probably more useful composite.alpha_over(img, Image.blend(t[0],depth_colors[z],0.3), (imgx, imgy), t[1]) else: if not self.world.lighting: # no lighting at all composite.alpha_over(img, t[0], (imgx, imgy), t[1]) elif blockid in transparent_blocks: # transparent means draw the whole # block shaded with the current # block's light black_coeff, _ = self.get_lighting_coefficient(x, y, z) if self.world.spawn and black_coeff > 0.8 and blockid in solid_blocks and not ( blockid in nospawn_blocks or ( z != 127 and (blocks[x,y,z+1] in solid_blocks or blocks[x,y,z+1] in fluid_blocks) ) ): composite.alpha_over(img, Image.blend(t[0], red_color, black_coeff), (imgx, imgy), t[1]) else: composite.alpha_over(img, Image.blend(t[0], black_color, black_coeff), (imgx, imgy), t[1]) else: # draw each face lit appropriately, # but first just draw the block composite.alpha_over(img, t[0], (imgx, imgy), t[1]) # top face black_coeff, face_occlude = self.get_lighting_coefficient(x, y, z + 1) # Use red instead of black for spawnable blocks if self.world.spawn and black_coeff > 0.8 and blockid in solid_blocks and not ( blockid in nospawn_blocks or ( z != 127 and (blocks[x,y,z+1] in solid_blocks or blocks[x,y,z+1] in fluid_blocks) ) ): over_color = red_color else: over_color = black_color if not face_occlude: composite.alpha_over(img, over_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[0]).enhance(black_coeff)) # left face black_coeff, face_occlude = self.get_lighting_coefficient(x - 1, y, z) if not face_occlude: composite.alpha_over(img, over_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[1]).enhance(black_coeff)) # right face black_coeff, face_occlude = self.get_lighting_coefficient(x, y + 1, z) if not face_occlude: composite.alpha_over(img, over_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[2]).enhance(black_coeff)) # Draw edge lines if blockid in (44,): # step block increment = 6 elif blockid in (78,): # snow increment = 9 else: increment = 0 if blockid not in transparent_blocks or blockid in (78,): #special case snow so the outline is still drawn draw = ImageDraw.Draw(img) if x != 15 and blocks[x+1,y,z] == 0: draw.line(((imgx+12,imgy+increment), (imgx+22,imgy+5+increment)), fill=(0,0,0), width=1) if y != 0 and blocks[x,y-1,z] == 0: draw.line(((imgx,imgy+6+increment), (imgx+12,imgy+increment)), fill=(0,0,0), width=1) for entity in tileEntities: if entity['id'] == 'Sign': msg=' \n'.join([entity['Text1'], entity['Text2'], entity['Text3'], entity['Text4']]) if msg.strip(): # convert the blockID coordinates from local chunk # coordinates to global world coordinates newPOI = dict(type="sign", x= entity['x'], y= entity['y'], z= entity['z'], msg=msg, chunk= (self.chunkX, self.chunkY), ) self.queue.put(["newpoi", newPOI]) # check to see if there are any signs in the persistentData list that are from this chunk. # if so, remove them from the persistentData list (since they're have been added to the world.POI # list above. self.queue.put(['removePOI', (self.chunkX, self.chunkY)]) return img
# Ignore if file doesn't exist, another task could have already # removed it. if e.errno != errno.ENOENT: logging.warning("Could not remove chunk '{0}'!".format(chunkfile)) raise else: logging.warning("Removed the corrupt file") logging.warning("You will need to re-run the Overviewer to fix this chunk") continue xpos = -192 + (col - colstart) * 192 ypos = -96 + (row - rowstart) * 96 composite.alpha_over(tileimg, chunkimg.convert("RGB"), (xpos, ypos), chunkimg) # Save them tileimg.save(imgpath) if optimizeimg: optimize_image(imgpath, imgformat, optimizeimg) with open(hashpath, "wb") as hashout: hashout.write(digest) class FakeResult(object): def __init__(self, res): self.res = res
def generate_special_texture(blockID, data): """Generates a special texture, such as a correctly facing minecraft track""" #print "%s has ancillary data: %X" %(blockID, data) # TODO torches, redstone torches, crops, ladders, stairs, # levers, doors, buttons, and signs all need to be handled here (and in chunkpy) if blockID == 66: # minetrack: raw_straight = terrain_images[128] raw_corner = terrain_images[112] ## use transform_image to scale and shear if data == 0: track = transform_image(raw_straight, blockID) elif data == 6: track = transform_image(raw_corner, blockID) elif data == 7: track = transform_image(raw_corner.rotate(270), blockID) elif data == 8: # flip track = transform_image(raw_corner.transpose(Image.FLIP_TOP_BOTTOM).rotate(90), blockID) elif data == 9: track = transform_image(raw_corner.transpose(Image.FLIP_TOP_BOTTOM), blockID) elif data == 1: track = transform_image(raw_straight.rotate(90), blockID) #slopes elif data == 2: # slope going up in +x direction track = transform_image_slope(raw_straight,blockID) track = track.transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, track, (2,0), track) # the 2 pixels move is needed to fit with the adjacent tracks return (img.convert("RGB"), img.split()[3]) elif data == 3: # slope going up in -x direction # tracks are sprites, in this case we are seeing the "side" of # the sprite, so draw a line to make it beautiful. img = Image.new("RGBA", (24,24), (38,92,255,0)) ImageDraw.Draw(img).line([(11,11),(23,17)],fill=(164,164,164)) # grey from track texture (exterior grey). # the track doesn't start from image corners, be carefull drawing the line! return (img.convert("RGB"), img.split()[3]) elif data == 4: # slope going up in -y direction track = transform_image_slope(raw_straight,blockID) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, track, (0,0), track) return (img.convert("RGB"), img.split()[3]) elif data == 5: # slope going up in +y direction # same as "data == 3" img = Image.new("RGBA", (24,24), (38,92,255,0)) ImageDraw.Draw(img).line([(1,17),(12,11)],fill=(164,164,164)) return (img.convert("RGB"), img.split()[3]) else: # just in case track = transform_image(raw_straight, blockID) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, track, (0,12), track) return (img.convert("RGB"), img.split()[3]) if blockID == 59: # crops raw_crop = terrain_images[88+data] crop1 = transform_image(raw_crop, blockID) crop2 = transform_image_side(raw_crop, blockID) crop3 = crop2.transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, crop1, (0,12), crop1) composite.alpha_over(img, crop2, (6,3), crop2) composite.alpha_over(img, crop3, (6,3), crop3) return (img.convert("RGB"), img.split()[3]) if blockID == 61: #furnace top = transform_image(terrain_images[62]) side1 = transform_image_side(terrain_images[45]) side2 = transform_image_side(terrain_images[44]).transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, side1, (0,6), side1) composite.alpha_over(img, side2, (12,6), side2) composite.alpha_over(img, top, (0,0), top) return (img.convert("RGB"), img.split()[3]) if blockID in (86,91): # jack-o-lantern top = transform_image(terrain_images[102]) frontID = 119 if blockID == 86 else 120 side1 = transform_image_side(terrain_images[frontID]) side2 = transform_image_side(terrain_images[118]).transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, side1, (0,6), side1) composite.alpha_over(img, side2, (12,6), side2) composite.alpha_over(img, top, (0,0), top) return (img.convert("RGB"), img.split()[3]) if blockID == 62: # lit furnace top = transform_image(terrain_images[62]) side1 = transform_image_side(terrain_images[45]) side2 = transform_image_side(terrain_images[45+16]).transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, side1, (0,6), side1) composite.alpha_over(img, side2, (12,6), side2) composite.alpha_over(img, top, (0,0), top) return (img.convert("RGB"), img.split()[3]) if blockID == 23: # dispenser top = transform_image(terrain_images[62]) side1 = transform_image_side(terrain_images[46]) side2 = transform_image_side(terrain_images[45]).transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, side1, (0,6), side1) composite.alpha_over(img, side2, (12,6), side2) composite.alpha_over(img, top, (0,0), top) return (img.convert("RGB"), img.split()[3]) if blockID == 65: # ladder raw_texture = terrain_images[83] #print "ladder is facing: %d" % data if data == 5: # normally this ladder would be obsured by the block it's attached to # but since ladders can apparently be placed on transparent blocks, we # have to render this thing anyway. same for data == 2 tex = transform_image_side(raw_texture) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, tex, (0,6), tex) return (img.convert("RGB"), img.split()[3]) if data == 2: tex = transform_image_side(raw_texture).transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, tex, (12,6), tex) return (img.convert("RGB"), img.split()[3]) if data == 3: tex = transform_image_side(raw_texture).transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, tex, (0,0), tex) return (img.convert("RGB"), img.split()[3]) if data == 4: tex = transform_image_side(raw_texture) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, tex, (12,0), tex) return (img.convert("RGB"), img.split()[3]) if blockID in (64,71): #wooden door, or iron door if data & 0x8 == 0x8: # top of the door raw_door = terrain_images[81 if blockID == 64 else 82] else: # bottom of the door raw_door = terrain_images[97 if blockID == 64 else 98] # if you want to render all doors as closed, then force # force swung to be False if data & 0x4 == 0x4: swung=True else: swung=False # mask out the high bits to figure out the orientation img = Image.new("RGBA", (24,24), (38,92,255,0)) if (data & 0x03) == 0: if not swung: tex = transform_image_side(raw_door) composite.alpha_over(img, tex, (0,6), tex) else: # flip first to set the doornob on the correct side tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)) tex = tex.transpose(Image.FLIP_LEFT_RIGHT) composite.alpha_over(img, tex, (0,0), tex) if (data & 0x03) == 1: if not swung: tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT) composite.alpha_over(img, tex, (0,0), tex) else: tex = transform_image_side(raw_door) composite.alpha_over(img, tex, (12,0), tex) if (data & 0x03) == 2: if not swung: tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)) composite.alpha_over(img, tex, (12,0), tex) else: tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT) composite.alpha_over(img, tex, (12,6), tex) if (data & 0x03) == 3: if not swung: tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)).transpose(Image.FLIP_LEFT_RIGHT) composite.alpha_over(img, tex, (12,6), tex) else: tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)) composite.alpha_over(img, tex, (0,6), tex) return (img.convert("RGB"), img.split()[3]) if blockID == 2: # grass top = transform_image(tintTexture(terrain_images[0],(115,175,71))) side1 = transform_image_side(terrain_images[3]) side2 = transform_image_side(terrain_images[3]).transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, side1, (0,6), side1) composite.alpha_over(img, side2, (12,6), side2) composite.alpha_over(img, top, (0,0), top) return (img.convert("RGB"), img.split()[3]) if blockID == 51: # fire firetexture = _load_image("fire.png") side1 = transform_image_side(firetexture) side2 = transform_image_side(firetexture).transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, side1, (12,0), side1) composite.alpha_over(img, side2, (0,0), side2) composite.alpha_over(img, side1, (0,6), side1) composite.alpha_over(img, side2, (12,6), side2) return (img.convert("RGB"), img.split()[3]) if blockID == 18: # leaves t = tintTexture(terrain_images[52], (37, 118, 25)) top = transform_image(t) side1 = transform_image_side(t) side2 = transform_image_side(t).transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, side1, (0,6), side1) composite.alpha_over(img, side2, (12,6), side2) composite.alpha_over(img, top, (0,0), top) return (img.convert("RGB"), img.split()[3]) if blockID == 17: # wood: normal, birch and pines top = terrain_images[21] if data == 0: side = terrain_images[20] img = _build_block(top, side, 17) return (img.convert("RGB"), img.split()[3]) if data == 1: side = terrain_images[116] img = _build_block(top, side, 17) return (img.convert("RGB"), img.split()[3]) if data == 2: side = terrain_images[117] img = _build_block(top, side, 17) return (img.convert("RGB"), img.split()[3]) if blockID == 35: # wool if data == 0: # white top = side = terrain_images[64] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 1: # orange top = side = terrain_images[210] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 2: # magenta top = side = terrain_images[194] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 3: # light blue top = side = terrain_images[178] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 4: # yellow top = side = terrain_images[162] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 5: # light green top = side = terrain_images[146] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 6: # pink top = side = terrain_images[130] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 7: # grey top = side = terrain_images[114] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 8: # light grey top = side = terrain_images[225] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 9: # cyan top = side = terrain_images[209] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 10: # purple top = side = terrain_images[193] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 11: # blue top = side = terrain_images[177] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 12: # brown top = side = terrain_images[161] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 13: # dark green top = side = terrain_images[145] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 14: # red top = side = terrain_images[129] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 15: # black top = side = terrain_images[113] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if blockID == 85: # fences # create needed images for Big stick fence raw_texture = terrain_images[4] raw_fence_top = Image.new("RGBA", (16,16), (38,92,255,0)) raw_fence_side = Image.new("RGBA", (16,16), (38,92,255,0)) fence_top_mask = Image.new("RGBA", (16,16), (38,92,255,0)) fence_side_mask = Image.new("RGBA", (16,16), (38,92,255,0)) # generate the masks images for textures of the fence ImageDraw.Draw(fence_top_mask).rectangle((6,6,9,9),outline=(0,0,0),fill=(0,0,0)) ImageDraw.Draw(fence_side_mask).rectangle((6,1,9,15),outline=(0,0,0),fill=(0,0,0)) # create textures top and side for fence big stick composite.alpha_over(raw_fence_top,raw_texture,(0,0),fence_top_mask) composite.alpha_over(raw_fence_side,raw_texture,(0,0),fence_side_mask) # Create the sides and the top of the big stick fence_side = transform_image_side(raw_fence_side,85) fence_other_side = fence_side.transpose(Image.FLIP_LEFT_RIGHT) fence_top = transform_image(raw_fence_top,85) # Darken the sides slightly. These methods also affect the alpha layer, # so save them first (we don't want to "darken" the alpha layer making # the block transparent) sidealpha = fence_side.split()[3] fence_side = ImageEnhance.Brightness(fence_side).enhance(0.9) fence_side.putalpha(sidealpha) othersidealpha = fence_other_side.split()[3] fence_other_side = ImageEnhance.Brightness(fence_other_side).enhance(0.8) fence_other_side.putalpha(othersidealpha) # Compose the fence big stick fence_big = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(fence_big,fence_side, (4,4),fence_side) composite.alpha_over(fence_big,fence_other_side, (8,4),fence_other_side) composite.alpha_over(fence_big,fence_top, (-1,1),fence_top) # Now render the small sticks. # Create needed images raw_fence_small_side = Image.new("RGBA", (16,16), (38,92,255,0)) fence_small_side_mask = Image.new("RGBA", (16,16), (38,92,255,0)) # Generate mask ImageDraw.Draw(fence_small_side_mask).rectangle((10,1,15,3),outline=(0,0,0),fill=(0,0,0)) ImageDraw.Draw(fence_small_side_mask).rectangle((10,7,15,9),outline=(0,0,0),fill=(0,0,0)) # create the texture for the side of small sticks fence composite.alpha_over(raw_fence_small_side,raw_texture,(0,0),fence_small_side_mask) # Create the sides and the top of the small sticks fence_small_side = transform_image_side(raw_fence_small_side,85) fence_small_other_side = fence_small_side.transpose(Image.FLIP_LEFT_RIGHT) # Darken the sides slightly. These methods also affect the alpha layer, # so save them first (we don't want to "darken" the alpha layer making # the block transparent) sidealpha = fence_small_other_side.split()[3] fence_small_other_side = ImageEnhance.Brightness(fence_small_other_side).enhance(0.9) fence_small_other_side.putalpha(sidealpha) sidealpha = fence_small_side.split()[3] fence_small_side = ImageEnhance.Brightness(fence_small_side).enhance(0.9) fence_small_side.putalpha(sidealpha) # Create img to compose the fence img = Image.new("RGBA", (24,24), (38,92,255,0)) # Position of fence small sticks in img. # These postitions are strange because the small sticks of the # fence are at the very left and at the very right of the 16x16 images pos_top_left = (-2,0) pos_top_right = (14,0) pos_bottom_right = (6,4) pos_bottom_left = (6,4) # +x axis points top right direction # +y axis points bottom right direction # First compose small sticks in the back of the image, # then big stick and thecn small sticks in the front. if (data & 0b0001) == 1: composite.alpha_over(img,fence_small_side, pos_top_left,fence_small_side) # top left if (data & 0b1000) == 8: composite.alpha_over(img,fence_small_other_side, pos_top_right,fence_small_other_side) # top right composite.alpha_over(img,fence_big,(0,0),fence_big) if (data & 0b0010) == 2: composite.alpha_over(img,fence_small_other_side, pos_bottom_left,fence_small_other_side) # bottom left if (data & 0b0100) == 4: composite.alpha_over(img,fence_small_side, pos_bottom_right,fence_small_side) # bottom right return (img.convert("RGB"),img.split()[3]) return None
def _build_block(top, side, blockID=None): """From a top texture and a side texture, build a block image. top and side should be 16x16 image objects. Returns a 24x24 image """ img = Image.new("RGBA", (24,24), (38,92,255,0)) top = transform_image(top, blockID) if not side: composite.alpha_over(img, top, (0,0), top) return img side = transform_image_side(side, blockID) otherside = side.transpose(Image.FLIP_LEFT_RIGHT) # Darken the sides slightly. These methods also affect the alpha layer, # so save them first (we don't want to "darken" the alpha layer making # the block transparent) sidealpha = side.split()[3] side = ImageEnhance.Brightness(side).enhance(0.9) side.putalpha(sidealpha) othersidealpha = otherside.split()[3] otherside = ImageEnhance.Brightness(otherside).enhance(0.8) otherside.putalpha(othersidealpha) ## special case for non-block things # TODO once torches are handled by generate_special_texture, remove # them from this list if blockID in (37,38,6,39,40,50,83): ## flowers, sapling, mushrooms, regular torch, reeds # instead of pasting these blocks at the cube edges, place them in the middle: # and omit the top composite.alpha_over(img, side, (6,3), side) composite.alpha_over(img, otherside, (6,3), otherside) return img if blockID in (81,): # cacti! composite.alpha_over(img, side, (2,6), side) composite.alpha_over(img, otherside, (10,6), otherside) composite.alpha_over(img, top, (0,2), top) elif blockID in (44,): # half step # shift each texture down 6 pixels composite.alpha_over(img, side, (0,12), side) composite.alpha_over(img, otherside, (12,12), otherside) composite.alpha_over(img, top, (0,6), top) elif blockID in (78,): # snow # shift each texture down 9 pixels composite.alpha_over(img, side, (0,6), side) composite.alpha_over(img, otherside, (12,6), otherside) composite.alpha_over(img, top, (0,9), top) else: composite.alpha_over(img, side, (0,6), side) composite.alpha_over(img, otherside, (12,6), otherside) composite.alpha_over(img, top, (0,0), top) # Manually touch up 6 pixels that leave a gap because of how the # shearing works out. This makes the blocks perfectly tessellate-able for x,y in [(13,23), (17,21), (21,19)]: # Copy a pixel to x,y from x-1,y img.putpixel((x,y), img.getpixel((x-1,y))) for x,y in [(3,4), (7,2), (11,0)]: # Copy a pixel to x,y from x+1,y img.putpixel((x,y), img.getpixel((x+1,y))) return img
def chunk_render(self, img=None, xoff=0, yoff=0, cave=False): """Renders a chunk with the given parameters, and returns the image. If img is given, the chunk is rendered to that image object. Otherwise, a new one is created. xoff and yoff are offsets in the image. For cave mode, all blocks that have any direct sunlight are not rendered, and blocks are drawn with a color tint depending on their depth.""" blocks = self.blocks if cave: # Cave mode. Actually go through and 0 out all blocks that are not in a # cave, so that it only renders caves. # Places where the skylight is not 0 (there's some amount of skylight # touching it) change it to something that won't get rendered, AND # won't get counted as "transparent". blocks = blocks.copy() blocks[self.skylight != 0] = 21 blockData = get_blockdata_array(self.level) blockData_expanded = numpy.empty((16,16,128), dtype=numpy.uint8) # Even elements get the lower 4 bits blockData_expanded[:,:,::2] = blockData & 0x0F # Odd elements get the upper 4 bits blockData_expanded[:,:,1::2] = blockData >> 4 tileEntities = get_tileentity_data(self.level) # Each block is 24x24 # The next block on the X axis adds 12px to x and subtracts 6px from y in the image # The next block on the Y axis adds 12px to x and adds 6px to y in the image # The next block up on the Z axis subtracts 12 from y axis in the image # Since there are 16x16x128 blocks in a chunk, the image will be 384x1728 # (height is 128*12 high, plus the size of the horizontal plane: 16*12) if not img: img = Image.new("RGBA", (384, 1728), (38,92,255,0)) for x,y,z,imgx,imgy in iterate_chunkblocks(xoff,yoff): blockid = blocks[x,y,z] # the following blocks don't have textures that can be pre-computed from the blockid # alone. additional data is required. # TODO torches, redstone torches, crops, ladders, stairs, # levers, doors, buttons, and signs all need to be handled here (and in textures.py) ## minecart track, crops, ladder, doors, etc. if blockid in textures.special_blocks: # also handle furnaces here, since one side has a different texture than the other ancilData = blockData_expanded[x,y,z] try: t = textures.specialblockmap[(blockid, ancilData)] except KeyError: t = None else: t = textures.blockmap[blockid] if not t: continue # Check if this block is occluded if cave and ( x == 0 and y != 15 and z != 127 ): # If it's on the x face, only render if there's a # transparent block in the y+1 direction OR the z-1 # direction if ( blocks[x,y+1,z] not in transparent_blocks and blocks[x,y,z+1] not in transparent_blocks ): continue elif cave and ( y == 15 and x != 0 and z != 127 ): # If it's on the facing y face, only render if there's # a transparent block in the x-1 direction OR the z-1 # direction if ( blocks[x-1,y,z] not in transparent_blocks and blocks[x,y,z+1] not in transparent_blocks ): continue elif cave and ( y == 15 and x == 0 and z != 127 ): # If it's on the facing edge, only render if what's # above it is transparent if ( blocks[x,y,z+1] not in transparent_blocks ): continue elif ( # Normal block or not cave mode, check sides for # transparentcy or render unconditionally if it's # on a shown face x != 0 and y != 15 and z != 127 and blocks[x-1,y,z] not in transparent_blocks and blocks[x,y+1,z] not in transparent_blocks and blocks[x,y,z+1] not in transparent_blocks ): # Don't render if all sides aren't transparent and # we're not on the edge continue # Draw the actual block on the image. For cave images, # tint the block with a color proportional to its depth if cave: # no lighting for cave -- depth is probably more useful composite.alpha_over(img, Image.blend(t[0],depth_colors[z],0.3), (imgx, imgy), t[1]) else: if not self.world.lighting: # no lighting at all composite.alpha_over(img, t[0], (imgx, imgy), t[1]) elif blockid in transparent_blocks: # transparent means draw the whole # block shaded with the current # block's light black_coeff, _ = self.get_lighting_coefficient(x, y, z) composite.alpha_over(img, Image.blend(t[0], black_color, black_coeff), (imgx, imgy), t[1]) else: # draw each face lit appropriately, # but first just draw the block composite.alpha_over(img, t[0], (imgx, imgy), t[1]) # top face black_coeff, face_occlude = self.get_lighting_coefficient(x, y, z + 1) if not face_occlude: composite.alpha_over(img, black_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[0]).enhance(black_coeff)) # left face black_coeff, face_occlude = self.get_lighting_coefficient(x - 1, y, z) if not face_occlude: composite.alpha_over(img, black_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[1]).enhance(black_coeff)) # right face black_coeff, face_occlude = self.get_lighting_coefficient(x, y + 1, z) if not face_occlude: composite.alpha_over(img, black_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[2]).enhance(black_coeff)) # Draw edge lines if blockid in (44,): # step block increment = 6 elif blockid in (78,): # snow increment = 9 else: increment = 0 if blockid not in transparent_blocks or blockid in (78,): #special case snow so the outline is still drawn draw = ImageDraw.Draw(img) if x != 15 and blocks[x+1,y,z] == 0: draw.line(((imgx+12,imgy+increment), (imgx+22,imgy+5+increment)), fill=(0,0,0), width=1) if y != 0 and blocks[x,y-1,z] == 0: draw.line(((imgx,imgy+6+increment), (imgx+12,imgy+increment)), fill=(0,0,0), width=1) for entity in tileEntities: if entity['id'] == 'Sign': # convert the blockID coordinates from local chunk # coordinates to global world coordinates newPOI = dict(type="sign", x= entity['x'], y= entity['y'], z= entity['z'], msg="%s\n%s\n%s\n%s" % (entity['Text1'], entity['Text2'], entity['Text3'], entity['Text4']), chunk= (self.chunkX, self.chunkY), ) self.queue.put(["newpoi", newPOI]) # check to see if there are any signs in the persistentData list that are from this chunk. # if so, remove them from the persistentData list (since they're have been added to the world.POI # list above. self.queue.put(['removePOI', (self.chunkX, self.chunkY)]) return img
def generate_special_texture(blockID, data): """Generates a special texture, such as a correctly facing minecraft track""" #print "%s has ancillary data: %X" %(blockID, data) # TODO torches, redstone torches, crops, ladders, stairs, # levers, doors, buttons, and signs all need to be handled here (and in chunkpy) if blockID == 66: # minetrack: raw_straight = terrain_images[128] raw_corner = terrain_images[112] ## use transform_image to scale and shear if data == 0: track = transform_image(raw_straight, blockID) elif data == 6: track = transform_image(raw_corner, blockID) elif data == 7: track = transform_image(raw_corner.rotate(270), blockID) elif data == 8: # flip track = transform_image(raw_corner.transpose(Image.FLIP_TOP_BOTTOM).rotate(90), blockID) elif data == 9: track = transform_image(raw_corner.transpose(Image.FLIP_TOP_BOTTOM), blockID) elif data == 1: track = transform_image(raw_straight.rotate(90), blockID) else: # TODO render carts that slop up or down track = transform_image(raw_straight, blockID) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, track, (0,12), track) return (img.convert("RGB"), img.split()[3]) if blockID == 59: # crops raw_crop = terrain_images[88+data] crop1 = transform_image(raw_crop, blockID) crop2 = transform_image_side(raw_crop, blockID) crop3 = crop2.transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, crop1, (0,12), crop1) composite.alpha_over(img, crop2, (6,3), crop2) composite.alpha_over(img, crop3, (6,3), crop3) return (img.convert("RGB"), img.split()[3]) if blockID == 61: #furnace top = transform_image(terrain_images[1]) side1 = transform_image_side(terrain_images[45]) side2 = transform_image_side(terrain_images[44]).transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, side1, (0,6), side1) composite.alpha_over(img, side2, (12,6), side2) composite.alpha_over(img, top, (0,0), top) return (img.convert("RGB"), img.split()[3]) if blockID in (86,91): # jack-o-lantern top = transform_image(terrain_images[102]) frontID = 119 if blockID == 86 else 120 side1 = transform_image_side(terrain_images[frontID]) side2 = transform_image_side(terrain_images[118]).transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, side1, (0,6), side1) composite.alpha_over(img, side2, (12,6), side2) composite.alpha_over(img, top, (0,0), top) return (img.convert("RGB"), img.split()[3]) if blockID == 62: # lit furnace top = transform_image(terrain_images[1]) side1 = transform_image_side(terrain_images[45]) side2 = transform_image_side(terrain_images[45+16]).transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, side1, (0,6), side1) composite.alpha_over(img, side2, (12,6), side2) composite.alpha_over(img, top, (0,0), top) return (img.convert("RGB"), img.split()[3]) if blockID == 65: # ladder raw_texture = terrain_images[83] #print "ladder is facing: %d" % data if data == 5: # normally this ladder would be obsured by the block it's attached to # but since ladders can apparently be placed on transparent blocks, we # have to render this thing anyway. same for data == 2 tex = transform_image_side(raw_texture) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, tex, (0,6), tex) return (img.convert("RGB"), img.split()[3]) if data == 2: tex = transform_image_side(raw_texture).transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, tex, (12,6), tex) return (img.convert("RGB"), img.split()[3]) if data == 3: tex = transform_image_side(raw_texture).transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, tex, (0,0), tex) return (img.convert("RGB"), img.split()[3]) if data == 4: tex = transform_image_side(raw_texture) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, tex, (12,0), tex) return (img.convert("RGB"), img.split()[3]) if blockID in (64,71): #wooden door, or iron door if data & 0x8 == 0x8: # top of the door raw_door = terrain_images[81 if blockID == 64 else 82] else: # bottom of the door raw_door = terrain_images[97 if blockID == 64 else 98] # if you want to render all doors as closed, then force # force swung to be False if data & 0x4 == 0x4: swung=True else: swung=False # mask out the high bits to figure out the orientation img = Image.new("RGBA", (24,24), (38,92,255,0)) if (data & 0x03) == 0: if not swung: tex = transform_image_side(raw_door) composite.alpha_over(img, tex, (0,6), tex) else: # flip first to set the doornob on the correct side tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)) tex = tex.transpose(Image.FLIP_LEFT_RIGHT) composite.alpha_over(img, tex, (0,0), tex) if (data & 0x03) == 1: if not swung: tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT) composite.alpha_over(img, tex, (0,0), tex) else: tex = transform_image_side(raw_door) composite.alpha_over(img, tex, (12,0), tex) if (data & 0x03) == 2: if not swung: tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)) composite.alpha_over(img, tex, (12,0), tex) else: tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT) composite.alpha_over(img, tex, (12,6), tex) if (data & 0x03) == 3: if not swung: tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)).transpose(Image.FLIP_LEFT_RIGHT) composite.alpha_over(img, tex, (12,6), tex) else: tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)) composite.alpha_over(img, tex, (0,6), tex) return (img.convert("RGB"), img.split()[3]) if blockID == 2: # grass top = transform_image(tintTexture(terrain_images[0],(170,255,50))) side1 = transform_image_side(terrain_images[3]) side2 = transform_image_side(terrain_images[3]).transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, side1, (0,6), side1) composite.alpha_over(img, side2, (12,6), side2) composite.alpha_over(img, top, (0,0), top) return (img.convert("RGB"), img.split()[3]) if blockID == 18: # leaves t = tintTexture(terrain_images[52], (170, 255, 50)) top = transform_image(t) side1 = transform_image_side(t) side2 = transform_image_side(t).transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, side1, (0,6), side1) composite.alpha_over(img, side2, (12,6), side2) composite.alpha_over(img, top, (0,0), top) return (img.convert("RGB"), img.split()[3]) return None
# removed it. if e.errno != errno.ENOENT: logging.warning( "Could not remove chunk '{0}'!".format(chunkfile)) raise else: logging.warning("Removed the corrupt file") logging.warning( "You will need to re-run the Overviewer to fix this chunk") continue xpos = -192 + (col - colstart) * 192 ypos = -96 + (row - rowstart) * 96 composite.alpha_over(tileimg, chunkimg.convert("RGB"), (xpos, ypos), chunkimg) # Save them tileimg.save(imgpath) if optimizeimg: optimize_image(imgpath, imgformat, optimizeimg) with open(hashpath, "wb") as hashout: hashout.write(digest) class FakeResult(object): def __init__(self, res): self.res = res
def generate_special_texture(blockID, data): """Generates a special texture, such as a correctly facing minecraft track""" #print "%s has ancillary data: %X" %(blockID, data) # TODO torches, redstone torches, crops, ladders, stairs, # levers, doors, buttons, and signs all need to be handled here (and in chunkpy) if blockID == 66: # minetrack: raw_straight = terrain_images[128] raw_corner = terrain_images[112] ## use transform_image to scale and shear if data == 0: track = transform_image(raw_straight, blockID) elif data == 6: track = transform_image(raw_corner, blockID) elif data == 7: track = transform_image(raw_corner.rotate(270), blockID) elif data == 8: # flip track = transform_image( raw_corner.transpose(Image.FLIP_TOP_BOTTOM).rotate(90), blockID) elif data == 9: track = transform_image( raw_corner.transpose(Image.FLIP_TOP_BOTTOM), blockID) elif data == 1: track = transform_image(raw_straight.rotate(90), blockID) #slopes elif data == 2: # slope going up in +x direction track = transform_image_slope(raw_straight, blockID) track = track.transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24, 24), (38, 92, 255, 0)) composite.alpha_over(img, track, (2, 0), track) # the 2 pixels move is needed to fit with the adjacent tracks return (img.convert("RGB"), img.split()[3]) elif data == 3: # slope going up in -x direction # tracks are sprites, in this case we are seeing the "side" of # the sprite, so draw a line to make it beautiful. img = Image.new("RGBA", (24, 24), (38, 92, 255, 0)) ImageDraw.Draw(img).line([(11, 11), (23, 17)], fill=(164, 164, 164)) # grey from track texture (exterior grey). # the track doesn't start from image corners, be carefull drawing the line! return (img.convert("RGB"), img.split()[3]) elif data == 4: # slope going up in -y direction track = transform_image_slope(raw_straight, blockID) img = Image.new("RGBA", (24, 24), (38, 92, 255, 0)) composite.alpha_over(img, track, (0, 0), track) return (img.convert("RGB"), img.split()[3]) elif data == 5: # slope going up in +y direction # same as "data == 3" img = Image.new("RGBA", (24, 24), (38, 92, 255, 0)) ImageDraw.Draw(img).line([(1, 17), (12, 11)], fill=(164, 164, 164)) return (img.convert("RGB"), img.split()[3]) else: # just in case track = transform_image(raw_straight, blockID) img = Image.new("RGBA", (24, 24), (38, 92, 255, 0)) composite.alpha_over(img, track, (0, 12), track) return (img.convert("RGB"), img.split()[3]) if blockID == 59: # crops raw_crop = terrain_images[88 + data] crop1 = transform_image(raw_crop, blockID) crop2 = transform_image_side(raw_crop, blockID) crop3 = crop2.transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24, 24), (38, 92, 255, 0)) composite.alpha_over(img, crop1, (0, 12), crop1) composite.alpha_over(img, crop2, (6, 3), crop2) composite.alpha_over(img, crop3, (6, 3), crop3) return (img.convert("RGB"), img.split()[3]) if blockID == 61: #furnace top = transform_image(terrain_images[62]) side1 = transform_image_side(terrain_images[45]) side2 = transform_image_side(terrain_images[44]).transpose( Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24, 24), (38, 92, 255, 0)) composite.alpha_over(img, side1, (0, 6), side1) composite.alpha_over(img, side2, (12, 6), side2) composite.alpha_over(img, top, (0, 0), top) return (img.convert("RGB"), img.split()[3]) if blockID in (86, 91): # jack-o-lantern top = transform_image(terrain_images[102]) frontID = 119 if blockID == 86 else 120 side1 = transform_image_side(terrain_images[frontID]) side2 = transform_image_side(terrain_images[118]).transpose( Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24, 24), (38, 92, 255, 0)) composite.alpha_over(img, side1, (0, 6), side1) composite.alpha_over(img, side2, (12, 6), side2) composite.alpha_over(img, top, (0, 0), top) return (img.convert("RGB"), img.split()[3]) if blockID == 62: # lit furnace top = transform_image(terrain_images[62]) side1 = transform_image_side(terrain_images[45]) side2 = transform_image_side(terrain_images[45 + 16]).transpose( Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24, 24), (38, 92, 255, 0)) composite.alpha_over(img, side1, (0, 6), side1) composite.alpha_over(img, side2, (12, 6), side2) composite.alpha_over(img, top, (0, 0), top) return (img.convert("RGB"), img.split()[3]) if blockID == 23: # dispenser top = transform_image(terrain_images[62]) side1 = transform_image_side(terrain_images[46]) side2 = transform_image_side(terrain_images[45]).transpose( Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24, 24), (38, 92, 255, 0)) composite.alpha_over(img, side1, (0, 6), side1) composite.alpha_over(img, side2, (12, 6), side2) composite.alpha_over(img, top, (0, 0), top) return (img.convert("RGB"), img.split()[3]) if blockID == 65: # ladder raw_texture = terrain_images[83] #print "ladder is facing: %d" % data if data == 5: # normally this ladder would be obsured by the block it's attached to # but since ladders can apparently be placed on transparent blocks, we # have to render this thing anyway. same for data == 2 tex = transform_image_side(raw_texture) img = Image.new("RGBA", (24, 24), (38, 92, 255, 0)) composite.alpha_over(img, tex, (0, 6), tex) return (img.convert("RGB"), img.split()[3]) if data == 2: tex = transform_image_side(raw_texture).transpose( Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24, 24), (38, 92, 255, 0)) composite.alpha_over(img, tex, (12, 6), tex) return (img.convert("RGB"), img.split()[3]) if data == 3: tex = transform_image_side(raw_texture).transpose( Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24, 24), (38, 92, 255, 0)) composite.alpha_over(img, tex, (0, 0), tex) return (img.convert("RGB"), img.split()[3]) if data == 4: tex = transform_image_side(raw_texture) img = Image.new("RGBA", (24, 24), (38, 92, 255, 0)) composite.alpha_over(img, tex, (12, 0), tex) return (img.convert("RGB"), img.split()[3]) if blockID in (64, 71): #wooden door, or iron door if data & 0x8 == 0x8: # top of the door raw_door = terrain_images[81 if blockID == 64 else 82] else: # bottom of the door raw_door = terrain_images[97 if blockID == 64 else 98] # if you want to render all doors as closed, then force # force swung to be False if data & 0x4 == 0x4: swung = True else: swung = False # mask out the high bits to figure out the orientation img = Image.new("RGBA", (24, 24), (38, 92, 255, 0)) if (data & 0x03) == 0: if not swung: tex = transform_image_side(raw_door) composite.alpha_over(img, tex, (0, 6), tex) else: # flip first to set the doornob on the correct side tex = transform_image_side( raw_door.transpose(Image.FLIP_LEFT_RIGHT)) tex = tex.transpose(Image.FLIP_LEFT_RIGHT) composite.alpha_over(img, tex, (0, 0), tex) if (data & 0x03) == 1: if not swung: tex = transform_image_side(raw_door).transpose( Image.FLIP_LEFT_RIGHT) composite.alpha_over(img, tex, (0, 0), tex) else: tex = transform_image_side(raw_door) composite.alpha_over(img, tex, (12, 0), tex) if (data & 0x03) == 2: if not swung: tex = transform_image_side( raw_door.transpose(Image.FLIP_LEFT_RIGHT)) composite.alpha_over(img, tex, (12, 0), tex) else: tex = transform_image_side(raw_door).transpose( Image.FLIP_LEFT_RIGHT) composite.alpha_over(img, tex, (12, 6), tex) if (data & 0x03) == 3: if not swung: tex = transform_image_side( raw_door.transpose(Image.FLIP_LEFT_RIGHT)).transpose( Image.FLIP_LEFT_RIGHT) composite.alpha_over(img, tex, (12, 6), tex) else: tex = transform_image_side( raw_door.transpose(Image.FLIP_LEFT_RIGHT)) composite.alpha_over(img, tex, (0, 6), tex) return (img.convert("RGB"), img.split()[3]) if blockID == 2: # grass top = transform_image(tintTexture(terrain_images[0], (115, 175, 71))) side1 = transform_image_side(terrain_images[3]) side2 = transform_image_side(terrain_images[3]).transpose( Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24, 24), (38, 92, 255, 0)) composite.alpha_over(img, side1, (0, 6), side1) composite.alpha_over(img, side2, (12, 6), side2) composite.alpha_over(img, top, (0, 0), top) return (img.convert("RGB"), img.split()[3]) if blockID == 51: # fire firetexture = _load_image("fire.png") side1 = transform_image_side(firetexture) side2 = transform_image_side(firetexture).transpose( Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24, 24), (38, 92, 255, 0)) composite.alpha_over(img, side1, (12, 0), side1) composite.alpha_over(img, side2, (0, 0), side2) composite.alpha_over(img, side1, (0, 6), side1) composite.alpha_over(img, side2, (12, 6), side2) return (img.convert("RGB"), img.split()[3]) if blockID == 18: # leaves t = tintTexture(terrain_images[52], (37, 118, 25)) top = transform_image(t) side1 = transform_image_side(t) side2 = transform_image_side(t).transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24, 24), (38, 92, 255, 0)) composite.alpha_over(img, side1, (0, 6), side1) composite.alpha_over(img, side2, (12, 6), side2) composite.alpha_over(img, top, (0, 0), top) return (img.convert("RGB"), img.split()[3]) if blockID == 17: # wood: normal, birch and pines top = terrain_images[21] if data == 0: side = terrain_images[20] img = _build_block(top, side, 17) return (img.convert("RGB"), img.split()[3]) if data == 1: side = terrain_images[116] img = _build_block(top, side, 17) return (img.convert("RGB"), img.split()[3]) if data == 2: side = terrain_images[117] img = _build_block(top, side, 17) return (img.convert("RGB"), img.split()[3]) if blockID == 35: # wool if data == 0: # white top = side = terrain_images[64] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 1: # orange top = side = terrain_images[210] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 2: # magenta top = side = terrain_images[194] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 3: # light blue top = side = terrain_images[178] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 4: # yellow top = side = terrain_images[162] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 5: # light green top = side = terrain_images[146] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 6: # pink top = side = terrain_images[130] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 7: # grey top = side = terrain_images[114] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 8: # light grey top = side = terrain_images[225] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 9: # cyan top = side = terrain_images[209] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 10: # purple top = side = terrain_images[193] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 11: # blue top = side = terrain_images[177] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 12: # brown top = side = terrain_images[161] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 13: # dark green top = side = terrain_images[145] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 14: # red top = side = terrain_images[129] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if data == 15: # black top = side = terrain_images[113] img = _build_block(top, side, 35) return (img.convert("RGB"), img.split()[3]) if blockID == 85: # fences # create needed images for Big stick fence raw_texture = terrain_images[4] raw_fence_top = Image.new("RGBA", (16, 16), (38, 92, 255, 0)) raw_fence_side = Image.new("RGBA", (16, 16), (38, 92, 255, 0)) fence_top_mask = Image.new("RGBA", (16, 16), (38, 92, 255, 0)) fence_side_mask = Image.new("RGBA", (16, 16), (38, 92, 255, 0)) # generate the masks images for textures of the fence ImageDraw.Draw(fence_top_mask).rectangle((6, 6, 9, 9), outline=(0, 0, 0), fill=(0, 0, 0)) ImageDraw.Draw(fence_side_mask).rectangle((6, 1, 9, 15), outline=(0, 0, 0), fill=(0, 0, 0)) # create textures top and side for fence big stick composite.alpha_over(raw_fence_top, raw_texture, (0, 0), fence_top_mask) composite.alpha_over(raw_fence_side, raw_texture, (0, 0), fence_side_mask) # Create the sides and the top of the big stick fence_side = transform_image_side(raw_fence_side, 85) fence_other_side = fence_side.transpose(Image.FLIP_LEFT_RIGHT) fence_top = transform_image(raw_fence_top, 85) # Darken the sides slightly. These methods also affect the alpha layer, # so save them first (we don't want to "darken" the alpha layer making # the block transparent) sidealpha = fence_side.split()[3] fence_side = ImageEnhance.Brightness(fence_side).enhance(0.9) fence_side.putalpha(sidealpha) othersidealpha = fence_other_side.split()[3] fence_other_side = ImageEnhance.Brightness(fence_other_side).enhance( 0.8) fence_other_side.putalpha(othersidealpha) # Compose the fence big stick fence_big = Image.new("RGBA", (24, 24), (38, 92, 255, 0)) composite.alpha_over(fence_big, fence_side, (4, 4), fence_side) composite.alpha_over(fence_big, fence_other_side, (8, 4), fence_other_side) composite.alpha_over(fence_big, fence_top, (-1, 1), fence_top) # Now render the small sticks. # Create needed images raw_fence_small_side = Image.new("RGBA", (16, 16), (38, 92, 255, 0)) fence_small_side_mask = Image.new("RGBA", (16, 16), (38, 92, 255, 0)) # Generate mask ImageDraw.Draw(fence_small_side_mask).rectangle((10, 1, 15, 3), outline=(0, 0, 0), fill=(0, 0, 0)) ImageDraw.Draw(fence_small_side_mask).rectangle((10, 7, 15, 9), outline=(0, 0, 0), fill=(0, 0, 0)) # create the texture for the side of small sticks fence composite.alpha_over(raw_fence_small_side, raw_texture, (0, 0), fence_small_side_mask) # Create the sides and the top of the small sticks fence_small_side = transform_image_side(raw_fence_small_side, 85) fence_small_other_side = fence_small_side.transpose( Image.FLIP_LEFT_RIGHT) # Darken the sides slightly. These methods also affect the alpha layer, # so save them first (we don't want to "darken" the alpha layer making # the block transparent) sidealpha = fence_small_other_side.split()[3] fence_small_other_side = ImageEnhance.Brightness( fence_small_other_side).enhance(0.9) fence_small_other_side.putalpha(sidealpha) sidealpha = fence_small_side.split()[3] fence_small_side = ImageEnhance.Brightness(fence_small_side).enhance( 0.9) fence_small_side.putalpha(sidealpha) # Create img to compose the fence img = Image.new("RGBA", (24, 24), (38, 92, 255, 0)) # Position of fence small sticks in img. # These postitions are strange because the small sticks of the # fence are at the very left and at the very right of the 16x16 images pos_top_left = (-2, 0) pos_top_right = (14, 0) pos_bottom_right = (6, 4) pos_bottom_left = (6, 4) # +x axis points top right direction # +y axis points bottom right direction # First compose small sticks in the back of the image, # then big stick and thecn small sticks in the front. if (data & 0b0001) == 1: composite.alpha_over(img, fence_small_side, pos_top_left, fence_small_side) # top left if (data & 0b1000) == 8: composite.alpha_over(img, fence_small_other_side, pos_top_right, fence_small_other_side) # top right composite.alpha_over(img, fence_big, (0, 0), fence_big) if (data & 0b0010) == 2: composite.alpha_over(img, fence_small_other_side, pos_bottom_left, fence_small_other_side) # bottom left if (data & 0b0100) == 4: composite.alpha_over(img, fence_small_side, pos_bottom_right, fence_small_side) # bottom right return (img.convert("RGB"), img.split()[3]) if blockID in (43, 44): # slab and double-slab if data == 0: # stone slab top = terrain_images[6] side = terrain_images[5] img = _build_block(top, side, blockID) return (img.convert("RGB"), img.split()[3]) if data == 1: # stone slab top = terrain_images[176] side = terrain_images[192] img = _build_block(top, side, blockID) return (img.convert("RGB"), img.split()[3]) if data == 2: # wooden slab top = side = terrain_images[4] img = _build_block(top, side, blockID) return (img.convert("RGB"), img.split()[3]) if data == 3: # cobblestone slab top = side = terrain_images[16] img = _build_block(top, side, blockID) return (img.convert("RGB"), img.split()[3]) return None
def _build_block(top, side, blockID=None): """From a top texture and a side texture, build a block image. top and side should be 16x16 image objects. Returns a 24x24 image """ img = Image.new("RGBA", (24, 24), (38, 92, 255, 0)) top = transform_image(top, blockID) if not side: composite.alpha_over(img, top, (0, 0), top) return img side = transform_image_side(side, blockID) otherside = side.transpose(Image.FLIP_LEFT_RIGHT) # Darken the sides slightly. These methods also affect the alpha layer, # so save them first (we don't want to "darken" the alpha layer making # the block transparent) sidealpha = side.split()[3] side = ImageEnhance.Brightness(side).enhance(0.9) side.putalpha(sidealpha) othersidealpha = otherside.split()[3] otherside = ImageEnhance.Brightness(otherside).enhance(0.8) otherside.putalpha(othersidealpha) ## special case for non-block things # TODO once torches are handled by generate_special_texture, remove # them from this list if blockID in (37, 38, 6, 39, 40, 50, 83): ## flowers, sapling, mushrooms, regular torch, reeds # instead of pasting these blocks at the cube edges, place them in the middle: # and omit the top composite.alpha_over(img, side, (6, 3), side) composite.alpha_over(img, otherside, (6, 3), otherside) return img if blockID in (81, ): # cacti! composite.alpha_over(img, side, (2, 6), side) composite.alpha_over(img, otherside, (10, 6), otherside) composite.alpha_over(img, top, (0, 2), top) elif blockID in (44, ): # half step # shift each texture down 6 pixels composite.alpha_over(img, side, (0, 12), side) composite.alpha_over(img, otherside, (12, 12), otherside) composite.alpha_over(img, top, (0, 6), top) elif blockID in (78, ): # snow # shift each texture down 9 pixels composite.alpha_over(img, side, (0, 6), side) composite.alpha_over(img, otherside, (12, 6), otherside) composite.alpha_over(img, top, (0, 9), top) else: composite.alpha_over(img, side, (0, 6), side) composite.alpha_over(img, otherside, (12, 6), otherside) composite.alpha_over(img, top, (0, 0), top) # Manually touch up 6 pixels that leave a gap because of how the # shearing works out. This makes the blocks perfectly tessellate-able for x, y in [(13, 23), (17, 21), (21, 19)]: # Copy a pixel to x,y from x-1,y img.putpixel((x, y), img.getpixel((x - 1, y))) for x, y in [(3, 4), (7, 2), (11, 0)]: # Copy a pixel to x,y from x+1,y img.putpixel((x, y), img.getpixel((x + 1, y))) return img
def generate_special_texture(blockID, data): """Generates a special texture, such as a correctly facing minecraft track""" #print "%s has ancillary data: %X" %(blockID, data) # TODO torches, redstone torches, crops, ladders, stairs, # levers, doors, buttons, and signs all need to be handled here (and in chunkpy) if blockID == 66: # minetrack: raw_straight = terrain_images[128] raw_corner = terrain_images[112] ## use transform_image to scale and shear if data == 0: track = transform_image(raw_straight, blockID) elif data == 6: track = transform_image(raw_corner, blockID) elif data == 7: track = transform_image(raw_corner.rotate(270), blockID) elif data == 8: # flip track = transform_image(raw_corner.transpose(Image.FLIP_TOP_BOTTOM).rotate(90), blockID) elif data == 9: track = transform_image(raw_corner.transpose(Image.FLIP_TOP_BOTTOM), blockID) elif data == 1: track = transform_image(raw_straight.rotate(90), blockID) else: # TODO render carts that slop up or down track = transform_image(raw_straight, blockID) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, track, (0,12), track) return (img.convert("RGB"), img.split()[3]) if blockID == 59: # crops raw_crop = terrain_images[88+data] crop1 = transform_image(raw_crop, blockID) crop2 = transform_image_side(raw_crop, blockID) crop3 = crop2.transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, crop1, (0,12), crop1) composite.alpha_over(img, crop2, (6,3), crop2) composite.alpha_over(img, crop3, (6,3), crop3) return (img.convert("RGB"), img.split()[3]) if blockID == 61: #furnace top = transform_image(terrain_images[1]) side1 = transform_image_side(terrain_images[45]) side2 = transform_image_side(terrain_images[44]).transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, side1, (0,6), side1) composite.alpha_over(img, side2, (12,6), side2) composite.alpha_over(img, top, (0,0), top) return (img.convert("RGB"), img.split()[3]) if blockID in (86,91): # jack-o-lantern top = transform_image(terrain_images[102]) frontID = 119 if blockID == 86 else 120 side1 = transform_image_side(terrain_images[frontID]) side2 = transform_image_side(terrain_images[118]).transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, side1, (0,6), side1) composite.alpha_over(img, side2, (12,6), side2) composite.alpha_over(img, top, (0,0), top) return (img.convert("RGB"), img.split()[3]) if blockID == 62: # lit furnace top = transform_image(terrain_images[1]) side1 = transform_image_side(terrain_images[45]) side2 = transform_image_side(terrain_images[45+16]).transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, side1, (0,6), side1) composite.alpha_over(img, side2, (12,6), side2) composite.alpha_over(img, top, (0,0), top) return (img.convert("RGB"), img.split()[3]) if blockID == 65: # ladder raw_texture = terrain_images[83] #print "ladder is facing: %d" % data if data == 5: # normally this ladder would be obsured by the block it's attached to # but since ladders can apparently be placed on transparent blocks, we # have to render this thing anyway. same for data == 2 tex = transform_image_side(raw_texture) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, tex, (0,6), tex) return (img.convert("RGB"), img.split()[3]) if data == 2: tex = transform_image_side(raw_texture).transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, tex, (12,6), tex) return (img.convert("RGB"), img.split()[3]) if data == 3: tex = transform_image_side(raw_texture).transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, tex, (0,0), tex) return (img.convert("RGB"), img.split()[3]) if data == 4: tex = transform_image_side(raw_texture) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, tex, (12,0), tex) return (img.convert("RGB"), img.split()[3]) if blockID in (64,71): #wooden door, or iron door if data & 0x8 == 0x8: # top of the door raw_door = terrain_images[81 if blockID == 64 else 82] else: # bottom of the door raw_door = terrain_images[97 if blockID == 64 else 98] # if you want to render all doors as closed, then force # force swung to be False if data & 0x4 == 0x4: swung=True else: swung=False # mask out the high bits to figure out the orientation img = Image.new("RGBA", (24,24), (38,92,255,0)) if (data & 0x03) == 0: if not swung: tex = transform_image_side(raw_door) composite.alpha_over(img, tex, (0,6), tex) else: # flip first to set the doornob on the correct side tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)) tex = tex.transpose(Image.FLIP_LEFT_RIGHT) composite.alpha_over(img, tex, (0,0), tex) if (data & 0x03) == 1: if not swung: tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT) composite.alpha_over(img, tex, (0,0), tex) else: tex = transform_image_side(raw_door) composite.alpha_over(img, tex, (12,0), tex) if (data & 0x03) == 2: if not swung: tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)) composite.alpha_over(img, tex, (12,0), tex) else: tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT) composite.alpha_over(img, tex, (12,6), tex) if (data & 0x03) == 3: if not swung: tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)).transpose(Image.FLIP_LEFT_RIGHT) composite.alpha_over(img, tex, (12,6), tex) else: tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)) composite.alpha_over(img, tex, (0,6), tex) return (img.convert("RGB"), img.split()[3]) if blockID == 2: # grass top = transform_image(tintTexture(terrain_images[0],(115,175,71))) side1 = transform_image_side(terrain_images[3]) side2 = transform_image_side(terrain_images[3]).transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, side1, (0,6), side1) composite.alpha_over(img, side2, (12,6), side2) composite.alpha_over(img, top, (0,0), top) return (img.convert("RGB"), img.split()[3]) if blockID == 18: # leaves t = tintTexture(terrain_images[52], (37, 118, 25)) top = transform_image(t) side1 = transform_image_side(t) side2 = transform_image_side(t).transpose(Image.FLIP_LEFT_RIGHT) img = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(img, side1, (0,6), side1) composite.alpha_over(img, side2, (12,6), side2) composite.alpha_over(img, top, (0,0), top) return (img.convert("RGB"), img.split()[3]) if blockID == 85: # fences # create needed images for Big stick fence raw_texture = terrain_images[4] raw_fence_top = Image.new("RGBA", (16,16), (38,92,255,0)) raw_fence_side = Image.new("RGBA", (16,16), (38,92,255,0)) fence_top_mask = Image.new("RGBA", (16,16), (38,92,255,0)) fence_side_mask = Image.new("RGBA", (16,16), (38,92,255,0)) # generate the masks images for textures of the fence ImageDraw.Draw(fence_top_mask).rectangle((6,6,9,9),outline=(0,0,0),fill=(0,0,0)) ImageDraw.Draw(fence_side_mask).rectangle((6,1,9,15),outline=(0,0,0),fill=(0,0,0)) # create textures top and side for fence big stick composite.alpha_over(raw_fence_top,raw_texture,(0,0),fence_top_mask) composite.alpha_over(raw_fence_side,raw_texture,(0,0),fence_side_mask) # Create the sides and the top of the big stick fence_side = transform_image_side(raw_fence_side,85) fence_other_side = fence_side.transpose(Image.FLIP_LEFT_RIGHT) fence_top = transform_image(raw_fence_top,85) # Darken the sides slightly. These methods also affect the alpha layer, # so save them first (we don't want to "darken" the alpha layer making # the block transparent) sidealpha = fence_side.split()[3] fence_side = ImageEnhance.Brightness(fence_side).enhance(0.9) fence_side.putalpha(sidealpha) othersidealpha = fence_other_side.split()[3] fence_other_side = ImageEnhance.Brightness(fence_other_side).enhance(0.8) fence_other_side.putalpha(othersidealpha) # Compose the fence big stick fence_big = Image.new("RGBA", (24,24), (38,92,255,0)) composite.alpha_over(fence_big,fence_side, (4,4),fence_side) composite.alpha_over(fence_big,fence_other_side, (8,4),fence_other_side) composite.alpha_over(fence_big,fence_top, (-1,1),fence_top) # Now render the small sticks. # Create needed images raw_fence_small_side = Image.new("RGBA", (16,16), (38,92,255,0)) fence_small_side_mask = Image.new("RGBA", (16,16), (38,92,255,0)) # Generate mask ImageDraw.Draw(fence_small_side_mask).rectangle((10,1,15,3),outline=(0,0,0),fill=(0,0,0)) ImageDraw.Draw(fence_small_side_mask).rectangle((10,7,15,9),outline=(0,0,0),fill=(0,0,0)) # create the texture for the side of small sticks fence composite.alpha_over(raw_fence_small_side,raw_texture,(0,0),fence_small_side_mask) # Create the sides and the top of the small sticks fence_small_side = transform_image_side(raw_fence_small_side,85) fence_small_other_side = fence_small_side.transpose(Image.FLIP_LEFT_RIGHT) # Darken the sides slightly. These methods also affect the alpha layer, # so save them first (we don't want to "darken" the alpha layer making # the block transparent) sidealpha = fence_small_other_side.split()[3] fence_small_other_side = ImageEnhance.Brightness(fence_small_other_side).enhance(0.9) fence_small_other_side.putalpha(sidealpha) sidealpha = fence_small_side.split()[3] fence_small_side = ImageEnhance.Brightness(fence_small_side).enhance(0.9) fence_small_side.putalpha(sidealpha) # Create img to compose the fence img = Image.new("RGBA", (24,24), (38,92,255,0)) # Position of fence small sticks in img. # These postitions are strange because the small sticks of the # fence are at the very left and at the very right of the 16x16 images pos_top_left = (-2,0) pos_top_right = (14,0) pos_bottom_right = (6,4) pos_bottom_left = (6,4) # +x axis points top right direction # +y axis points bottom right direction # First compose small sticks in the back of the image, # then big stick and thecn small sticks in the front. if data == 1: img = fence_big return (img.convert("RGB"),img.split()[3]) elif data == 2: #fence in line with x axis composite.alpha_over(img,fence_small_other_side, pos_top_right,fence_small_other_side) # top right composite.alpha_over(img,fence_big,(0,0),fence_big) composite.alpha_over(img,fence_small_other_side, pos_bottom_left,fence_small_other_side) # bottom left return (img.convert("RGB"),img.split()[3]) elif data == 3: #fence in line with y axis composite.alpha_over(img,fence_small_side, pos_top_left,fence_small_side) # top left composite.alpha_over(img,fence_big,(0,0),fence_big) composite.alpha_over(img,fence_small_side, pos_bottom_right,fence_small_side) # bottom right return (img.convert("RGB"),img.split()[3]) elif data == 4: #fence corner +x, -y composite.alpha_over(img,fence_small_other_side, pos_top_right,fence_small_other_side) # top right composite.alpha_over(img,fence_small_side, pos_top_left,fence_small_side) # top left composite.alpha_over(img,fence_big,(0,0),fence_big) return (img.convert("RGB"),img.split()[3]) elif data == 5: #fence corner -x, -y composite.alpha_over(img,fence_small_side, pos_top_left,fence_small_side) # top left composite.alpha_over(img,fence_big,(0,0),fence_big) composite.alpha_over(img,fence_small_other_side, pos_bottom_left,fence_small_other_side) # bottom left return (img.convert("RGB"),img.split()[3]) elif data == 6: #fence corner -x, +y composite.alpha_over(img,fence_big,(0,0),fence_big) composite.alpha_over(img,fence_small_side, pos_bottom_right,fence_small_side) # bottom right composite.alpha_over(img,fence_small_other_side, pos_bottom_left,fence_small_other_side) # bottom left return (img.convert("RGB"),img.split()[3]) elif data == 7: #fence corner +x, +y composite.alpha_over(img,fence_small_other_side, pos_top_right,fence_small_other_side) # top right composite.alpha_over(img,fence_big,(0,0),fence_big) composite.alpha_over(img,fence_small_side, pos_bottom_right,fence_small_side) # bottom right return (img.convert("RGB"),img.split()[3]) elif data == 8: #fence dead end +x composite.alpha_over(img,fence_small_other_side, pos_top_right,fence_small_other_side) # top right composite.alpha_over(img,fence_big,(0,0),fence_big) return (img.convert("RGB"),img.split()[3]) elif data == 9: #fence dead end -y composite.alpha_over(img,fence_small_side, pos_top_left,fence_small_side) # top left composite.alpha_over(img,fence_big,(0,0),fence_big) return (img.convert("RGB"),img.split()[3]) elif data == 10: #fence dead end -x composite.alpha_over(img,fence_big,(0,0),fence_big) composite.alpha_over(img,fence_small_other_side, pos_bottom_left,fence_small_other_side) # bottom left return (img.convert("RGB"),img.split()[3]) elif data == 11: #fence dead end +y composite.alpha_over(img,fence_big,(0,0),fence_big) composite.alpha_over(img,fence_small_side, pos_bottom_right,fence_small_side) # bottom right return (img.convert("RGB"),img.split()[3]) elif data == 12: #fence cross with +y missing composite.alpha_over(img,fence_small_side, pos_top_left,fence_small_side) # top left composite.alpha_over(img,fence_small_other_side, pos_top_right,fence_small_other_side) # top right composite.alpha_over(img,fence_big,(0,0),fence_big) composite.alpha_over(img,fence_small_other_side, pos_bottom_left,fence_small_other_side) # bottom left return (img.convert("RGB"),img.split()[3]) elif data == 13: #fence cross with +x missing composite.alpha_over(img,fence_small_side, pos_top_left,fence_small_side) # top left composite.alpha_over(img,fence_big,(0,0),fence_big) composite.alpha_over(img,fence_small_other_side, pos_bottom_left,fence_small_other_side) # bottom left composite.alpha_over(img,fence_small_side, pos_bottom_right,fence_small_side) # bottom right return (img.convert("RGB"),img.split()[3]) elif data == 14: #fence cross with -y missing composite.alpha_over(img,fence_small_other_side, pos_top_right,fence_small_other_side) # top right composite.alpha_over(img,fence_big,(0,0),fence_big) composite.alpha_over(img,fence_small_other_side, pos_bottom_left,fence_small_other_side) # bottom left composite.alpha_over(img,fence_small_side, pos_bottom_right,fence_small_side) # bottom right return (img.convert("RGB"),img.split()[3]) elif data == 15: #fence cross with -x missing composite.alpha_over(img,fence_small_side, pos_top_left,fence_small_side) # top left composite.alpha_over(img,fence_small_other_side, pos_top_right,fence_small_other_side) # top right composite.alpha_over(img,fence_big,(0,0),fence_big) composite.alpha_over(img,fence_small_side, pos_bottom_right,fence_small_side) # bottom right return (img.convert("RGB"),img.split()[3]) elif data == 16: #fence cross composite.alpha_over(img,fence_small_side, pos_top_left,fence_small_side) # top left composite.alpha_over(img,fence_small_other_side, pos_top_right,fence_small_other_side) # top right composite.alpha_over(img,fence_big,(0,0),fence_big) composite.alpha_over(img,fence_small_other_side, pos_bottom_left,fence_small_other_side) # bottom left composite.alpha_over(img,fence_small_side, pos_bottom_right,fence_small_side) # bottom right return (img.convert("RGB"),img.split()[3]) elif data == None: # This can happend if a fence is in the border # of a chunk and the chunk is in the border of the map. composite.alpha_over(img,fence_big,(0,0),) return (img.convert("RGB"), img.split()[3]) else: # just in case composite.alpha_over(img,fence_big,(0,0),) return (img.convert("RGB"), img.split()[3]) return None
def chunk_render(self, img=None, xoff=0, yoff=0, cave=False): """Renders a chunk with the given parameters, and returns the image. If img is given, the chunk is rendered to that image object. Otherwise, a new one is created. xoff and yoff are offsets in the image. For cave mode, all blocks that have any direct sunlight are not rendered, and blocks are drawn with a color tint depending on their depth.""" blocks = self.blocks pseudo_ancildata_blocks = set([85]) left_blocks = self.left_blocks right_blocks = self.right_blocks if cave: # Cave mode. Actually go through and 0 out all blocks that are not in a # cave, so that it only renders caves. # Places where the skylight is not 0 (there's some amount of skylight # touching it) change it to something that won't get rendered, AND # won't get counted as "transparent". blocks = blocks.copy() blocks[self.skylight != 0] = 21 blockData = get_blockdata_array(self.level) blockData_expanded = numpy.empty((16, 16, 128), dtype=numpy.uint8) # Even elements get the lower 4 bits blockData_expanded[:, :, ::2] = blockData & 0x0F # Odd elements get the upper 4 bits blockData_expanded[:, :, 1::2] = blockData >> 4 tileEntities = get_tileentity_data(self.level) if self.world.useBiomeData: biomeColorData = textures.getBiomeData(self.world.worlddir, self.chunkX, self.chunkY) # in the 32x32 block of biome data, what chunk is this?l startX = self.chunkX % 32 startY = self.chunkY % 32 # Each block is 24x24 # The next block on the X axis adds 12px to x and subtracts 6px from y in the image # The next block on the Y axis adds 12px to x and adds 6px to y in the image # The next block up on the Z axis subtracts 12 from y axis in the image # Since there are 16x16x128 blocks in a chunk, the image will be 384x1728 # (height is 128*12 high, plus the size of the horizontal plane: 16*12) if not img: img = Image.new("RGBA", (384, 1728), (38, 92, 255, 0)) for x in xrange(15, -1, -1): for y in xrange(16): imgx = xoff + x * 12 + y * 12 imgy = yoff - x * 6 + y * 6 + 128 * 12 + 16 * 12 // 2 imgy += 12 for z in xrange(128): imgy -= 12 blockid = blocks[x, y, z] # the following blocks don't have textures that can be pre-computed from the blockid # alone. additional data is required. # TODO torches, redstone torches, crops, ladders, stairs, # levers, doors, buttons, and signs all need to be handled here (and in textures.py) ## minecart track, crops, ladder, doors, etc. if blockid in textures.special_blocks: # also handle furnaces here, since one side has a different texture than the other ancilData = blockData_expanded[x, y, z] try: if blockid in pseudo_ancildata_blocks: pseudo_ancilData = self.generate_pseudo_ancildata( x, y, z, blockid) ancilData = pseudo_ancilData t = textures.specialblockmap[(blockid, ancilData)] except KeyError: t = None else: t = textures.blockmap[blockid] if not t: continue if self.world.useBiomeData: # 16 : number of blocks in a chunk (in one direction) # 32 : number of chunks in a region (and biome file) in one direction # so 16 * 32 == 512 : number of blocks in biome file, in one direction if blockid == 2: #grass index = biomeColorData[((startY * 16) + y) * 512 + (startX * 16) + x] c = textures.grasscolor[index] # only tint the top texture t = textures.prepareGrassTexture(c) elif blockid == 18: # leaves index = biomeColorData[((startY * 16) + y) * 512 + (startX * 16) + x] c = textures.foliagecolor[index] t = textures.prepareLeafTexture(c) # Check if this block is occluded if cave and (x == 0 and y != 15 and z != 127): # If it's on the x face, only render if there's a # transparent block in the y+1 direction OR the z-1 # direction if (blocks[x, y + 1, z] not in transparent_blocks and blocks[x, y, z + 1] not in transparent_blocks): continue elif cave and (y == 15 and x != 0 and z != 127): # If it's on the facing y face, only render if there's # a transparent block in the x-1 direction OR the z-1 # direction if (blocks[x - 1, y, z] not in transparent_blocks and blocks[x, y, z + 1] not in transparent_blocks): continue elif cave and (y == 15 and x == 0 and z != 127): # If it's on the facing edge, only render if what's # above it is transparent if (blocks[x, y, z + 1] not in transparent_blocks): continue elif (left_blocks == None and right_blocks == None): # Normal block or not cave mode, check sides for # transparentcy or render if it's a border chunk. if (x != 0 and y != 15 and z != 127 and blocks[x - 1, y, z] not in transparent_blocks and blocks[x, y + 1, z] not in transparent_blocks and blocks[x, y, z + 1] not in transparent_blocks): continue elif (left_blocks != None and right_blocks == None): if ( # If it has the left face covered check for # transparent blocks in left face y != 15 and z != 127 and (left_blocks[15, y, z] if x == 0 else blocks[x - 1, y, z]) not in transparent_blocks and blocks[x, y + 1, z] not in transparent_blocks and blocks[x, y, z + 1] not in transparent_blocks): continue elif (left_blocks == None and right_blocks != None): if ( # If it has the right face covered check for # transparent blocks in right face x != 0 and z != 127 and blocks[x - 1, y, z] not in transparent_blocks and (right_blocks[x, 0, z] if y == 15 else blocks[x, y + 1, z]) not in transparent_blocks and blocks[x, y, z + 1] not in transparent_blocks): continue elif ( # If it's a interior chunk check for transparent blocks # in the adjacent chunks. z != 127 and (left_blocks[15, y, z] if x == 0 else blocks[x - 1, y, z]) not in transparent_blocks and (right_blocks[x, 0, z] if y == 15 else blocks[x, y + 1, z]) not in transparent_blocks and blocks[x, y, z + 1] not in transparent_blocks # Don't render if all sides aren't transparent ): continue # Draw the actual block on the image. For cave images, # tint the block with a color proportional to its depth if cave: # no lighting for cave -- depth is probably more useful composite.alpha_over( img, Image.blend(t[0], depth_colors[z], 0.3), (imgx, imgy), t[1]) else: if not self.world.lighting: # no lighting at all composite.alpha_over(img, t[0], (imgx, imgy), t[1]) elif blockid in transparent_blocks: # transparent means draw the whole # block shaded with the current # block's light black_coeff, _ = self.get_lighting_coefficient( x, y, z) if self.world.spawn and black_coeff > 0.8 and blockid in solid_blocks and not ( blockid in nospawn_blocks or (z != 127 and (blocks[x, y, z + 1] in solid_blocks or blocks[x, y, z + 1] in fluid_blocks))): composite.alpha_over( img, Image.blend(t[0], red_color, black_coeff), (imgx, imgy), t[1]) else: composite.alpha_over( img, Image.blend(t[0], black_color, black_coeff), (imgx, imgy), t[1]) else: # draw each face lit appropriately, # but first just draw the block composite.alpha_over(img, t[0], (imgx, imgy), t[1]) # top face black_coeff, face_occlude = self.get_lighting_coefficient( x, y, z + 1) # Use red instead of black for spawnable blocks if self.world.spawn and black_coeff > 0.8 and blockid in solid_blocks and not ( blockid in nospawn_blocks or (z != 127 and (blocks[x, y, z + 1] in solid_blocks or blocks[x, y, z + 1] in fluid_blocks))): over_color = red_color else: over_color = black_color if not face_occlude: composite.alpha_over( img, over_color, (imgx, imgy), ImageEnhance.Brightness( facemasks[0]).enhance(black_coeff)) # left face black_coeff, face_occlude = self.get_lighting_coefficient( x - 1, y, z) if not face_occlude: composite.alpha_over( img, over_color, (imgx, imgy), ImageEnhance.Brightness( facemasks[1]).enhance(black_coeff)) # right face black_coeff, face_occlude = self.get_lighting_coefficient( x, y + 1, z) if not face_occlude: composite.alpha_over( img, over_color, (imgx, imgy), ImageEnhance.Brightness( facemasks[2]).enhance(black_coeff)) # Draw edge lines if blockid in (44, ): # step block increment = 6 elif blockid in (78, ): # snow increment = 9 else: increment = 0 if blockid not in transparent_blocks or blockid in ( 78, ): #special case snow so the outline is still drawn draw = ImageDraw.Draw(img) if x != 15 and blocks[x + 1, y, z] == 0: draw.line(((imgx + 12, imgy + increment), (imgx + 22, imgy + 5 + increment)), fill=(0, 0, 0), width=1) if y != 0 and blocks[x, y - 1, z] == 0: draw.line(((imgx, imgy + 6 + increment), (imgx + 12, imgy + increment)), fill=(0, 0, 0), width=1) for entity in tileEntities: if entity['id'] == 'Sign': msg = ' \n'.join([ entity['Text1'], entity['Text2'], entity['Text3'], entity['Text4'] ]) if msg.strip(): # convert the blockID coordinates from local chunk # coordinates to global world coordinates newPOI = dict( type="sign", x=entity['x'], y=entity['y'], z=entity['z'], msg=msg, chunk=(self.chunkX, self.chunkY), ) self.queue.put(["newpoi", newPOI]) # check to see if there are any signs in the persistentData list that are from this chunk. # if so, remove them from the persistentData list (since they're have been added to the world.POI # list above. self.queue.put(['removePOI', (self.chunkX, self.chunkY)]) return img