0

Merge remote branch 'origin/devel'

Conflicts:
	docs/config.rst
This commit is contained in:
Andrew Chin
2012-06-03 21:15:12 -04:00
11 changed files with 452 additions and 95 deletions

View File

@@ -70,6 +70,7 @@ feature.
* Zach McCullough <nosrepa@gmail.com> * Zach McCullough <nosrepa@gmail.com>
* Mike <mike@snowcrash.ca> * Mike <mike@snowcrash.ca>
* Morlok8k <otis.spankmeyer@gmail.com> * Morlok8k <otis.spankmeyer@gmail.com>
* Adam Novak <interfect@gmail.com>
* Richard Pastrick <rpastric@contre.us> * Richard Pastrick <rpastric@contre.us>
* Ryan Rector <rmrector@gmail.com> * Ryan Rector <rmrector@gmail.com>
* Jason Scheirer <jason.scheirer@gmail.com> * Jason Scheirer <jason.scheirer@gmail.com>

View File

@@ -432,7 +432,14 @@ values. The valid configuration keys are listed below.
**Default:** ``#1a1a1a`` **Default:** ``#1a1a1a``
.. _option_texturepath: ``base``
Allows you to specify a remote location for the tile folder, useful if you
rsync your map's images to a remote server. Leave a trailing slash and point
to the location that contains the tile folders for each render, not the
tiles folder itself. For example, if the tile images start at
http://domain.com/map/world_day/ you want to set this to http://domain.com/map/
.. _option_texture_pack:
``texturepath`` ``texturepath``
This is a where a specific texture pack can be found to be used during this render. This is a where a specific texture pack can be found to be used during this render.
@@ -624,6 +631,17 @@ Depth
max max
highest level of blocks to render. Default: 255 highest level of blocks to render. Default: 255
Exposed
Only renders blocks that are exposed (adjacent to a transparent block).
**Options**
mode
when set to 1, inverts the render mode, only drawing unexposed blocks. Default: 0
NoFluids
Don't render fluid blocks (water, lava).
EdgeLines EdgeLines
Draw edge lines on the back side of blocks, to help distinguish them from Draw edge lines on the back side of blocks, to help distinguish them from
the background. the background.

View File

@@ -421,7 +421,7 @@ dir but you forgot to put quotes around the directory, since it contains spaces.
# only pass to the TileSet the options it really cares about # only pass to the TileSet the options it really cares about
render['name'] = render_name # perhaps a hack. This is stored here for the asset manager render['name'] = render_name # perhaps a hack. This is stored here for the asset manager
tileSetOpts = util.dict_subset(render, ["name", "imgformat", "renderchecks", "rerenderprob", "bgcolor", "imgquality", "optimizeimg", "rendermode", "worldname_orig", "title", "dimension", "changelist","showspawn", "overlay"]) tileSetOpts = util.dict_subset(render, ["name", "imgformat", "renderchecks", "rerenderprob", "bgcolor", "imgquality", "optimizeimg", "rendermode", "worldname_orig", "title", "dimension", "changelist","showspawn", "overlay","base"])
tileSetOpts.update({"spawn": w.find_true_spawn()}) # TODO find a better way to do this tileSetOpts.update({"spawn": w.find_true_spawn()}) # TODO find a better way to do this
tset = tileset.TileSet(rset, assetMrg, tex, tileSetOpts, tileset_dir) tset = tileset.TileSet(rset, assetMrg, tex, tileSetOpts, tileset_dir)
tilesets.append(tset) tilesets.append(tset)

View File

@@ -62,6 +62,15 @@ class Depth(RenderPrimitive):
"min": ("lowest level of blocks to render", 0), "min": ("lowest level of blocks to render", 0),
"max": ("highest level of blocks to render", 255), "max": ("highest level of blocks to render", 255),
} }
class Exposed(RenderPrimitive):
name = "exposed"
options = {
"mode": ("0 = exposed blocks only, 1 = unexposed blocks only", 0),
}
class NoFluids(RenderPrimitive):
name = "no-fluids"
class EdgeLines(RenderPrimitive): class EdgeLines(RenderPrimitive):
name = "edge-lines" name = "edge-lines"

View File

