0

Merge branch 'blending' of https://github.com/agrif/Minecraft-Overviewer into agrif-blending

This commit is contained in:
Andrew Brown
2010-11-07 08:09:25 -05:00
8 changed files with 431 additions and 60 deletions

7
.gitignore vendored
View File

@@ -1 +1,8 @@
*.pyc *.pyc
build
# various forms of compiled _composite extensions
_composite.so
_composite.pyd
_composite_d.pyd
_composite.dylib

View File

@@ -85,6 +85,28 @@ you can use the Overviewer:
hidden directory). You can also get this file from any of the third party hidden directory). You can also get this file from any of the third party
texture packs out there. texture packs out there.
Compiling the C Extension (optional)
------------------------------------
The C Extension for Overviewer is completely optional. It provides a higher
quality image compositing function that looks better on maps with lighting
enabled, and a slight performance boost.
If you downloaded Overviewer as a binary package, this extension may be already
compiled for you. Overviewer emits a warning if the extension is not found, but
will still work fine.
If you have a C compiler and the Python development libraries set up, you can
compile this extension like this::
python setup.py build
Note that you need the development headers for your version of Python installed,
look for a package named 'python-dev', 'python-devel' or similar. Also, some
Python distributions do not install "Imaging.h" and "ImPlatform.h" properly. If
you get errors complaining about them, you can get them from the PIL source, or
at <http://svn.effbot.org/public/tags/pil-1.1.7/libImaging/>. Just put them in
the same directory as "_composite.c".
Running Running
------- -------
To generate a set of Google Map tiles, use the gmap.py script like this:: To generate a set of Google Map tiles, use the gmap.py script like this::

224
_composite.c Normal file
View File

