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
Beispiel #3
0
    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
Beispiel #9
0
                # 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
Beispiel #12
0
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
Beispiel #13
0
    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