diff --git a/overviewer_core/src/iterate.c b/overviewer_core/src/iterate.c index 6411f90..f274845 100644 --- a/overviewer_core/src/iterate.c +++ b/overviewer_core/src/iterate.c @@ -321,71 +321,46 @@ generate_pseudo_data(RenderState *state, unsigned char ancilData) { } return final_data; - } else if (state-> block == 54) { /* chests */ - /* the top 2 bits are used to store the type of chest - * (single or double), the 2 bottom bits are used for - * orientation, look textures.py for more information. */ + } else if (state->block == 54) { /* normal chests */ + /* Orientation is given by ancilData, pseudo data needed to + * choose from single or double chest and the correct half of + * the chest. */ + + /* Add two bits to ancilData to store single or double chest + * and which half of the chest it is: bit 0x10 = second half + * bit 0x8 = first half */ - /* if placed alone chests always face west, return 0 to make a - * chest facing west */ - unsigned char chest_data = 0, air_data = 0, final_data = 0; + unsigned char chest_data = 0, final_data = 0; /* search for chests */ chest_data = check_adjacent_blocks(state, x, y, z, 54); - /* search for air */ - air_data = check_adjacent_blocks(state, x, y, z, 0); + if (chest_data == 1) { /* another chest in the upper-left */ + final_data = final_data | 0x10 | ancilData; - if (chest_data == 1) { /* another chest in the east */ - final_data = final_data | 0x8; /* only can face to north or south */ - if ( (air_data & 0x2) == 2 ) { - final_data = final_data | 0x1; /* facing north */ - } else { - final_data = final_data | 0x3; /* facing south */ - } + } else if (chest_data == 2) { /* in the bottom-left */ + final_data = final_data | 0x8 | ancilData; - } else if (chest_data == 2) { /* in the north */ - final_data = final_data | 0x4; /* only can face to east or west */ - if ( !((air_data & 0x4) == 4) ) { /* 0 = west */ - final_data = final_data | 0x2; /* facing east */ - } + } else if (chest_data == 4) { /*in the bottom-right */ + final_data = final_data | 0x8 | ancilData; - } else if (chest_data == 4) { /*in the west */ - final_data = final_data | 0x4; - if ( (air_data & 0x2) == 2 ) { - final_data = final_data | 0x1; /* facing north */ - } else { - final_data = final_data | 0x3; /* facing south */ - } - - } else if (chest_data == 8) { /*in the south */ - final_data = final_data | 0x8; - if ( !((air_data & 0x4) == 4) ) { - final_data = final_data | 0x2; /* facing east */ - } + } else if (chest_data == 8) { /*in the upper-right */ + final_data = final_data | 0x10 | ancilData; } else if (chest_data == 0) { /* Single chest, determine the orientation */ - if ( ((air_data & 0x8) == 0) && ((air_data & 0x2) == 2) ) { /* block in +x and no block in -x */ - final_data = final_data | 0x1; /* facing north */ - - } else if ( ((air_data & 0x2) == 0) && ((air_data & 0x8) == 8)) { - final_data = final_data | 0x3; - - } else if ( ((air_data & 0x4) == 0) && ((air_data & 0x1) == 1)) { - final_data = final_data | 0x2; - } /* else, facing west, value = 0 */ + final_data = ancilData; } else { - /* more than one adjacent chests! render as normal chest */ + /* more than one adjacent chests! That shouldn't be + * possible! render as normal chest */ return 0; } - return final_data; } else if ((state->block == 101) || (state->block == 102)) { /* iron bars and glass panes: - * they seem to stick to almost everything but air, but + * they seem to stick to almost everything but air, * not sure yet! Still a TODO! */ /* return check adjacent blocks with air, bit inverted */ return check_adjacent_blocks(state, x, y, z, 0) ^ 0x0f; diff --git a/overviewer_core/src/primitives/lighting.c b/overviewer_core/src/primitives/lighting.c index 317ac98..d264ae7 100644 --- a/overviewer_core/src/primitives/lighting.c +++ b/overviewer_core/src/primitives/lighting.c @@ -158,7 +158,8 @@ get_lighting_color(RenderPrimitiveLighting *self, RenderState *state, blocklevel = get_data(state, BLOCKLIGHT, x, y, z); /* special half-step handling, stairs handling */ - if (block == 44 || block == 53 || block == 67 || block == 108 || block == 109 || block == 114) { + if (block == 44 || block == 53 || block == 67 || block == 108 || block == 109 || block == 114 || + block == 128 || block == 134 || block == 135 || block == 136) { unsigned int upper_block; /* stairs and half-blocks take the skylevel from the upper block if it's transparent */ @@ -167,7 +168,9 @@ get_lighting_color(RenderPrimitiveLighting *self, RenderState *state, do { upper_counter++; upper_block = get_data(state, BLOCKS, x, y + upper_counter, z); - } while (upper_block == 44 || upper_block == 53 || upper_block == 67 || upper_block == 108 || upper_block == 109 || upper_block == 114); + } while (upper_block == 44 || upper_block == 53 || upper_block == 67 || upper_block == 108 || + upper_block == 109 || upper_block == 114 || upper_block == 128 || upper_block == 134 || + upper_block == 135 || upper_block == 136); if (is_transparent(upper_block)) { skylevel = get_data(state, SKYLIGHT, x, y + upper_counter, z); } else { diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index c150101..e8f9c38 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -131,7 +131,7 @@ class Textures(object): # a list of subdirectories to search for a given file, # after the obvious '.' - search_dirs = ['anim', 'misc', 'environment'] + search_dirs = ['anim', 'misc', 'environment', 'item'] search_zip_paths = [filename,] + [d + '/' + filename for d in search_dirs] def search_dir(base): """Search the given base dir for filename, in search_dirs.""" @@ -852,17 +852,36 @@ block(blockid=15, top_index=33) # coal ore block(blockid=16, top_index=34) -@material(blockid=17, data=range(4), solid=True) +@material(blockid=17, data=range(12), solid=True) def wood(self, blockid, data): + # extract orientation and wood type frorm data bits + wood_type = data & 3 + wood_orientation = data & 12 + if self.rotation == 1: + if wood_orientation == 4: wood_orientation = 8 + elif wood_orientation == 8: wood_orientation = 4 + elif self.rotation == 2: + if wood_orientation == 4: wood_orientation = 8 + elif wood_orientation == 8: wood_orientation = 4 + + # choose textures top = self.terrain_images[21] - if data == 0: # normal - return self.build_block(top, self.terrain_images[20]) - if data == 1: # birch - return self.build_block(top, self.terrain_images[116]) - if data == 2: # pine - return self.build_block(top, self.terrain_images[117]) - if data == 3: # jungle wood - return self.build_block(top, self.terrain_images[153]) + if wood_type == 0: # normal + side = self.terrain_images[20] + if wood_type == 1: # birch + side = self.terrain_images[116] + if wood_type == 2: # pine + side = self.terrain_images[117] + if wood_type == 3: # jungle wood + side = self.terrain_images[153] + + # choose orientation and paste textures + if wood_orientation == 0: + return self.build_block(top, side) + elif wood_orientation == 4: # east-west orientation + return self.build_full_block(side.rotate(90), None, None, top, side.rotate(90)) + elif wood_orientation == 8: # north-south orientation + return self.build_full_block(side, None, None, side.rotate(270), top) @material(blockid=18, data=range(16), transparent=True, solid=True) def leaves(self, blockid, data): @@ -1491,8 +1510,8 @@ def fire(self, blockid, data): # monster spawner block(blockid=52, top_index=34, transparent=True) -# wooden, cobblestone, red brick, stone brick and netherbrick stairs. -@material(blockid=[53,67,108,109,114], data=range(8), transparent=True, solid=True, nospawn=True) +# wooden, cobblestone, red brick, stone brick, netherbrick, sandstone, spruce, birch and jungle stairs. +@material(blockid=[53,67,108,109,114,128,134,135,136], data=range(8), transparent=True, solid=True, nospawn=True) def stairs(self, blockid, data): # first, rotations @@ -1526,13 +1545,27 @@ def stairs(self, blockid, data): texture = self.terrain_images[54] elif blockid == 114: # netherbrick stairs texture = self.terrain_images[224] - + elif blockid == 128: # sandstone stairs + texture = self.terrain_images[192] + elif blockid == 134: # spruce wood stairs + texture = self.terrain_images[198] + elif blockid == 135: # birch wood stairs + texture = self.terrain_images[214] + elif blockid == 136: # jungle good stairs + texture = self.terrain_images[199] + + side = texture.copy() half_block_u = texture.copy() # up, down, left, right half_block_d = texture.copy() half_block_l = texture.copy() half_block_r = texture.copy() + # sandstone stairs have spcial top texture + if blockid == 128: + half_block_u = self.terrain_images[176].copy() + half_block_d = self.terrain_images[176].copy() + # generate needed geometries ImageDraw.Draw(side).rectangle((0,0,7,6),outline=(0,0,0,0),fill=(0,0,0,0)) ImageDraw.Draw(half_block_u).rectangle((0,8,15,15),outline=(0,0,0,0),fill=(0,0,0,0)) @@ -1610,50 +1643,195 @@ def stairs(self, blockid, data): return img -# normal and locked chest (locked was the one used in april fools' day) -# uses pseudo-ancildata found in iterate.c -@material(blockid=[54,95], data=range(12), solid=True) +# normal, locked (used in april's fool day) and ender chests chests +@material(blockid=[54,95,130], data=range(30), transparent = True) def chests(self, blockid, data): - # First two bits of the pseudo data store if it's a single chest - # or it's a double chest, first half or second half (left to right). - # The last two bits store the orientation. + # the first 3 bits are the orientation as stored in minecraft, + # bits 0x8 and 0x10 indicate which half of the double chest is it. - # No need for rotation stuff, uses pseudo data and rotates with the map + # first, do the rotation if needed + orientation_data = data & 7 + if self.rotation == 1: + if orientation_data == 2: data = 5 | (data & 24) + elif orientation_data == 3: data = 4 | (data & 24) + elif orientation_data == 4: data = 2 | (data & 24) + elif orientation_data == 5: data = 3 | (data & 24) + elif self.rotation == 2: + if orientation_data == 2: data = 3 | (data & 24) + elif orientation_data == 3: data = 2 | (data & 24) + elif orientation_data == 4: data = 5 | (data & 24) + elif orientation_data == 5: data = 4 | (data & 24) + elif self.rotation == 3: + if orientation_data == 2: data = 4 | (data & 24) + elif orientation_data == 3: data = 5 | (data & 24) + elif orientation_data == 4: data = 3 | (data & 24) + elif orientation_data == 5: data = 2 | (data & 24) + + if blockid in (95,130) and not data in [2,3,4,5]: return None + # iterate.c will only return the ancil data (without pseudo + # ancil data) for locked and ender chests, so only + # ancilData = 2,3,4,5 are used for this blockids + + if data & 24 == 0: + if blockid == 130: t = self.load_image("enderchest.png") + else: t = self.load_image("chest.png") - top = self.terrain_images[25] - side = self.terrain_images[26] + # the textures is no longer in terrain.png, get it from + # item/chest.png and get by cropping all the needed stuff + if t.size != (64,64): t = t.resize((64,64), Image.ANTIALIAS) + # top + top = t.crop((14,0,28,14)) + top.load() # every crop need a load, crop is a lazy operation + # see PIL manual + img = Image.new("RGBA", (16,16), self.bgcolor) + alpha_over(img,top,(1,1)) + top = img + # front + front_top = t.crop((14,14,28,19)) + front_top.load() + front_bottom = t.crop((14,34,28,43)) + front_bottom.load() + front_lock = t.crop((1,0,3,4)) + front_lock.load() + front = Image.new("RGBA", (16,16), self.bgcolor) + alpha_over(front,front_top, (1,1)) + alpha_over(front,front_bottom, (1,6)) + alpha_over(front,front_lock, (7,3)) + # left side + # left side, right side, and back are esentially the same for + # the default texture, we take it anyway just in case other + # textures make use of it. + side_l_top = t.crop((0,14,14,19)) + side_l_top.load() + side_l_bottom = t.crop((0,34,14,43)) + side_l_bottom.load() + side_l = Image.new("RGBA", (16,16), self.bgcolor) + alpha_over(side_l,side_l_top, (1,1)) + alpha_over(side_l,side_l_bottom, (1,6)) + # right side + side_r_top = t.crop((28,14,43,20)) + side_r_top.load() + side_r_bottom = t.crop((28,33,42,43)) + side_r_bottom.load() + side_r = Image.new("RGBA", (16,16), self.bgcolor) + alpha_over(side_r,side_l_top, (1,1)) + alpha_over(side_r,side_l_bottom, (1,6)) + # back + back_top = t.crop((42,14,56,18)) + back_top.load() + back_bottom = t.crop((42,33,56,43)) + back_bottom.load() + back = Image.new("RGBA", (16,16), self.bgcolor) + alpha_over(back,side_l_top, (1,1)) + alpha_over(back,side_l_bottom, (1,6)) - if data & 12 == 0: # single chest - front = self.terrain_images[27] - back = self.terrain_images[26] - - elif data & 12 == 4: # double, first half - front = self.terrain_images[41] - back = self.terrain_images[57] - - elif data & 12 == 8: # double, second half - front = self.terrain_images[42] - back = self.terrain_images[58] - - else: # just in case - front = self.terrain_images[25] - side = self.terrain_images[25] - back = self.terrain_images[25] - - if data & 3 == 0: # facing west - img = self.build_full_block(top, None, None, side, front) - - elif data & 3 == 1: # north - img = self.build_full_block(top, None, None, front, side) - - elif data & 3 == 2: # east - img = self.build_full_block(top, None, None, side, back) - - elif data & 3 == 3: # south - img = self.build_full_block(top, None, None, back, side) - else: - img = self.build_full_block(top, None, None, back, side) + # large chest + # the textures is no longer in terrain.png, get it from + # item/chest.png and get all the needed stuff + t = self.load_image("largechest.png") + if t.size != (128,64): t = t.resize((128,64), Image.ANTIALIAS) + # top + top = t.crop((14,0,44,14)) + top.load() + img = Image.new("RGBA", (32,16), self.bgcolor) + alpha_over(img,top,(1,1)) + top = img + # front + front_top = t.crop((14,14,44,18)) + front_top.load() + front_bottom = t.crop((14,33,44,43)) + front_bottom.load() + front_lock = t.crop((1,0,3,5)) + front_lock.load() + front = Image.new("RGBA", (32,16), self.bgcolor) + alpha_over(front,front_top,(1,1)) + alpha_over(front,front_bottom,(1,5)) + alpha_over(front,front_lock,(15,3)) + # left side + side_l_top = t.crop((0,14,14,18)) + side_l_top.load() + side_l_bottom = t.crop((0,33,14,43)) + side_l_bottom.load() + side_l = Image.new("RGBA", (16,16), self.bgcolor) + alpha_over(side_l,side_l_top, (1,1)) + alpha_over(side_l,side_l_bottom,(1,5)) + # right side + side_r_top = t.crop((44,14,58,18)) + side_r_top.load() + side_r_bottom = t.crop((44,33,58,43)) + side_r_bottom.load() + side_r = Image.new("RGBA", (16,16), self.bgcolor) + alpha_over(side_r,side_r_top, (1,1)) + alpha_over(side_r,side_r_bottom,(1,5)) + # back + back_top = t.crop((58,14,88,18)) + back_top.load() + back_bottom = t.crop((58,33,88,43)) + back_bottom.load() + back = Image.new("RGBA", (32,16), self.bgcolor) + alpha_over(back,back_top,(1,1)) + alpha_over(back,back_bottom,(1,5)) + + + if data & 24 == 8: # double chest, first half + top = top.crop((0,0,16,16)) + top.load() + front = front.crop((0,0,16,16)) + front.load() + back = back.crop((0,0,16,16)) + back.load() + #~ side = side_l + + elif data & 24 == 16: # double, second half + top = top.crop((16,0,32,16)) + top.load() + front = front.crop((16,0,32,16)) + front.load() + back = back.crop((16,0,32,16)) + back.load() + #~ side = side_r + + else: # just in case + return None + + # compose the final block + img = Image.new("RGBA", (24,24), self.bgcolor) + if data & 7 == 2: # north + side = self.transform_image_side(side_r) + alpha_over(img, side, (1,7)) + back = self.transform_image_side(back) + alpha_over(img, back.transpose(Image.FLIP_LEFT_RIGHT), (11,7)) + front = self.transform_image_side(front) + top = self.transform_image_top(top.rotate(180)) + alpha_over(img, top, (0,2)) + + elif data & 7 == 3: # south + side = self.transform_image_side(side_l) + alpha_over(img, side, (1,7)) + front = self.transform_image_side(front).transpose(Image.FLIP_LEFT_RIGHT) + top = self.transform_image_top(top.rotate(180)) + alpha_over(img, top, (0,2)) + alpha_over(img, front,(11,7)) + + elif data & 7 == 4: # west + side = self.transform_image_side(side_r) + alpha_over(img, side.transpose(Image.FLIP_LEFT_RIGHT), (11,7)) + front = self.transform_image_side(front) + alpha_over(img, front,(1,7)) + top = self.transform_image_top(top.rotate(270)) + alpha_over(img, top, (0,2)) + + elif data & 7 == 5: # east + back = self.transform_image_side(back) + side = self.transform_image_side(side_l).transpose(Image.FLIP_LEFT_RIGHT) + alpha_over(img, side, (11,7)) + alpha_over(img, back, (1,7)) + top = self.transform_image_top(top.rotate(270)) + alpha_over(img, top, (0,2)) + + else: # just in case + img = None return img @@ -3085,8 +3263,11 @@ def enchantment_table(self, blockid, data): # TODO this is a place holder, is a 2d image pasted @material(blockid=117, data=range(5), transparent=True) def brewing_stand(self, blockid, data): + base = self.terrain_images[156] + img = self.build_full_block(None, None, None, None, None, base) t = self.terrain_images[157] - img = self.build_billboard(t) + stand = self.build_billboard(t) + alpha_over(img,stand,(0,-2)) return img # cauldron @@ -3220,3 +3401,90 @@ def slabs(self, blockid, data): alpha_over(img, top, (0,6 - delta), top) return img + +# emerald ore +block(blockid=130, top_index=171) + +# emerald block +block(blockid=133, top_index=25) + +# cocoa plant +@material(blockid=127, data=range(12), transparent=True) +def cocoa_plant(self, blockid, data): + orientation = data & 3 + # rotation + if self.rotation == 1: + if orientation == 0: orientation = 1 + elif orientation == 1: orientation = 2 + elif orientation == 2: orientation = 3 + elif orientation == 3: orientation = 0 + elif self.rotation == 2: + if orientation == 0: orientation = 2 + elif orientation == 1: orientation = 3 + elif orientation == 2: orientation = 0 + elif orientation == 3: orientation = 1 + elif self.rotation == 3: + if orientation == 0: orientation = 3 + elif orientation == 1: orientation = 0 + elif orientation == 2: orientation = 1 + elif orientation == 3: orientation = 2 + + size = data & 12 + if size == 8: # big + t = self.terrain_images[168] + c_left = (0,3) + c_right = (8,3) + c_top = (5,2) + elif size == 4: # normal + t = self.terrain_images[169] + c_left = (-2,2) + c_right = (8,2) + c_top = (5,2) + elif size == 0: # small + t = self.terrain_images[170] + c_left = (-3,2) + c_right = (6,2) + c_top = (5,2) + + # let's get every texture piece necessary to do this + stalk = t.copy() + ImageDraw.Draw(stalk).rectangle((0,0,11,16),outline=(0,0,0,0),fill=(0,0,0,0)) + ImageDraw.Draw(stalk).rectangle((12,4,16,16),outline=(0,0,0,0),fill=(0,0,0,0)) + + top = t.copy() # warning! changes with plant size + ImageDraw.Draw(top).rectangle((0,7,16,16),outline=(0,0,0,0),fill=(0,0,0,0)) + ImageDraw.Draw(top).rectangle((7,0,16,6),outline=(0,0,0,0),fill=(0,0,0,0)) + + side = t.copy() # warning! changes with plant size + ImageDraw.Draw(side).rectangle((0,0,6,16),outline=(0,0,0,0),fill=(0,0,0,0)) + ImageDraw.Draw(side).rectangle((0,0,16,3),outline=(0,0,0,0),fill=(0,0,0,0)) + ImageDraw.Draw(side).rectangle((0,14,16,16),outline=(0,0,0,0),fill=(0,0,0,0)) + + # first compose the block of the cocoa plant + block = Image.new("RGBA", (24,24), self.bgcolor) + tmp = self.transform_image_side(side).transpose(Image.FLIP_LEFT_RIGHT) + alpha_over (block, tmp, c_right,tmp) # right side + tmp = tmp.transpose(Image.FLIP_LEFT_RIGHT) + alpha_over (block, tmp, c_left,tmp) # left side + tmp = self.transform_image_top(top) + alpha_over(block, tmp, c_top,tmp) + if size == 0: + # fix a pixel hole + block.putpixel((6,9), block.getpixel((6,10))) + + # compose the cocoa plant + img = Image.new("RGBA", (24,24), self.bgcolor) + if orientation in (2,3): # south and west + tmp = self.transform_image_side(stalk).transpose(Image.FLIP_LEFT_RIGHT) + alpha_over(img, block,(-1,-2), block) + alpha_over(img, tmp, (4,-2), tmp) + if orientation == 3: + img = img.transpose(Image.FLIP_LEFT_RIGHT) + elif orientation in (0,1): # north and east + tmp = self.transform_image_side(stalk.transpose(Image.FLIP_LEFT_RIGHT)) + alpha_over(img, block,(-1,5), block) + alpha_over(img, tmp, (2,12), tmp) + if orientation == 0: + img = img.transpose(Image.FLIP_LEFT_RIGHT) + + return img