Add support for redstone and improve the looking of waterfalls.
Changes in textures.py and iterate.c
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
185
textures.py
185
textures.py
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user