@@ -81,6 +81,7 @@ renders = Setting(required=True, default=util.OrderedDict(),
"markers": Setting(required=False, validator=validateMarkers, default=[]), "markers": Setting(required=False, validator=validateMarkers, default=[]),
"overlay": Setting(required=False, validator=validateOverlays, default=[]), "overlay": Setting(required=False, validator=validateOverlays, default=[]),
"showspawn": Setting(required=False, validator=validateBool, default=True), "showspawn": Setting(required=False, validator=validateBool, default=True),
"base": Setting(required=False, validator=validateStr, default=""),
# Remove this eventually (once people update their configs) # Remove this eventually (once people update their configs)
"worldname": Setting(required=False, default=None, "worldname": Setting(required=False, default=None,

View File

@@ -321,71 +321,46 @@ generate_pseudo_data(RenderState *state, unsigned char ancilData) {
} }
return final_data; return final_data;
} else if (state-> block == 54) { /* chests */ } else if (state->block == 54) { /* normal chests */
/* the top 2 bits are used to store the type of chest /* Orientation is given by ancilData, pseudo data needed to
* (single or double), the 2 bottom bits are used for * choose from single or double chest and the correct half of
* orientation, look textures.py for more information. */ * 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 unsigned char chest_data = 0, final_data = 0;
* chest facing west */
unsigned char chest_data = 0, air_data = 0, final_data = 0;
/* search for chests */ /* search for chests */
chest_data = check_adjacent_blocks(state, x, y, z, 54); chest_data = check_adjacent_blocks(state, x, y, z, 54);
/* search for air */ if (chest_data == 1) { /* another chest in the upper-left */
air_data = check_adjacent_blocks(state, x, y, z, 0); final_data = final_data | 0x10 | ancilData;
if (chest_data == 1) { /* another chest in the east */ } else if (chest_data == 2) { /* in the bottom-left */
final_data = final_data | 0x8; /* only can face to north or south */ final_data = final_data | 0x8 | ancilData;
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 north */ } else if (chest_data == 4) { /*in the bottom-right */
final_data = final_data | 0x4; /* only can face to east or west */ final_data = final_data | 0x8 | ancilData;
if ( !((air_data & 0x4) == 4) ) { /* 0 = west */
final_data = final_data | 0x2; /* facing east */
}
} else if (chest_data == 4) { /*in the west */ } else if (chest_data == 8) { /*in the upper-right */
final_data = final_data | 0x4; final_data = final_data | 0x10 | ancilData;
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 == 0) { } else if (chest_data == 0) {
/* Single chest, determine the orientation */ /* Single chest, determine the orientation */
if ( ((air_data & 0x8) == 0) && ((air_data & 0x2) == 2) ) { /* block in +x and no block in -x */ final_data = ancilData;
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 */
} else { } 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 0;
} }
return final_data; return final_data;
} else if ((state->block == 101) || (state->block == 102)) { } else if ((state->block == 101) || (state->block == 102)) {
/* iron bars and glass panes: /* 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! */ * not sure yet! Still a TODO! */
/* return check adjacent blocks with air, bit inverted */ /* return check adjacent blocks with air, bit inverted */
return check_adjacent_blocks(state, x, y, z, 0) ^ 0x0f; return check_adjacent_blocks(state, x, y, z, 0) ^ 0x0f;

View File

@@ -41,7 +41,7 @@ edge_lines_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, P
int x = state->x, y = state->y, z = state->z; int x = state->x, y = state->y, z = state->z;
int increment=0; int increment=0;
if (state->block == 44 && ((state->block_data & 0x8) == 0 )) // half-step BUT no upsidown half-step if ((state->block == 44 || state->block == 126) && ((state->block_data & 0x8) == 0 )) // half-steps BUT no upsidown half-steps
increment=6; increment=6;
else if ((state->block == 78) || (state->block == 93) || (state->block == 94)) // snow, redstone repeaters (on and off) else if ((state->block == 78) || (state->block == 93) || (state->block == 94)) // snow, redstone repeaters (on and off)
increment=9; increment=9;

View File

@@ -0,0 +1,109 @@
/*
* This file is part of the Minecraft Overviewer.
*
* Minecraft Overviewer is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Minecraft Overviewer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with the Overviewer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../overviewer.h"
typedef struct {
unsigned int mode; /* 0 = exposed only, 1 = unexposed only */
} PrimitiveExposed;
static int
exposed_start(void *data, RenderState *state, PyObject *support) {
PrimitiveExposed *self = (PrimitiveExposed *)data;
if (!render_mode_parse_option(support, "mode", "I", &(self->mode)))
return 1;
return 0;
}
static int
exposed_hidden(void *data, RenderState *state, int x, int y, int z) {
PrimitiveExposed *self = (PrimitiveExposed *)data;
/* Unset these flags if seeming exposure from any of these directions would
* be due to not having data there.
*/
int validMinusX = 1;
int validPlusX = 1;
int validMinusY = 1;
int validPlusY = 1;
int validMinusZ = 1;
int validPlusZ = 1;
/* special handling for section boundaries */
/* If the neighboring section has no block data, ignore exposure from that
* direction
*/
if (x == 0 && (!(state->chunks[0][1].loaded) || state->chunks[0][1].sections[state->chunky].blocks == NULL)) {
/* No data in -x direction */
validMinusX = 0;
}
if (x == 15 && (!(state->chunks[2][1].loaded) || state->chunks[2][1].sections[state->chunky].blocks == NULL)) {
/* No data in +x direction */
validPlusX = 0;
}
if (y == 0 && (state->chunky - 1 < 0 || state->chunks[1][1].sections[state->chunky - 1].blocks == NULL)) {
/* No data in -y direction */
validMinusY = 0;
}
if (y == 15 && (state->chunky + 1 >= SECTIONS_PER_CHUNK || state->chunks[1][1].sections[state->chunky + 1].blocks == NULL)) {
/* No data in +y direction */
validPlusY = 0;
}
if (z == 0 && (!(state->chunks[1][0].loaded) || state->chunks[1][0].sections[state->chunky].blocks == NULL)) {
/* No data in -z direction */
validMinusZ = 0;
}
if (z == 15 && (!(state->chunks[1][2].loaded) || state->chunks[1][2].sections[state->chunky].blocks == NULL)) {
/* No data in +z direction */
validPlusZ = 0;
}
/* If any of the 6 blocks adjacent to us are transparent, we're exposed */
if( (validMinusX && is_transparent(get_data(state, BLOCKS, x-1, y, z))) ||
(validPlusX && is_transparent(get_data(state, BLOCKS, x+1, y, z))) ||
(validMinusY && is_transparent(get_data(state, BLOCKS, x, y-1, z))) ||
(validPlusY && is_transparent(get_data(state, BLOCKS, x, y+1, z))) ||
(validMinusZ && is_transparent(get_data(state, BLOCKS, x, y, z-1))) ||
(validPlusZ && is_transparent(get_data(state, BLOCKS, x, y, z+1 ))) ) {
/* Block is exposed */
/* Returns 1 and hides us if we're rendering unexposed blocks, 0 and
* shows us if we're rendering exposed blocks
*/
return self->mode;
}
/* We have no valid evidence that the block is exposed */
return !(self->mode); /* Hide in normal mode, reveal in inverted mode */
}
RenderPrimitiveInterface primitive_exposed = {
"exposed", sizeof(PrimitiveExposed),
exposed_start,
NULL,
NULL,
exposed_hidden,
NULL,
};

View File

@@ -0,0 +1,37 @@
/*
* This file is part of the Minecraft Overviewer.
*
* Minecraft Overviewer is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Minecraft Overviewer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with the Overviewer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../overviewer.h"
static int
no_fluids_start(void *data, RenderState *state, PyObject *support) {
return 0;
}
static int
no_fluids_hidden(void *data, RenderState *state, int x, int y, int z) {
return block_has_property(state->block, FLUID);
}
RenderPrimitiveInterface primitive_no_fluids = {
"no-fluids", 0,
no_fluids_start,
NULL,
NULL,
no_fluids_hidden,
NULL,
};

View File

@@ -131,7 +131,7 @@ class Textures(object):
# a list of subdirectories to search for a given file, # a list of subdirectories to search for a given file,
# after the obvious '.' # 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] search_zip_paths = [filename,] + [d + '/' + filename for d in search_dirs]
def search_dir(base): def search_dir(base):
"""Search the given base dir for filename, in search_dirs.""" """Search the given base dir for filename, in search_dirs."""
@@ -1336,6 +1336,8 @@ block(blockid=41, top_index=23)
block(blockid=42, top_index=22) block(blockid=42, top_index=22)
# double slabs and slabs # double slabs and slabs
# these wooden slabs are unobtainable without cheating, they are still
# here because lots of pre-1.3 worlds use this blocks
@material(blockid=[43, 44], data=range(16), transparent=(44,), solid=True) @material(blockid=[43, 44], data=range(16), transparent=(44,), solid=True)
def slabs(self, blockid, data): def slabs(self, blockid, data):
texture = data & 7 texture = data & 7
@@ -1489,8 +1491,8 @@ def fire(self, blockid, data):
# monster spawner # monster spawner
block(blockid=52, top_index=34, transparent=True) block(blockid=52, top_index=34, transparent=True)
# wooden, cobblestone, red brick, stone brick and netherbrick stairs. # wooden, cobblestone, red brick, stone brick, netherbrick and sandstone stairs.
@material(blockid=[53,67,108,109,114], data=range(8), transparent=True, solid=True, nospawn=True) @material(blockid=[53,67,108,109,114,128], data=range(8), transparent=True, solid=True, nospawn=True)
def stairs(self, blockid, data): def stairs(self, blockid, data):
# first, rotations # first, rotations
@@ -1524,7 +1526,9 @@ def stairs(self, blockid, data):
texture = self.terrain_images[54] texture = self.terrain_images[54]
elif blockid == 114: # netherbrick stairs elif blockid == 114: # netherbrick stairs
texture = self.terrain_images[224] texture = self.terrain_images[224]
elif blockid ==128: #sandstone stairs
texture = self.terrain_images[192]
side = texture.copy() side = texture.copy()
half_block_u = texture.copy() # up, down, left, right half_block_u = texture.copy() # up, down, left, right
half_block_d = texture.copy() half_block_d = texture.copy()
@@ -1608,50 +1612,195 @@ def stairs(self, blockid, data):
return img return img
# normal and locked chest (locked was the one used in april fools' day) # normal, locked (used in april's fool day) and ender chests chests
# uses pseudo-ancildata found in iterate.c @material(blockid=[54,95,130], data=range(30), transparent = True)
@material(blockid=[54,95], data=range(12), solid=True)
def chests(self, blockid, data): def chests(self, blockid, data):
# First two bits of the pseudo data store if it's a single chest # the first 3 bits are the orientation as stored in minecraft,
# or it's a double chest, first half or second half (left to right). # bits 0x8 and 0x10 indicate which half of the double chest is it.
# The last two bits store the orientation.
# 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")
t.save("textura.png")
# 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))
top = self.terrain_images[25]
side = self.terrain_images[26]
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: 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 return img
@@ -3083,8 +3232,11 @@ def enchantment_table(self, blockid, data):
# TODO this is a place holder, is a 2d image pasted # TODO this is a place holder, is a 2d image pasted
@material(blockid=117, data=range(5), transparent=True) @material(blockid=117, data=range(5), transparent=True)
def brewing_stand(self, blockid, data): 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] t = self.terrain_images[157]
img = self.build_billboard(t) stand = self.build_billboard(t)
alpha_over(img,stand,(0,-2))
return img return img
# cauldron # cauldron
@@ -3169,3 +3321,58 @@ block(blockid=123, top_index=211)
# active redstone lamp # active redstone lamp
block(blockid=124, top_index=212) block(blockid=124, top_index=212)
# wooden double and normal slabs
# these are the new wooden slabs, blockids 43 44 still have wooden
# slabs, but those are unobtainable without cheating
@material(blockid=[125, 126], data=range(16), transparent=(44,), solid=True)
def slabs(self, blockid, data):
texture = data & 7
if texture== 0: # oak
top = side = self.terrain_images[4]
elif texture== 1: # spruce
top = side = self.terrain_images[198]
elif texture== 2: # birch
top = side = self.terrain_images[214]
elif texture== 3: # jungle
top = side = self.terrain_images[199]
else:
return None
if blockid == 125: # double slab
return self.build_block(top, side)
# cut the side texture in half
mask = side.crop((0,8,16,16))
side = Image.new(side.mode, side.size, self.bgcolor)
alpha_over(side, mask,(0,0,16,8), mask)
# plain slab
top = self.transform_image_top(top)
side = self.transform_image_side(side)
otherside = side.transpose(Image.FLIP_LEFT_RIGHT)
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)
# upside down slab
delta = 0
if data & 8 == 8:
delta = 6
img = Image.new("RGBA", (24,24), self.bgcolor)
alpha_over(img, side, (0,12 - delta), side)
alpha_over(img, otherside, (12,12 - delta), otherside)
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)

View File

@@ -516,7 +516,7 @@ class TileSet(object):
defaultZoom = 1, defaultZoom = 1,
maxZoom = self.treedepth, maxZoom = self.treedepth,
path = self.options.get('name'), path = self.options.get('name'),
base = '', base = self.options.get('base'),
bgcolor = bgcolorformat(self.options.get('bgcolor')), bgcolor = bgcolorformat(self.options.get('bgcolor')),
world = self.options.get('worldname_orig') + world = self.options.get('worldname_orig') +
(" - " + self.options.get('dimension') if self.options.get('dimension') != 'default' else ''), (" - " + self.options.get('dimension') if self.options.get('dimension') != 'default' else ''),