@@ -0,0 +1,224 @@
/*
* 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/>.
*/
/*
* This file implements a custom alpha_over function for (some) PIL
* images. It's designed to be used through composite.py, which
* includes a proxy alpha_over function that falls back to the default
* PIL paste if this extension is not found.
*/
#include <Python.h>
#include <Imaging.h>
/* like (a * b + 127) / 255), but much faster on most platforms
from PIL's _imaging.c */
#define MULDIV255(a, b, tmp) \
(tmp = (a) * (b) + 128, ((((tmp) >> 8) + (tmp)) >> 8))
typedef struct
{
PyObject_HEAD
Imaging image;
} ImagingObject;
static Imaging imaging_python_to_c(PyObject* obj)
{
PyObject* im;
Imaging image;
/* first, get the 'im' attribute */
im = PyObject_GetAttrString(obj, "im");
if (!im)
return NULL;
/* make sure 'im' is the right type */
if (strcmp(im->ob_type->tp_name, "ImagingCore") != 0)
{
/* it's not -- raise an error and exit */
PyErr_SetString(PyExc_TypeError, "image attribute 'im' is not a core Imaging type");
return NULL;
}
image = ((ImagingObject*)im)->image;
Py_DECREF(im);
return image;
}
static PyObject* _composite_alpha_over(PyObject* self, PyObject* args)
{
/* raw input python variables */
PyObject* dest, * src, * pos, * mask;
/* libImaging handles */
Imaging imDest, imSrc, imMask;
/* cached blend properties */
int src_has_alpha, mask_offset, mask_stride;
/* destination position and size */
int dx, dy, xsize, ysize;
/* source position */
int sx, sy;
/* iteration variables */
unsigned int x, y, i;
/* temporary calculation variables */
int tmp1, tmp2, tmp3;
if (!PyArg_ParseTuple(args, "OOOO", &dest, &src, &pos, &mask))
return NULL;
imDest = imaging_python_to_c(dest);
imSrc = imaging_python_to_c(src);
imMask = imaging_python_to_c(mask);
if (!imDest || !imSrc || !imMask)
return NULL;
/* check the various image modes, make sure they make sense */
if (strcmp(imDest->mode, "RGBA") != 0)
{
PyErr_SetString(PyExc_ValueError, "given destination image does not have mode \"RGBA\"");
return NULL;
}
if (strcmp(imSrc->mode, "RGBA") != 0 && strcmp(imSrc->mode, "RGB") != 0)
{
PyErr_SetString(PyExc_ValueError, "given source image does not have mode \"RGBA\" or \"RGB\"");
return NULL;
}
if (strcmp(imMask->mode, "RGBA") != 0 && strcmp(imMask->mode, "L") != 0)
{
PyErr_SetString(PyExc_ValueError, "given mask image does not have mode \"RGBA\" or \"L\"");
return NULL;
}
/* make sure mask size matches src size */
if (imSrc->xsize != imMask->xsize || imSrc->ysize != imMask->ysize)
{
PyErr_SetString(PyExc_ValueError, "mask and source image sizes do not match");
return NULL;
}
/* set up flags for the src/mask type */
src_has_alpha = (imSrc->pixelsize == 4 ? 1 : 0);
/* how far into image the first alpha byte resides */
mask_offset = (imMask->pixelsize == 4 ? 3 : 0);
/* how many bytes to skip to get to the next alpha byte */
mask_stride = imMask->pixelsize;
/* destination position read */
if (!PyArg_ParseTuple(pos, "iiii", &dx, &dy, &xsize, &ysize))
{
PyErr_SetString(PyExc_TypeError, "given blend destination rect is not valid");
return NULL;
}
/* set up the source position, size and destination position */
/* handle negative dest pos */
if (dx < 0)
{
sx = -dx;
dx = 0;
} else {
sx = 0;
}
if (dy < 0)
{
sy = -dy;
dy = 0;
} else {
sy = 0;
}
/* set up source dimensions */
xsize -= sx;
ysize -= sy;
/* clip dimensions, if needed */
if (dx + xsize > imDest->xsize)
xsize = imDest->xsize - dx;
if (dy + ysize > imDest->ysize)
ysize = imDest->ysize - dy;
/* check that there remains any blending to be done */
if (xsize <= 0 || ysize <= 0)
{
/* nothing to do, return */
Py_INCREF(dest);
return dest;
}
for (y = 0; y < ysize; y++)
{
UINT8* out = (UINT8*) imDest->image[dy + y] + dx*4;
UINT8* outmask = (UINT8*) imDest->image[dy + y] + dx*4 + 3;
UINT8* in = (UINT8*) imSrc->image[sy + y] + sx*(imSrc->pixelsize);
UINT8* inmask = (UINT8*) imMask->image[sy + y] + sx*mask_stride + mask_offset;
for (x = 0; x < xsize; x++)
{
/* special cases */
if (*inmask == 255 || *outmask == 0)
{
*outmask = *inmask;
*out = *in;
out++, in++;
*out = *in;
out++, in++;
*out = *in;
out++, in++;
} else if (*inmask == 0) {
/* do nothing -- source is fully transparent */
out += 3;
in += 3;
} else {
/* general case */
int alpha = *inmask + MULDIV255(*outmask, 255 - *inmask, tmp1);
for (i = 0; i < 3; i++)
{
/* general case */
*out = MULDIV255(*in, *inmask, tmp1) + MULDIV255(MULDIV255(*out, *outmask, tmp2), 255 - *inmask, tmp3);
*out = (*out * 255) / alpha;
out++, in++;
}
*outmask = alpha;
}
out++;
if (src_has_alpha)
in++;
outmask += 4;
inmask += mask_stride;
}
}
Py_INCREF(dest);
return dest;
}
static PyMethodDef _CompositeMethods[] =
{
{"alpha_over", _composite_alpha_over, METH_VARARGS, "alpha over composite function"},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC init_composite(void)
{
(void) Py_InitModule("_composite", _CompositeMethods);
}

View File

@@ -22,6 +22,7 @@ import logging
import nbt import nbt
import textures import textures
import world import world
import composite
""" """
This module has routines related to rendering one particular chunk into an This module has routines related to rendering one particular chunk into an
@@ -36,7 +37,11 @@ image
# of the dest image will have its alpha channel modified. To prevent this: # of the dest image will have its alpha channel modified. To prevent this:
# first use im.split() and take the third item which is the alpha channel and # first use im.split() and take the third item which is the alpha channel and
# use that as the mask. Then take the image and use im.convert("RGB") to strip # use that as the mask. Then take the image and use im.convert("RGB") to strip
# the image from its alpha channel, and use that as the source to paste() # the image from its alpha channel, and use that as the source to alpha_over()
# (note that this workaround is NOT technically needed when using the
# alpha_over extension, BUT this extension may fall back to PIL's
# paste(), which DOES need the workaround.)
def get_lvldata(filename): def get_lvldata(filename):
"""Takes a filename and returns the Level struct, which contains all the """Takes a filename and returns the Level struct, which contains all the
@@ -556,36 +561,36 @@ class ChunkRenderer(object):
# tint the block with a color proportional to its depth # tint the block with a color proportional to its depth
if cave: if cave:
# no lighting for cave -- depth is probably more useful # no lighting for cave -- depth is probably more useful
img.paste(Image.blend(t[0],depth_colors[z],0.3), (imgx, imgy), t[1]) composite.alpha_over(img, Image.blend(t[0],depth_colors[z],0.3), (imgx, imgy), t[1])
else: else:
if not self.world.lighting: if not self.world.lighting:
# no lighting at all # no lighting at all
img.paste(t[0], (imgx, imgy), t[1]) composite.alpha_over(img, t[0], (imgx, imgy), t[1])
elif blockid in transparent_blocks: elif blockid in transparent_blocks:
# transparent means draw the whole # transparent means draw the whole
# block shaded with the current # block shaded with the current
# block's light # block's light
black_coeff, _ = self.get_lighting_coefficient(x, y, z) black_coeff, _ = self.get_lighting_coefficient(x, y, z)
img.paste(Image.blend(t[0], black_color, black_coeff), (imgx, imgy), t[1]) composite.alpha_over(img, Image.blend(t[0], black_color, black_coeff), (imgx, imgy), t[1])
else: else:
# draw each face lit appropriately, # draw each face lit appropriately,
# but first just draw the block # but first just draw the block
img.paste(t[0], (imgx, imgy), t[1]) composite.alpha_over(img, t[0], (imgx, imgy), t[1])
# top face # top face
black_coeff, face_occlude = self.get_lighting_coefficient(x, y, z + 1) black_coeff, face_occlude = self.get_lighting_coefficient(x, y, z + 1)
if not face_occlude: if not face_occlude:
img.paste((0,0,0), (imgx, imgy), ImageEnhance.Brightness(facemasks[0]).enhance(black_coeff)) composite.alpha_over(img, black_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[0]).enhance(black_coeff))
# left face # left face
black_coeff, face_occlude = self.get_lighting_coefficient(x - 1, y, z) black_coeff, face_occlude = self.get_lighting_coefficient(x - 1, y, z)
if not face_occlude: if not face_occlude:
img.paste((0,0,0), (imgx, imgy), ImageEnhance.Brightness(facemasks[1]).enhance(black_coeff)) composite.alpha_over(img, black_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[1]).enhance(black_coeff))
# right face # right face
black_coeff, face_occlude = self.get_lighting_coefficient(x, y + 1, z) black_coeff, face_occlude = self.get_lighting_coefficient(x, y + 1, z)
if not face_occlude: if not face_occlude:
img.paste((0,0,0), (imgx, imgy), ImageEnhance.Brightness(facemasks[2]).enhance(black_coeff)) composite.alpha_over(img, black_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[2]).enhance(black_coeff))
# Draw edge lines # Draw edge lines
if blockid in (44,): # step block if blockid in (44,): # step block
@@ -616,6 +621,8 @@ def generate_facemasks():
toppart = textures.transform_image(white) toppart = textures.transform_image(white)
leftpart = textures.transform_image_side(white) leftpart = textures.transform_image_side(white)
# using the real PIL paste here (not alpha_over) because there is
# no alpha channel (and it's mode "L")
top.paste(toppart, (0,0)) top.paste(toppart, (0,0))
left.paste(leftpart, (0,6)) left.paste(leftpart, (0,6))
right = left.transpose(Image.FLIP_LEFT_RIGHT) right = left.transpose(Image.FLIP_LEFT_RIGHT)

