diff --git a/src/iterate.c b/src/iterate.c index 6f2b02b..8fab11b 100644 --- a/src/iterate.c +++ b/src/iterate.c @@ -74,7 +74,7 @@ is_transparent(unsigned char b) { unsigned char - check_adjacent_blocks(RenderState *state, unsigned char blockid) { + check_adjacent_blocks(RenderState *state, int x,int y,int z, unsigned char blockid) { /* * Generates a pseudo ancillary data for blocks that depend of * what are surrounded and don't have ancillary data. This @@ -96,48 +96,48 @@ unsigned char if (state->x == 15) { /* +x direction */ if (state->up_right_blocks != Py_None) { /* just in case we are in the end of the world */ - if (getArrayByte3D(state->up_right_blocks, 0, state->y, state->z) == blockid) { + if (getArrayByte3D(state->up_right_blocks, 0, y, z) == blockid) { pdata = pdata|(1 << 3); } } } else { - if (getArrayByte3D(state->blocks, state->x + 1, state->y, state->z) == blockid) { + if (getArrayByte3D(state->blocks, x + 1, y, z) == blockid) { pdata = pdata|(1 << 3); } } if (state->y == 15) { /* +y direction*/ if (state->right_blocks != Py_None) { - if (getArrayByte3D(state->right_blocks, state->x, 0, state->z) == blockid) { + if (getArrayByte3D(state->right_blocks, x, 0, z) == blockid) { pdata = pdata|(1 << 2); } } } else { - if (getArrayByte3D(state->blocks, state->x, state->y + 1, state->z) == blockid) { + if (getArrayByte3D(state->blocks, x, y + 1, z) == blockid) { pdata = pdata|(1 << 2); } } if (state->x == 0) { /* -x direction*/ if (state->left_blocks != Py_None) { - if (getArrayByte3D(state->left_blocks, 15, state->y, state->z) == blockid) { + if (getArrayByte3D(state->left_blocks, 15, y, z) == blockid) { pdata = pdata|(1 << 1); } } } else { - if (getArrayByte3D(state->blocks, state->x - 1, state->y, state->z) == blockid) { + if (getArrayByte3D(state->blocks, x - 1, y, z) == blockid) { pdata = pdata|(1 << 1); } } if (state->y == 0) { /* -y direction */ if (state->up_left_blocks != Py_None) { - if (getArrayByte3D(state->up_left_blocks, state->x, 15, state->z) == blockid) { + if (getArrayByte3D(state->up_left_blocks, x, 15, z) == blockid) { pdata = pdata|(1 << 0); } } } else { - if (getArrayByte3D(state->blocks, state->x, state->y - 1, state->z) == blockid) { + if (getArrayByte3D(state->blocks, x, y - 1, z) == blockid) { pdata = pdata|(1 << 0); } } @@ -147,15 +147,69 @@ unsigned char unsigned char -generate_pseudo_data(RenderState *state) { +generate_pseudo_data(RenderState *state, unsigned char ancilData) { /* * Generates a fake ancillary data for blocks that are drawn * depending on what are surrounded. */ + int x = state->x, y = state->y, z = state->z; + unsigned char data = 0; + + if (state->block == 9) { /* water */ + /* an aditional bit for top is added to the 4 bits of check_adjacent_blocks */ + if ((ancilData == 0) || (ancilData >= 10)) { /* static water, only top, and unkown ancildata values */ + data = 16; + return data; /* = 0b10000 */ + } else if ((ancilData > 0) && (ancilData < 8)) { /* flowing water */ + data = (check_adjacent_blocks(state, x, y, z, state->block) ^ 0x0f) | 0x10; + return data; + } else if ((ancilData == 8) || (ancilData == 9)) { /* falling water */ + data = (check_adjacent_blocks(state, x, y, z, state->block) ^ 0x0f); + return data; + } - if (state->block == 85) { /* fences */ - return check_adjacent_blocks(state, state->block); + + } else if (state->block == 85) { /* fences */ + return check_adjacent_blocks(state, x, y, z, state->block); + + + } else if (state->block == 55) { /* redstone */ + /* three addiotional bit are added, one for on/off state, and + * another two for going-up redstone wire in the same block + * (connection with the level z+1) */ + unsigned char above_level_data = 0, same_level_data = 0, below_level_data = 0, possibly_connected = 0, final_data = 0; + + /* check for air in z+1, no air = no connection with upper level */ + if ((z != 127) && (getArrayByte3D(state->left_blocks, x, y, z) == 0)) { + above_level_data = check_adjacent_blocks(state, x, y, z + 1, state->block); + } /* else above_level_data = 0 */ + + /* check connection with same level */ + same_level_data = check_adjacent_blocks(state, x, y, z, 55); + + /* check the posibility of connection with z-1 level, check for air */ + possibly_connected = check_adjacent_blocks(state, x, y, z, 0); + + /* check connection with z-1 level */ + if (z != 0) { + below_level_data = check_adjacent_blocks(state, x, y, z - 1, state->block); + } /* else below_level_data = 0 */ + + final_data = above_level_data | same_level_data | (below_level_data & possibly_connected); + + /* add the three bits */ + if (ancilData > 0) { /* powered redstone wire */ + final_data = final_data | 0x40; + } + if ((above_level_data & 0x01)) { /* draw top left going up redstonewire */ + final_data = final_data | 0x20; + } + if ((above_level_data & 0x08)) { /* draw top right going up redstonewire */ + final_data = final_data | 0x10; + } + return final_data; } + return 0; } @@ -275,8 +329,8 @@ chunk_render(PyObject *self, PyObject *args) { PyObject *tmp; unsigned char ancilData = getArrayByte3D(blockdata_expanded, state.x, state.y, state.z); - if (state.block == 85) { - ancilData = generate_pseudo_data(&state); + if ((state.block == 85) || (state.block == 9) || (state.block == 55)) { + ancilData = generate_pseudo_data(&state, ancilData); } tmp = PyTuple_New(2); diff --git a/textures.py b/textures.py index 08d70f8..9e4a930 100644 --- a/textures.py +++ b/textures.py @@ -265,6 +265,79 @@ def _build_block(top, side, blockID=None): return img +def _build_full_block(top, side1, side2, side3, side4, bottom=None, blockID=None): + """From a top texture, a bottom texture and 4 different side textures, + build a full block with four differnts faces. All images should be 16x16 + image objects. Returns a 24x24 image. Can be used to render any block. + + side1 is in the -y face of the cube (top left) + side2 is in the +x (top right) + side3 is in the -x (bottom left) + side4 is in the +y (bottom right) + + A non transparent block uses top, side 3 and side 4 + + """ + img = Image.new("RGBA", (24,24), (38,92,255,0)) + + # first back sides + if side1 != None : + side1 = transform_image_side(side1, blockID) + side1 = side1.transpose(Image.FLIP_TOP_BOTTOM) + + # Darken this side. + sidealpha = side1.split()[3] + side1 = ImageEnhance.Brightness(side1).enhance(0.9) + side1.putalpha(sidealpha) + + composite.alpha_over(img, side1, (0,0), side1) + + + if side2 != None : + side2 = transform_image_side(side2, blockID) + side2 = side2.transpose(Image.FLIP_LEFT_RIGHT) + side2 = side2.transpose(Image.FLIP_TOP_BOTTOM) + + # Darken this side. + sidealpha2 = side2.split()[3] + side2 = ImageEnhance.Brightness(side2).enhance(0.8) + side2.putalpha(sidealpha2) + + composite.alpha_over(img, side2, (12,0), side2) + + if bottom != None : + bottom = transform_image(bottom, blockID) + composite.alpha_over(img, bottom, (0,12), top) + + if top != None : + top = transform_image(top, blockID) + composite.alpha_over(img, top, (0,0), top) + + # front sides + if side3 != None : + side3 = transform_image_side(side3, blockID) + + # Darken this side + sidealpha = side3.split()[3] + side3 = ImageEnhance.Brightness(side3).enhance(0.9) + side3.putalpha(sidealpha) + + composite.alpha_over(img, side3, (0,6), side3) + + if side4 != None : + side4 = transform_image_side(side4, blockID) + side4 = side4.transpose(Image.FLIP_LEFT_RIGHT) + + # Darken this side + sidealpha = side4.split()[3] + side4 = ImageEnhance.Brightness(side4).enhance(0.8) + side4.putalpha(sidealpha) + + composite.alpha_over(img, side4, (12,6), side4) + + return img + + def _build_blockimages(): """Returns a mapping from blockid to an image of that block in perspective The values of the mapping are actually (image in RGB mode, alpha channel). @@ -801,6 +874,114 @@ def generate_special_texture(blockID, data): img = _build_block(top, side, blockID) return (img.convert("RGB"), img.split()[3]) + + if blockID == 9: # spring water, flowing water and waterfall water + + watertexture = _load_image("water.png") + + if (data & 0b10000) == 16: + top = watertexture + + else: top = None + + if (data & 0b0001) == 1: + side1 = watertexture # top left + else: side1 = None + + if (data & 0b1000) == 8: + side2 = watertexture # top right + else: side2 = None + + if (data & 0b0010) == 2: + side3 = watertexture # bottom left + else: side3 = None + + if (data & 0b0100) == 4: + side4 = watertexture # bottom right + else: side4 = None + + img = _build_full_block(top,side1,side2,side3,side4) + + return (img.convert("RGB"),img.split()[3]) + + + if blockID == 55: # redstone wire + + if data & 0b1000000 == 64: # powered redstone wire + redstone_wire_t = terrain_images[165] + redstone_wire_t = tintTexture(redstone_wire_t,(255,0,0)) + + redstone_cross_t = terrain_images[164] + redstone_cross_t = tintTexture(redstone_cross_t,(255,0,0)) + + + else: # unpowered redstone wire + redstone_wire_t = terrain_images[165] + redstone_wire_t = tintTexture(redstone_wire_t,(48,0,0)) + + redstone_cross_t = terrain_images[164] + redstone_cross_t = tintTexture(redstone_cross_t,(48,0,0)) + + # generate an image per redstone direction + branch_top_left = redstone_cross_t.copy() + ImageDraw.Draw(branch_top_left).rectangle((0,0,4,15),outline=(0,0,0,0),fill=(0,0,0,0)) + ImageDraw.Draw(branch_top_left).rectangle((11,0,15,15),outline=(0,0,0,0),fill=(0,0,0,0)) + ImageDraw.Draw(branch_top_left).rectangle((0,11,15,15),outline=(0,0,0,0),fill=(0,0,0,0)) + + branch_top_right = redstone_cross_t.copy() + ImageDraw.Draw(branch_top_right).rectangle((0,0,15,4),outline=(0,0,0,0),fill=(0,0,0,0)) + ImageDraw.Draw(branch_top_right).rectangle((0,0,4,15),outline=(0,0,0,0),fill=(0,0,0,0)) + ImageDraw.Draw(branch_top_right).rectangle((0,11,15,15),outline=(0,0,0,0),fill=(0,0,0,0)) + + branch_bottom_right = redstone_cross_t.copy() + ImageDraw.Draw(branch_bottom_right).rectangle((0,0,15,4),outline=(0,0,0,0),fill=(0,0,0,0)) + ImageDraw.Draw(branch_bottom_right).rectangle((0,0,4,15),outline=(0,0,0,0),fill=(0,0,0,0)) + ImageDraw.Draw(branch_bottom_right).rectangle((11,0,15,15),outline=(0,0,0,0),fill=(0,0,0,0)) + + branch_bottom_left = redstone_cross_t.copy() + ImageDraw.Draw(branch_bottom_left).rectangle((0,0,15,4),outline=(0,0,0,0),fill=(0,0,0,0)) + ImageDraw.Draw(branch_bottom_left).rectangle((11,0,15,15),outline=(0,0,0,0),fill=(0,0,0,0)) + ImageDraw.Draw(branch_bottom_left).rectangle((0,11,15,15),outline=(0,0,0,0),fill=(0,0,0,0)) + + # generate the bottom texture + if data & 0b111111 == 0: + bottom = redstone_cross_t.copy() + + elif data & 0b1111 == 10: #= 0b1010 redstone wire in the x direction + bottom = redstone_wire_t.copy() + + elif data & 0b1111 == 5: #= 0b0101 redstone wire in the y direction + bottom = redstone_wire_t.copy().rotate(90) + + else: + bottom = Image.new("RGBA", (16,16), (38,92,255,0)) + if (data & 0b0001) == 1: + composite.alpha_over(bottom,branch_top_left) + + if (data & 0b1000) == 8: + composite.alpha_over(bottom,branch_top_right) + + if (data & 0b0010) == 2: + composite.alpha_over(bottom,branch_bottom_left) + + if (data & 0b0100) == 4: + composite.alpha_over(bottom,branch_bottom_right) + + # check for going up redstone wire + if data & 0b100000 == 32: + side1 = redstone_wire_t.rotate(90) + else: + side1 = None + + if data & 0b010000 == 16: + side2 = redstone_wire_t.rotate(90) + else: + side2 = None + + img = _build_full_block(None,side1,side2,None,None,bottom) + + return (img.convert("RGB"),img.split()[3]) + return None def tintTexture(im, c): @@ -896,7 +1077,7 @@ def getBiomeData(worlddir, chunkX, chunkY): # This set holds block ids that require special pre-computing. These are typically # things that require ancillary data to render properly (i.e. ladder plus orientation) -special_blocks = set([66,59,61,62, 65,64,71,91,86,2,18,85,17,23,35,51,43,44]) +special_blocks = set([66,59,61,62, 65,64,71,91,86,2,18,85,17,23,35,51,43,44,9,55]) # this is a map of special blockIDs to a list of all # possible values for ancillary data that it might have. @@ -917,6 +1098,8 @@ special_map[35] = range(16) # wool, colored and white special_map[51] = range(16) # fire special_map[43] = range(4) # stone, sandstone, wooden and cobblestone double-slab special_map[44] = range(4) # stone, sandstone, wooden and cobblestone slab +special_map[9] = range(32) # water: spring,flowing, waterfall, and others (unknown) ancildata values. +special_map[55] = range(128) # redstone wire # apparently pumpkins and jack-o-lanterns have ancillary data, but it's unknown # what that data represents. For now, assume that the range for data is 0 to 5