0

Add support for redstone and improve the looking of waterfalls.

Changes in textures.py and iterate.c
This commit is contained in:
Alejandro Aguilera
2011-03-27 03:51:45 +02:00
parent 0fe9c7c050
commit afb05098f9
2 changed files with 252 additions and 15 deletions

View File

@@ -74,7 +74,7 @@ is_transparent(unsigned char b) {
unsigned char 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 * Generates a pseudo ancillary data for blocks that depend of
* what are surrounded and don't have ancillary data. This * what are surrounded and don't have ancillary data. This
@@ -96,48 +96,48 @@ unsigned char
if (state->x == 15) { /* +x direction */ 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 (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); pdata = pdata|(1 << 3);
} }
} }
} else { } 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); pdata = pdata|(1 << 3);
} }
} }
if (state->y == 15) { /* +y direction*/ if (state->y == 15) { /* +y direction*/
if (state->right_blocks != Py_None) { 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); pdata = pdata|(1 << 2);
} }
} }
} else { } 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); pdata = pdata|(1 << 2);
} }
} }
if (state->x == 0) { /* -x direction*/ if (state->x == 0) { /* -x direction*/
if (state->left_blocks != Py_None) { 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); pdata = pdata|(1 << 1);
} }
} }
} else { } 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); pdata = pdata|(1 << 1);
} }
} }
if (state->y == 0) { /* -y direction */ if (state->y == 0) { /* -y direction */
if (state->up_left_blocks != Py_None) { 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); pdata = pdata|(1 << 0);
} }
} }
} else { } 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); pdata = pdata|(1 << 0);
} }
} }
@@ -147,15 +147,69 @@ unsigned char
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 * Generates a fake ancillary data for blocks that are drawn
* depending on what are surrounded. * 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) ^ 0b1111) | 0b10000;
return data;
} else if ((ancilData == 8) || (ancilData == 9)) { /* falling water */
data = (check_adjacent_blocks(state, x, y, z, state->block) ^ 0b1111);
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 | 0b1000000;
}
if ((above_level_data & 0b0001) == 1) { /* draw top left going up redstonewire */
final_data = final_data | 0b0100000;
}
if ((above_level_data & 0b1000) == 8) { /* draw top right going up redstonewire */
final_data = final_data | 0b0010000;
}
return final_data;
} }
return 0; return 0;
} }
@@ -275,8 +329,8 @@ chunk_render(PyObject *self, PyObject *args) {
PyObject *tmp; PyObject *tmp;
unsigned char ancilData = getArrayByte3D(blockdata_expanded, state.x, state.y, state.z); unsigned char ancilData = getArrayByte3D(blockdata_expanded, state.x, state.y, state.z);
if (state.block == 85) { if ((state.block == 85) || (state.block == 9) || (state.block == 55)) {
ancilData = generate_pseudo_data(&state); ancilData = generate_pseudo_data(&state, ancilData);
} }
tmp = PyTuple_New(2); tmp = PyTuple_New(2);

View File

@@ -265,6 +265,79 @@ def _build_block(top, side, blockID=None):
return img 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(): def _build_blockimages():
"""Returns a mapping from blockid to an image of that block in perspective """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). 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) img = _build_block(top, side, blockID)
return (img.convert("RGB"), img.split()[3]) 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 return None
def tintTexture(im, c): 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 # 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) # 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 # this is a map of special blockIDs to a list of all
# possible values for ancillary data that it might have. # 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[51] = range(16) # fire
special_map[43] = range(4) # stone, sandstone, wooden and cobblestone double-slab 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[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 # 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 # what that data represents. For now, assume that the range for data is 0 to 5