51
composite.py Normal file
View File

@@ -0,0 +1,51 @@
# 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/>.
import logging
from PIL import Image
"""
This module has an alpha-over function that is used throughout
Overviewer. It defaults to the PIL paste function when the custom
alpha-over extension cannot be found.
"""
extension_alpha_over = None
try:
from _composite import alpha_over as _extension_alpha_over
extension_alpha_over = _extension_alpha_over
except ImportError:
logging.warning("alpha_over extension not found; using default PIL paste()")
def alpha_over(dest, src, pos_or_rect=(0, 0), mask=None):
"""Composite src over dest, using mask as the alpha channel (if
given), otherwise using src's alpha channel. pos_or_rect can
either be a position or a rectangle, specifying where on dest to
put src. Falls back to dest.paste() if the alpha_over extension
can't be found."""
if mask == None:
mask = src
global extension_alpha_over
if extension_alpha_over != None:
# extension ALWAYS expects rects, so convert if needed
if len(pos_or_rect) == 2:
pos_or_rect = (pos_or_rect[0], pos_or_rect[1], src.size[0], src.size[1])
extension_alpha_over(dest, src, pos_or_rect, mask)
else:
# fallback
dest.paste(src, pos_or_rect, mask)

View File

@@ -29,6 +29,7 @@ import util
from PIL import Image from PIL import Image
from optimizeimages import optimize_image from optimizeimages import optimize_image
import composite
""" """
@@ -449,7 +450,10 @@ def render_innertile(dest, name, imgformat, optimizeimg):
# Create the actual image now # Create the actual image now
img = Image.new("RGBA", (384, 384), (38,92,255,0)) img = Image.new("RGBA", (384, 384), (38,92,255,0))
# we'll use paste (NOT alpha_over) for quadtree generation because
# this is just straight image stitching, not alpha blending
if q0path: if q0path:
try: try:
quad0 = Image.open(q0path).resize((192,192), Image.ANTIALIAS) quad0 = Image.open(q0path).resize((192,192), Image.ANTIALIAS)
@@ -613,7 +617,7 @@ def render_worldtile(chunks, colstart, colend, rowstart, rowend, path, imgformat
xpos = -192 + (col-colstart)*192 xpos = -192 + (col-colstart)*192
ypos = -96 + (row-rowstart)*96 ypos = -96 + (row-rowstart)*96
tileimg.paste(chunkimg.convert("RGB"), (xpos, ypos), chunkimg) composite.alpha_over(tileimg, chunkimg.convert("RGB"), (xpos, ypos), chunkimg)
# Save them # Save them
tileimg.save(imgpath) tileimg.save(imgpath)

View File

@@ -1,13 +1,68 @@
from distutils.core import setup from distutils.core import setup, Extension
import py2exe from distutils.command.build import build
from distutils.command.clean import clean
from distutils.dir_util import remove_tree
from distutils import log
import os, os.path
setup(console=['gmap.py'], try:
data_files=[('textures', ['textures/lava.png', 'textures/water.png']), import py2exe
('', ['template.html'])], except ImportError:
zipfile = None, py2exe = None
options = {'py2exe': {
'bundle_files': 1, # now, setup the keyword arguments for setup
}}, # (because we don't know until runtime if py2exe is available)
setup_kwargs = {}
setup_kwargs['options'] = {}
setup_kwargs['ext_modules'] = []
setup_kwargs['cmdclass'] = {}
#
# py2exe options
#
if py2exe != None:
setup_kwargs['console'] = ['gmap.py']
setup_kwargs['data_files'] = [('textures', ['textures/lava.png', 'textures/water.png']),
('', ['template.html'])]
setup_kwargs['zipfile'] = None
setup_kwargs['options']['py2exe'] = {'bundle_files' : 1}
#
# _composite.c extension
#
setup_kwargs['ext_modules'].append(Extension('_composite', ['_composite.c']))
# tell build_ext to build the extension in-place
# (NOT in build/)
setup_kwargs['options']['build_ext'] = {'inplace' : 1}
# tell the build command to only run build_ext
build.sub_commands = [('build_ext', None)]
# custom clean command to remove in-place extension
class CustomClean(clean):
def run(self):
# do the normal cleanup
clean.run(self)
# try to remove '_composite.{so,pyd,...}' extension,
) # regardless of the current system's extension name convention
build_ext = self.get_finalized_command('build_ext')
fname = build_ext.get_ext_fullpath('_composite')
pretty_fname = os.path.split(fname)[1]
if os.path.exists(fname):
try:
if not self.dry_run:
os.remove(fname)
log.info("removing '%s'", pretty_fname)
except OSError:
log.warn("'%s' could not be cleaned -- permission denied",
pretty_fname)
else:
log.debug("'%s' does not exist -- can't clean it",
pretty_fname)
setup_kwargs['cmdclass']['clean'] = CustomClean
###
setup(**setup_kwargs)

View File

@@ -24,6 +24,7 @@ import numpy
from PIL import Image, ImageEnhance from PIL import Image, ImageEnhance
import util import util
import composite
def _find_file(filename, mode="rb"): def _find_file(filename, mode="rb"):
"""Searches for the given file and returns an open handle to it. """Searches for the given file and returns an open handle to it.
@@ -157,13 +158,13 @@ def transform_image_side(img, blockID=None):
# img to be unchanged # img to be unchanged
mask = img.crop((0,8,16,16)) mask = img.crop((0,8,16,16))
n = Image.new(img.mode, img.size, (38,92,255,0)) n = Image.new(img.mode, img.size, (38,92,255,0))
n.paste(mask,(0,0,16,8), mask) composite.alpha_over(n, mask,(0,0,16,8), mask)
img = n img = n
if blockID in (78,): # snow if blockID in (78,): # snow
# make the top three quarters transparent # make the top three quarters transparent
mask = img.crop((0,12,16,16)) mask = img.crop((0,12,16,16))
n = Image.new(img.mode, img.size, (38,92,255,0)) n = Image.new(img.mode, img.size, (38,92,255,0))
n.paste(mask,(0,12,16,16), mask) composite.alpha_over(n, mask,(0,12,16,16), mask)
img = n img = n
# Size of the cube side before shear # Size of the cube side before shear
@@ -189,7 +190,7 @@ def _build_block(top, side, blockID=None):
top = transform_image(top, blockID) top = transform_image(top, blockID)
if not side: if not side:
img.paste(top, (0,0), top) composite.alpha_over(img, top, (0,0), top)
return img return img
side = transform_image_side(side, blockID) side = transform_image_side(side, blockID)
@@ -212,29 +213,29 @@ def _build_block(top, side, blockID=None):
if blockID in (37,38,6,39,40,50,83): ## flowers, sapling, mushrooms, regular torch, reeds if blockID in (37,38,6,39,40,50,83): ## flowers, sapling, mushrooms, regular torch, reeds
# instead of pasting these blocks at the cube edges, place them in the middle: # instead of pasting these blocks at the cube edges, place them in the middle:
# and omit the top # and omit the top
img.paste(side, (6,3), side) composite.alpha_over(img, side, (6,3), side)
img.paste(otherside, (6,3), otherside) composite.alpha_over(img, otherside, (6,3), otherside)
return img return img
if blockID in (81,): # cacti! if blockID in (81,): # cacti!
img.paste(side, (2,6), side) composite.alpha_over(img, side, (2,6), side)
img.paste(otherside, (10,6), otherside) composite.alpha_over(img, otherside, (10,6), otherside)
img.paste(top, (0,2), top) composite.alpha_over(img, top, (0,2), top)
elif blockID in (44,): # half step elif blockID in (44,): # half step
# shift each texture down 6 pixels # shift each texture down 6 pixels
img.paste(side, (0,12), side) composite.alpha_over(img, side, (0,12), side)
img.paste(otherside, (12,12), otherside) composite.alpha_over(img, otherside, (12,12), otherside)
img.paste(top, (0,6), top) composite.alpha_over(img, top, (0,6), top)
elif blockID in (78,): # snow elif blockID in (78,): # snow
# shift each texture down 9 pixels # shift each texture down 9 pixels
img.paste(side, (0,6), side) composite.alpha_over(img, side, (0,6), side)
img.paste(otherside, (12,6), otherside) composite.alpha_over(img, otherside, (12,6), otherside)
img.paste(top, (0,9), top) composite.alpha_over(img, top, (0,9), top)
else: else:
img.paste(side, (0,6), side) composite.alpha_over(img, side, (0,6), side)
img.paste(otherside, (12,6), otherside) composite.alpha_over(img, otherside, (12,6), otherside)
img.paste(top, (0,0), top) composite.alpha_over(img, top, (0,0), top)
# Manually touch up 6 pixels that leave a gap because of how the # Manually touch up 6 pixels that leave a gap because of how the
# shearing works out. This makes the blocks perfectly tessellate-able # shearing works out. This makes the blocks perfectly tessellate-able
@@ -366,7 +367,7 @@ def generate_special_texture(blockID, data):
track = transform_image(raw_straight, blockID) track = transform_image(raw_straight, blockID)
img = Image.new("RGBA", (24,24), (38,92,255,0)) img = Image.new("RGBA", (24,24), (38,92,255,0))
img.paste(track, (0,12), track) composite.alpha_over(img, track, (0,12), track)
return (img.convert("RGB"), img.split()[3]) return (img.convert("RGB"), img.split()[3])
if blockID == 59: # crops if blockID == 59: # crops
@@ -376,9 +377,9 @@ def generate_special_texture(blockID, data):
crop3 = crop2.transpose(Image.FLIP_LEFT_RIGHT) crop3 = crop2.transpose(Image.FLIP_LEFT_RIGHT)
img = Image.new("RGBA", (24,24), (38,92,255,0)) img = Image.new("RGBA", (24,24), (38,92,255,0))
img.paste(crop1, (0,12), crop1) composite.alpha_over(img, crop1, (0,12), crop1)
img.paste(crop2, (6,3), crop2) composite.alpha_over(img, crop2, (6,3), crop2)
img.paste(crop3, (6,3), crop3) composite.alpha_over(img, crop3, (6,3), crop3)
return (img.convert("RGB"), img.split()[3]) return (img.convert("RGB"), img.split()[3])
if blockID == 61: #furnace if blockID == 61: #furnace
@@ -388,9 +389,9 @@ def generate_special_texture(blockID, data):
img = Image.new("RGBA", (24,24), (38,92,255,0)) img = Image.new("RGBA", (24,24), (38,92,255,0))
img.paste(side1, (0,6), side1) composite.alpha_over(img, side1, (0,6), side1)
img.paste(side2, (12,6), side2) composite.alpha_over(img, side2, (12,6), side2)
img.paste(top, (0,0), top) composite.alpha_over(img, top, (0,0), top)
return (img.convert("RGB"), img.split()[3]) return (img.convert("RGB"), img.split()[3])
if blockID == 62: # lit furnace if blockID == 62: # lit furnace
@@ -400,9 +401,9 @@ def generate_special_texture(blockID, data):
img = Image.new("RGBA", (24,24), (38,92,255,0)) img = Image.new("RGBA", (24,24), (38,92,255,0))
img.paste(side1, (0,6), side1) composite.alpha_over(img, side1, (0,6), side1)
img.paste(side2, (12,6), side2) composite.alpha_over(img, side2, (12,6), side2)
img.paste(top, (0,0), top) composite.alpha_over(img, top, (0,0), top)
return (img.convert("RGB"), img.split()[3]) return (img.convert("RGB"), img.split()[3])
if blockID == 65: # ladder if blockID == 65: # ladder
@@ -414,22 +415,22 @@ def generate_special_texture(blockID, data):
# have to render this thing anyway. same for data == 2 # have to render this thing anyway. same for data == 2
tex = transform_image_side(raw_texture) tex = transform_image_side(raw_texture)
img = Image.new("RGBA", (24,24), (38,92,255,0)) img = Image.new("RGBA", (24,24), (38,92,255,0))
img.paste(tex, (0,6), tex) composite.alpha_over(img, tex, (0,6), tex)
return (img.convert("RGB"), img.split()[3]) return (img.convert("RGB"), img.split()[3])
if data == 2: if data == 2:
tex = transform_image_side(raw_texture).transpose(Image.FLIP_LEFT_RIGHT) tex = transform_image_side(raw_texture).transpose(Image.FLIP_LEFT_RIGHT)
img = Image.new("RGBA", (24,24), (38,92,255,0)) img = Image.new("RGBA", (24,24), (38,92,255,0))
img.paste(tex, (12,6), tex) composite.alpha_over(img, tex, (12,6), tex)
return (img.convert("RGB"), img.split()[3]) return (img.convert("RGB"), img.split()[3])
if data == 3: if data == 3:
tex = transform_image_side(raw_texture).transpose(Image.FLIP_LEFT_RIGHT) tex = transform_image_side(raw_texture).transpose(Image.FLIP_LEFT_RIGHT)
img = Image.new("RGBA", (24,24), (38,92,255,0)) img = Image.new("RGBA", (24,24), (38,92,255,0))
img.paste(tex, (0,0), tex) composite.alpha_over(img, tex, (0,0), tex)
return (img.convert("RGB"), img.split()[3]) return (img.convert("RGB"), img.split()[3])
if data == 4: if data == 4:
tex = transform_image_side(raw_texture) tex = transform_image_side(raw_texture)
img = Image.new("RGBA", (24,24), (38,92,255,0)) img = Image.new("RGBA", (24,24), (38,92,255,0))
img.paste(tex, (12,0), tex) composite.alpha_over(img, tex, (12,0), tex)
return (img.convert("RGB"), img.split()[3]) return (img.convert("RGB"), img.split()[3])
if blockID in (64,71): #wooden door, or iron door if blockID in (64,71): #wooden door, or iron door
@@ -450,36 +451,36 @@ def generate_special_texture(blockID, data):
if (data & 0x03) == 0: if (data & 0x03) == 0:
if not swung: if not swung:
tex = transform_image_side(raw_door) tex = transform_image_side(raw_door)
img.paste(tex, (0,6), tex) composite.alpha_over(img, tex, (0,6), tex)
else: else:
# flip first to set the doornob on the correct side # flip first to set the doornob on the correct side
tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)) tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT))
tex = tex.transpose(Image.FLIP_LEFT_RIGHT) tex = tex.transpose(Image.FLIP_LEFT_RIGHT)
img.paste(tex, (0,0), tex) composite.alpha_over(img, tex, (0,0), tex)
if (data & 0x03) == 1: if (data & 0x03) == 1:
if not swung: if not swung:
tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT) tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT)
img.paste(tex, (0,0), tex) composite.alpha_over(img, tex, (0,0), tex)
else: else:
tex = transform_image_side(raw_door) tex = transform_image_side(raw_door)
img.paste(tex, (12,0), tex) composite.alpha_over(img, tex, (12,0), tex)
if (data & 0x03) == 2: if (data & 0x03) == 2:
if not swung: if not swung:
tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)) tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT))
img.paste(tex, (12,0), tex) composite.alpha_over(img, tex, (12,0), tex)
else: else:
tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT) tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT)
img.paste(tex, (12,6), tex) composite.alpha_over(img, tex, (12,6), tex)
if (data & 0x03) == 3: if (data & 0x03) == 3:
if not swung: if not swung:
tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)).transpose(Image.FLIP_LEFT_RIGHT) tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)).transpose(Image.FLIP_LEFT_RIGHT)
img.paste(tex, (12,6), tex) composite.alpha_over(img, tex, (12,6), tex)
else: else:
tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)) tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT))
img.paste(tex, (0,6), tex) composite.alpha_over(img, tex, (0,6), tex)
return (img.convert("RGB"), img.split()[3]) return (img.convert("RGB"), img.split()[3])