diff --git a/chunk.py b/chunk.py index cfe9ea6..59b374e 100644 --- a/chunk.py +++ b/chunk.py @@ -284,6 +284,180 @@ class ChunkRenderer(object): return self._right_blocklight right_blocklight = property(_load_right_blocklight) + def _load_up_right(self): + """Loads and sets data from upper-right chunk""" + chunk_path = self.world.get_chunk_path(self.coords[0] + 1, self.coords[1]) + try: + chunk_data = get_lvldata(chunk_path) + self._up_right_skylight = get_skylight_array(chunk_data) + self._up_right_blocklight = get_blocklight_array(chunk_data) + self._up_right_blocks = get_blockarray(chunk_data) + except IOError: + self._up_right_skylight = None + self._up_right_blocklight = None + self._up_right_blocks = None + + def _load_up_right_blocks(self): + """Loads and returns upper-right block array""" + if not hasattr(self, "_up_right_blocks"): + self._load_up_right() + return self._up_right_blocks + up_right_blocks = property(_load_up_right_blocks) + + def _load_up_left(self): + """Loads and sets data from upper-left chunk""" + chunk_path = self.world.get_chunk_path(self.coords[0], self.coords[1] - 1) + try: + chunk_data = get_lvldata(chunk_path) + self._up_left_skylight = get_skylight_array(chunk_data) + self._up_left_blocklight = get_blocklight_array(chunk_data) + self._up_left_blocks = get_blockarray(chunk_data) + except IOError: + self._up_left_skylight = None + self._up_left_blocklight = None + self._up_left_blocks = None + + def _load_up_left_blocks(self): + """Loads and returns lower-left block array""" + if not hasattr(self, "_up_left_blocks"): + self._load_up_left() + return self._up_left_blocks + up_left_blocks = property(_load_up_left_blocks) + + def generate_pseudo_ancildata(self,x,y,z,blockid): + """ Generates a pseudo ancillary data for blocks that depend of + what are surrounded and don't have ancillary data""" + + blocks = self.blocks + up_left_blocks = self.up_left_blocks + up_right_blocks = self.up_right_blocks + left_blocks = self.left_blocks + right_blocks = self.right_blocks + + if ( # The block is surrounded by 0 blocks with same blockid + (up_right_blocks[0,y,z] != blockid if x == 15 else blocks[x+1,y,z] != blockid) and + (left_blocks[15,y,z] != blockid if x == 0 else blocks[x - 1,y,z] != blockid) and + (right_blocks[x,0,z] != blockid if y == 15 else blocks[x,y + 1,z] != blockid) and + (up_left_blocks[x,15,z] != blockid if y == 0 else blocks[x,y - 1,z] != blockid) + ): return 1 + + # Now 3 in line, they should be more common: + + elif ( # The block is surrounded by 2 blocks with same blockid, along x axis + (up_right_blocks[0,y,z] == blockid if x == 15 else blocks[x+1,y,z] == blockid) and + (left_blocks[15,y,z] == blockid if x == 0 else blocks[x - 1,y,z] == blockid) and + (right_blocks[x,0,z] != blockid if y == 15 else blocks[x,y + 1,z] != blockid) and + (up_left_blocks[x,15,z] != blockid if y == 0 else blocks[x,y - 1,z] != blockid) + ): return 2 + + elif ( # The block is surrounded by 2 blocks with same blockid, along y axis + (up_right_blocks[0,y,z] != blockid if x == 15 else blocks[x+1,y,z] != blockid) and + (left_blocks[15,y,z] != blockid if x == 0 else blocks[x - 1,y,z] != blockid) and + (right_blocks[x,0,z] == blockid if y == 15 else blocks[x,y + 1,z] == blockid) and + (up_left_blocks[x,15,z] == blockid if y == 0 else blocks[x,y - 1,z] == blockid) + ): return 3 + + # Now 3 in corner: + + elif ( # The block is surrounded by 2 blocks with same blockid, in a -y to x corner + (up_right_blocks[0,y,z] == blockid if x == 15 else blocks[x+1,y,z] == blockid) and + (left_blocks[15,y,z] != blockid if x == 0 else blocks[x - 1,y,z] != blockid) and + (right_blocks[x,0,z] != blockid if y == 15 else blocks[x,y + 1,z] != blockid) and + (up_left_blocks[x,15,z] == blockid if y == 0 else blocks[x,y - 1,z] == blockid) + ): return 4 + + elif ( # The block is surrounded by 2 blocks with same blockid, in a -y to -x corner + (up_right_blocks[0,y,z] != blockid if x == 15 else blocks[x+1,y,z] != blockid) and + (left_blocks[15,y,z] == blockid if x == 0 else blocks[x - 1,y,z] == blockid) and + (right_blocks[x,0,z] != blockid if y == 15 else blocks[x,y + 1,z] != blockid) and + (up_left_blocks[x,15,z] == blockid if y == 0 else blocks[x,y - 1,z] == blockid) + ): return 5 + + elif ( # The block is surrounded by 2 blocks with same blockid, in a y to -x corner + (up_right_blocks[0,y,z] != blockid if x == 15 else blocks[x+1,y,z] != blockid) and + (left_blocks[15,y,z] == blockid if x == 0 else blocks[x - 1,y,z] == blockid) and + (right_blocks[x,0,z] == blockid if y == 15 else blocks[x,y + 1,z] == blockid) and + (up_left_blocks[x,15,z] != blockid if y == 0 else blocks[x,y - 1,z] != blockid) + ): return 6 + + elif ( # The block is surrounded by 2 blocks with same blockid, in a y to x corner + (up_right_blocks[0,y,z] == blockid if x == 15 else blocks[x+1,y,z] == blockid) and + (left_blocks[15,y,z] != blockid if x == 0 else blocks[x - 1,y,z] != blockid) and + (right_blocks[x,0,z] == blockid if y == 15 else blocks[x,y + 1,z] == blockid) and + (up_left_blocks[x,15,z] != blockid if y == 0 else blocks[x,y - 1,z] != blockid) + ): return 7 + + # Now 1 in dead end: + + elif ( # The block is surrounded by 1 blocks with same blockid, in +x + (up_right_blocks[0,y,z] == blockid if x == 15 else blocks[x+1,y,z] == blockid) and + (left_blocks[15,y,z] != blockid if x == 0 else blocks[x - 1,y,z] != blockid) and + (right_blocks[x,0,z] != blockid if y == 15 else blocks[x,y + 1,z] != blockid) and + (up_left_blocks[x,15,z] != blockid if y == 0 else blocks[x,y - 1,z] != blockid) + ): return 8 + + elif ( # The block is surrounded by 1 blocks with same blockid, in -y + (up_right_blocks[0,y,z] != blockid if x == 15 else blocks[x+1,y,z] != blockid) and + (left_blocks[15,y,z] != blockid if x == 0 else blocks[x - 1,y,z] != blockid) and + (right_blocks[x,0,z] != blockid if y == 15 else blocks[x,y + 1,z] != blockid) and + (up_left_blocks[x,15,z] == blockid if y == 0 else blocks[x,y - 1,z] == blockid) + ): return 9 + + elif ( # The block is surrounded by 1 blocks with same blockid, in -x + (up_right_blocks[0,y,z] != blockid if x == 15 else blocks[x+1,y,z] != blockid) and + (left_blocks[15,y,z] == blockid if x == 0 else blocks[x - 1,y,z] == blockid) and + (right_blocks[x,0,z] != blockid if y == 15 else blocks[x,y + 1,z] != blockid) and + (up_left_blocks[x,15,z] != blockid if y == 0 else blocks[x,y - 1,z] != blockid) + ): return 10 + + elif ( # The block is surrounded by 1 blocks with same blockid, in +y + (up_right_blocks[0,y,z] != blockid if x == 15 else blocks[x+1,y,z] != blockid) and + (left_blocks[15,y,z] != blockid if x == 0 else blocks[x - 1,y,z] != blockid) and + (right_blocks[x,0,z] == blockid if y == 15 else blocks[x,y + 1,z] == blockid) and + (up_left_blocks[x,15,z] != blockid if y == 0 else blocks[x,y - 1,z] != blockid) + ): return 11 + + # Now surrounded by 3 identical blocks: + + elif ( # The block is surrounded by 3 blocks with same blockid, in postiions -x, -y, +x + (up_right_blocks[0,y,z] == blockid if x == 15 else blocks[x+1,y,z] == blockid) and + (left_blocks[15,y,z] == blockid if x == 0 else blocks[x - 1,y,z] == blockid) and + (right_blocks[x,0,z] != blockid if y == 15 else blocks[x,y + 1,z] != blockid) and + (up_left_blocks[x,15,z] == blockid if y == 0 else blocks[x,y - 1,z] == blockid) + ): return 12 + + elif ( # The block is surrounded by 3 blocks with same blockid, in postiions +y, -y, -x + (up_right_blocks[0,y,z] != blockid if x == 15 else blocks[x+1,y,z] != blockid) and + (left_blocks[15,y,z] == blockid if x == 0 else blocks[x - 1,y,z] == blockid) and + (right_blocks[x,0,z] == blockid if y == 15 else blocks[x,y + 1,z] == blockid) and + (up_left_blocks[x,15,z] == blockid if y == 0 else blocks[x,y - 1,z] == blockid) + ): return 13 + + elif ( # The block is surrounded by 3 blocks with same blockid, in postiions -x, +y, +x + (up_right_blocks[0,y,z] == blockid if x == 15 else blocks[x+1,y,z] == blockid) and + (left_blocks[15,y,z] == blockid if x == 0 else blocks[x - 1,y,z] == blockid) and + (right_blocks[x,0,z] == blockid if y == 15 else blocks[x,y + 1,z] == blockid) and + (up_left_blocks[x,15,z] != blockid if y == 0 else blocks[x,y - 1,z] != blockid) + ): return 14 + + elif ( # The block is surrounded by 3 blocks with same blockid, in postiions +y, -y, +x + (up_right_blocks[0,y,z] == blockid if x == 15 else blocks[x+1,y,z] == blockid) and + (left_blocks[15,y,z] != blockid if x == 0 else blocks[x - 1,y,z] != blockid) and + (right_blocks[x,0,z] == blockid if y == 15 else blocks[x,y + 1,z] == blockid) and + (up_left_blocks[x,15,z] == blockid if y == 0 else blocks[x,y - 1,z] == blockid) + ): return 15 + + # Block completely sourrounded by 4 blocks: + + elif ( # The block is surrounded completely + (up_right_blocks[0,y,z] == blockid if x == 15 else blocks[x+1,y,z] == blockid) and + (left_blocks[15,y,z] == blockid if x == 0 else blocks[x - 1,y,z] == blockid) and + (right_blocks[x,0,z] == blockid if y == 15 else blocks[x,y + 1,z] == blockid) and + (up_left_blocks[x,15,z] == blockid if y == 0 else blocks[x,y - 1,z] == blockid) + ): return 16 + + else: return None + def _hash_blockarray(self): """Finds a hash of the block array""" if hasattr(self, "_digest"): @@ -482,6 +656,7 @@ class ChunkRenderer(object): 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 @@ -535,6 +710,10 @@ class ChunkRenderer(object): # 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 diff --git a/textures.py b/textures.py index 2356d6c..499ce6f 100644 --- a/textures.py +++ b/textures.py @@ -21,7 +21,7 @@ from cStringIO import StringIO import math import numpy -from PIL import Image, ImageEnhance, ImageOps +from PIL import Image, ImageEnhance, ImageOps, ImageDraw import util import composite @@ -521,7 +521,196 @@ def generate_special_texture(blockID, data): 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 @@ -608,7 +797,7 @@ def getBiomeData(worlddir, chunkX, chunkY): # This set holds block ids that require special pre-computing. These are typically # things that require ancillary data to render properly (i.e. ladder plus orientation) -special_blocks = set([66,59,61,62, 65,64,71,91,86,2,18]) +special_blocks = set([66,59,61,62, 65,64,71,91,86,2,18,85]) # this is a map of special blockIDs to a list of all # possible values for ancillary data that it might have. @@ -622,6 +811,7 @@ special_map[64] = range(16) # wooden door special_map[71] = range(16) # iron door special_map[91] = range(5) # jack-o-lantern special_map[86] = range(5) # pumpkin +special_map[85] = range(17) # fences # apparently pumpkins and jack-o-lanterns have ancillary data, but it's unknown # what that data represents. For now, assume that the range for data is 0 to 5 # like torches