0

Merge branch 'dtt-c-render' into py-package

Conflicts:
	overviewer.py
This commit is contained in:
Aaron Griffith
2011-04-01 21:59:52 -04:00
8 changed files with 539 additions and 405 deletions

View File

@@ -131,6 +131,7 @@ try:
print "... done"
stats = get_stats(timelist)
print stats
if log:
log.write("%s %s\n" % (commit, repr(stats)))
except CalledProcessError, e:
if options.fatal_errors:

View File

@@ -27,22 +27,51 @@ import subprocess
import multiprocessing
import time
import logging
import platform
from overviewer_core import util
logging.basicConfig(level=logging.INFO,format="%(asctime)s [%(levelname)s] %(message)s")
this_dir = util.get_program_path()
# make sure the c_overviewer extension is available
try:
from overviewer_core import c_overviewer
except ImportError:
## try to find the build extension
ext = os.path.join(this_dir, "c_overviewer.%s" % ("pyd" if platform.system() == "Windows" else "so"))
if os.path.exists(ext):
print "Something has gone wrong importing the c_overviewer extension. Please"
print "make sure it is up-to-date (clean and rebuild)"
sys.exit(1)
print "You need to compile the c_overviewer module to run Minecraft Overviewer."
print "Run `python setup.py build`, or see the README for details."
import traceback
traceback.print_exc()
sys.exit(1)
if hasattr(sys, "frozen"):
pass # we don't bother with a compat test since it should always be in sync
elif "extension_version" in dir(c_overviewer):
# check to make sure the binary matches the headers
if os.path.exists(os.path.join(this_dir, "src", "overviewer.h")):
with open(os.path.join(this_dir, "src", "overviewer.h")) as f:
lines = f.readlines()
lines = filter(lambda x: x.startswith("#define OVERVIEWER_EXTENSION_VERSION"), lines)
if lines:
l = lines[0]
if int(l.split()[2].strip()) != c_overviewer.extension_version():
print "Please rebuild your c_overviewer module. It is out of date!"
sys.exit(1)
else:
print "Please rebuild your c_overviewer module. It is out of date!"
sys.exit(1)
from overviewer_core.configParser import ConfigOptionParser
from overviewer_core import optimizeimages, world, quadtree
from overviewer_core import googlemap, rendernode, util
from overviewer_core import googlemap, rendernode
helptext = """
@@ -99,7 +128,7 @@ def main():
sys.exit(0)
if len(args) < 1:
print "You need to give me your world number or directory"
logging.error("You need to give me your world number or directory")
parser.print_help()
list_worlds()
sys.exit(1)
@@ -112,7 +141,7 @@ def main():
# if there are no worlds found at all, exit now
if not worlds:
parser.print_help()
print "\nInvalid world path"
logging.error("Invalid world path")
sys.exit(1)
try:
@@ -125,12 +154,12 @@ def main():
except KeyError:
# it's not a number, name, or path
parser.print_help()
print "Invalid world name or path"
logging.error("Invalid world name or path")
sys.exit(1)
except KeyError:
# it was an invalid number
parser.print_help()
print "Invalid world number"
logging.error("Invalid world number")
sys.exit(1)
if len(args) != 2:
@@ -183,6 +212,8 @@ def main():
w = world.World(worlddir, useBiomeData=useBiomeData)
w.go(options.procs)
logging.info("Rending the following tilesets: %s", ",".join(options.rendermode))
# create the quadtrees
# TODO chunklist
q = []

View File

@@ -1,6 +1,7 @@
from optparse import OptionParser
import sys
import os.path
import logging
class OptionsResults(object):
pass
@@ -22,10 +23,12 @@ class ConfigOptionParser(object):
self.requiredArgs = []
def display_config(self):
logging.info("Using the following settings:")
for x in self.configVars:
n = x['dest']
print "%s: %r" % (n, self.configResults.__dict__[n])
def add_option(self, *args, **kwargs):
if kwargs.get("configFileOnly", False) and kwargs.get("commandLineOnly", False):
@@ -71,14 +74,14 @@ class ConfigOptionParser(object):
except NameError, ex:
import traceback
traceback.print_exc()
print "\nError parsing %s. Please check the trackback above" % self.configFile
logging.error("Error parsing %s. Please check the trackback above" % self.configFile)
sys.exit(1)
except SyntaxError, ex:
import traceback
traceback.print_exc()
tb = sys.exc_info()[2]
#print tb.tb_frame.f_code.co_filename
print "\nError parsing %s. Please check the trackback above" % self.configFile
logging.error("Error parsing %s. Please check the trackback above" % self.configFile)
sys.exit(1)
#print l.keys()
@@ -89,7 +92,7 @@ class ConfigOptionParser(object):
n = a['dest']
if a.get('commandLineOnly', False):
if n in l.keys():
print "Error: %s can only be specified on the command line. It is not valid in the config file" % n
logging.error("Error: %s can only be specified on the command line. It is not valid in the config file" % n)
sys.exit(1)
configResults.__dict__[n] = l.get(n)
@@ -113,7 +116,8 @@ class ConfigOptionParser(object):
for a in self.configVars:
n = a['dest']
if configResults.__dict__[n] == None and a.get('required',False):
raise Exception("%s is required" % n)
logging.error("%s is required" % n)
sys.exit(1)
# sixth, check types
for a in self.configVars:
@@ -128,7 +132,7 @@ class ConfigOptionParser(object):
try:
configResults.__dict__[n] = self.checkType(configResults.__dict__[n], a)
except ValueError, ex:
print "There was a problem converting the value '%s' to type %s for config parameter '%s'" % (configResults.__dict__[n], a['type'], n)
logging.error("There was a problem converting the value '%s' to type %s for config parameter '%s'" % (configResults.__dict__[n], a['type'], n))
import traceback
#traceback.print_exc()
sys.exit(1)
@@ -153,7 +157,7 @@ class ConfigOptionParser(object):
return long(value)
elif a['type'] == "choice":
if value not in a['choices']:
print "The value '%s' is not valid for config parameter '%s'" % (value, a['dest'])
logging.error("The value '%s' is not valid for config parameter '%s'" % (value, a['dest']))
sys.exit(1)
return value
elif a['type'] == "float":
@@ -164,5 +168,5 @@ class ConfigOptionParser(object):
if not callable(value):
raise ValueError("Not callable")
else:
print "Unknown type!"
logging.error("Unknown type!")
sys.exit(1)

View File

@@ -222,6 +222,10 @@ class QuadtreeGen(object):
unconvert_coords = self.world.unconvert_coords
#get_region_path = self.world.get_region_path
get_region = self.world.regionfiles.get
regionx = None
regiony = None
c = None
mcr = None
for row in xrange(rowstart-16, rowend+1):
for col in xrange(colstart, colend+1):
# due to how chunks are arranged, we can only allow
@@ -230,12 +234,18 @@ class QuadtreeGen(object):
if row % 2 != col % 2:
continue
# return (col, row, chunkx, chunky, regionpath)
chunkx, chunky = unconvert_coords(col, row)
#c = get_region_path(chunkx, chunky)
_, _, c, mcr = get_region((chunkx//32, chunky//32),(None,None,None,None));
regionx_ = chunkx//32
regiony_ = chunky//32
if regionx_ != regionx or regiony_ != regiony:
regionx = regionx_
regiony = regiony_
_, _, c, mcr = get_region((regionx, regiony),(None,None,None,None))
if c is not None and mcr.chunkExists(chunkx,chunky):
chunklist.append((col, row, chunkx, chunky, c))
return chunklist
def get_worldtiles(self):

View File

@@ -17,6 +17,11 @@
#include "overviewer.h"
PyObject *get_extension_version(PyObject *self, PyObject *args) {
return Py_BuildValue("i", OVERVIEWER_EXTENSION_VERSION);
}
static PyMethodDef COverviewerMethods[] = {
{"alpha_over", alpha_over_wrap, METH_VARARGS,
"alpha over composite function"},
@@ -26,9 +31,12 @@ static PyMethodDef COverviewerMethods[] = {
"returns available render modes"},
{"get_render_mode_info", get_render_mode_info, METH_VARARGS,
"returns info for a particular render mode"},
{"extension_version", get_extension_version, METH_VARARGS,
"Returns the extension version"},
{NULL, NULL, 0, NULL} /* Sentinel */
};
PyMODINIT_FUNC
initc_overviewer(void)
{

View File

@@ -24,6 +24,10 @@
#ifndef __OVERVIEWER_H_INCLUDED__
#define __OVERVIEWER_H_INCLUDED__
// increment this value if you've made a change to the c extesion
// and want to force users to rebuild
#define OVERVIEWER_EXTENSION_VERSION 2
/* Python PIL, and numpy headers */
#include <Python.h>
#include <Imaging.h>

View File

@@ -285,7 +285,7 @@ def _build_full_block(top, side1, side2, side3, side4, bottom=None, blockID=None
# first back sides
if side1 != None :
side1 = transform_image_side(side1, blockID)
side1 = side1.transpose(Image.FLIP_TOP_BOTTOM)
side1 = side1.transpose(Image.FLIP_LEFT_RIGHT)
# Darken this side.
sidealpha = side1.split()[3]
@@ -297,8 +297,6 @@ def _build_full_block(top, side1, side2, side3, side4, bottom=None, blockID=None
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]
@@ -356,9 +354,9 @@ def _build_blockimages():
# 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
-1, -1, -1, -1, -1, 13, 12, 29, 28, 23, 22, -1, -1, 7, 8, 35, # Gold/iron blocks? Doublestep? TNT from above?
# 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
36, 37, 80, -1, 65, 4, 25, -1, 98, 24, -1, -1, 86, -1, -1, -1, # Torch from above? leaving out fire. Redstone wire? Crops/furnaces handled elsewhere. sign post
36, 37, -1, -1, 65, 4, 25, -1, 98, 24, -1, -1, 86, -1, -1, -1, # Torch from above? leaving out fire. Redstone wire? Crops/furnaces handled elsewhere. sign post
# 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
-1, -1, -1, 16, -1, -1, -1, -1, -1, 51, 51,115, 99, -1, 66, 67, # door,ladder left out. Minecart rail orientation, redstone torches
-1, -1, -1, 16, -1, -1, -1, -1, -1, 51, 51, -1, -1, -1, 66, 67, # door,ladder left out. Minecart rail orientation, redstone torches
# 80 81 82 83 84 85 86 87 88 89 90 91
66, 69, 72, 73, 74, -1,102,103,104,105,-1, 102 # clay?
]
@@ -373,9 +371,9 @@ def _build_blockimages():
# 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
-1, -1, -1, -1, -1, 13, 12, 29, 28, 23, 22, -1, -1, 7, 8, 35,
# 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
36, 37, 80, -1, 65, 4, 25,101, 98, 24, -1, -1, 86, -1, -1, -1,
36, 37, -1, -1, 65, 4, 25,101, 98, 24, -1, -1, 86, -1, -1, -1,
# 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
-1, -1, -1, 16, -1, -1, -1, -1, -1, 51, 51,115, 99, -1, 66, 67,
-1, -1, -1, 16, -1, -1, -1, -1, -1, 51, 51, -1, -1, -1, 66, 67,
# 80 81 82 83 84 85 86 87 88 89 90 91
66, 69, 72, 73, 74,-1 ,118,103,104,105, -1, 118
]
@@ -431,241 +429,44 @@ load_water()
def generate_special_texture(blockID, data):
"""Generates a special texture, such as a correctly facing minecraft track"""
#print "%s has ancillary data: %X" %(blockID, data)
# TODO torches, redstone torches, crops, ladders, stairs,
# levers, doors, buttons, and signs all need to be handled here (and in chunkpy)
if blockID == 66: # minetrack:
raw_straight = terrain_images[128]
raw_corner = terrain_images[112]
## use transform_image to scale and shear
if data == 0:
track = transform_image(raw_straight, blockID)
elif data == 6:
track = transform_image(raw_corner, blockID)
elif data == 7:
track = transform_image(raw_corner.rotate(270), blockID)
elif data == 8:
# flip
track = transform_image(raw_corner.transpose(Image.FLIP_TOP_BOTTOM).rotate(90),
blockID)
elif data == 9:
track = transform_image(raw_corner.transpose(Image.FLIP_TOP_BOTTOM),
blockID)
elif data == 1:
track = transform_image(raw_straight.rotate(90), blockID)
#slopes
elif data == 2: # slope going up in +x direction
track = transform_image_slope(raw_straight,blockID)
track = track.transpose(Image.FLIP_LEFT_RIGHT)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, track, (2,0), track)
# the 2 pixels move is needed to fit with the adjacent tracks
return (img.convert("RGB"), img.split()[3])
elif data == 3: # slope going up in -x direction
# tracks are sprites, in this case we are seeing the "side" of
# the sprite, so draw a line to make it beautiful.
img = Image.new("RGBA", (24,24), (38,92,255,0))
ImageDraw.Draw(img).line([(11,11),(23,17)],fill=(164,164,164))
# grey from track texture (exterior grey).
# the track doesn't start from image corners, be carefull drawing the line!
return (img.convert("RGB"), img.split()[3])
elif data == 4: # slope going up in -y direction
track = transform_image_slope(raw_straight,blockID)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, track, (0,0), track)
return (img.convert("RGB"), img.split()[3])
elif data == 5: # slope going up in +y direction
# same as "data == 3"
img = Image.new("RGBA", (24,24), (38,92,255,0))
ImageDraw.Draw(img).line([(1,17),(12,11)],fill=(164,164,164))
return (img.convert("RGB"), img.split()[3])
else: # just in case
track = transform_image(raw_straight, blockID)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, track, (0,12), track)
return (img.convert("RGB"), img.split()[3])
if blockID == 58: # crafting table
top = terrain_images[43]
side3 = terrain_images[43+16]
side4 = terrain_images[43+16+1]
img = _build_full_block(top, None, None, side3, side4, None, 58)
return (img.convert("RGB"), img.split()[3])
if blockID == 59: # crops
raw_crop = terrain_images[88+data]
crop1 = transform_image(raw_crop, blockID)
crop2 = transform_image_side(raw_crop, blockID)
crop3 = crop2.transpose(Image.FLIP_LEFT_RIGHT)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, crop1, (0,12), crop1)
composite.alpha_over(img, crop2, (6,3), crop2)
composite.alpha_over(img, crop3, (6,3), crop3)
return (img.convert("RGB"), img.split()[3])
if blockID == 61: #furnace
top = transform_image(terrain_images[62])
side1 = transform_image_side(terrain_images[45])
side2 = transform_image_side(terrain_images[44]).transpose(Image.FLIP_LEFT_RIGHT)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, side1, (0,6), side1)
composite.alpha_over(img, side2, (12,6), side2)
composite.alpha_over(img, top, (0,0), top)
return (img.convert("RGB"), img.split()[3])
if blockID in (86,91): # jack-o-lantern
top = transform_image(terrain_images[102])
frontID = 119 if blockID == 86 else 120
side1 = transform_image_side(terrain_images[frontID])
side2 = transform_image_side(terrain_images[118]).transpose(Image.FLIP_LEFT_RIGHT)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, side1, (0,6), side1)
composite.alpha_over(img, side2, (12,6), side2)
composite.alpha_over(img, top, (0,0), top)
return (img.convert("RGB"), img.split()[3])
if blockID == 62: # lit furnace
top = transform_image(terrain_images[62])
side1 = transform_image_side(terrain_images[45])
side2 = transform_image_side(terrain_images[45+16]).transpose(Image.FLIP_LEFT_RIGHT)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, side1, (0,6), side1)
composite.alpha_over(img, side2, (12,6), side2)
composite.alpha_over(img, top, (0,0), top)
return (img.convert("RGB"), img.split()[3])
if blockID == 23: # dispenser
top = transform_image(terrain_images[62])
side1 = transform_image_side(terrain_images[46])
side2 = transform_image_side(terrain_images[45]).transpose(Image.FLIP_LEFT_RIGHT)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, side1, (0,6), side1)
composite.alpha_over(img, side2, (12,6), side2)
composite.alpha_over(img, top, (0,0), top)
return (img.convert("RGB"), img.split()[3])
if blockID == 65: # ladder
raw_texture = terrain_images[83]
#print "ladder is facing: %d" % data
if data == 5:
# normally this ladder would be obsured by the block it's attached to
# but since ladders can apparently be placed on transparent blocks, we
# have to render this thing anyway. same for data == 2
tex = transform_image_side(raw_texture)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, tex, (0,6), tex)
return (img.convert("RGB"), img.split()[3])
if data == 2:
tex = transform_image_side(raw_texture).transpose(Image.FLIP_LEFT_RIGHT)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, tex, (12,6), tex)
return (img.convert("RGB"), img.split()[3])
if data == 3:
tex = transform_image_side(raw_texture).transpose(Image.FLIP_LEFT_RIGHT)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, tex, (0,0), tex)
return (img.convert("RGB"), img.split()[3])
if data == 4:
tex = transform_image_side(raw_texture)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, tex, (12,0), tex)
return (img.convert("RGB"), img.split()[3])
if blockID in (64,71): #wooden door, or iron door
if data & 0x8 == 0x8: # top of the door
raw_door = terrain_images[81 if blockID == 64 else 82]
else: # bottom of the door
raw_door = terrain_images[97 if blockID == 64 else 98]
# if you want to render all doors as closed, then force
# force swung to be False
if data & 0x4 == 0x4:
swung=True
else:
swung=False
# mask out the high bits to figure out the orientation
img = Image.new("RGBA", (24,24), (38,92,255,0))
if (data & 0x03) == 0:
if not swung:
tex = transform_image_side(raw_door)
composite.alpha_over(img, tex, (0,6), tex)
else:
# flip first to set the doornob on the correct side
tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT))
tex = tex.transpose(Image.FLIP_LEFT_RIGHT)
composite.alpha_over(img, tex, (0,0), tex)
if (data & 0x03) == 1:
if not swung:
tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT)
composite.alpha_over(img, tex, (0,0), tex)
else:
tex = transform_image_side(raw_door)
composite.alpha_over(img, tex, (12,0), tex)
if (data & 0x03) == 2:
if not swung:
tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT))
composite.alpha_over(img, tex, (12,0), tex)
else:
tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT)
composite.alpha_over(img, tex, (12,6), tex)
if (data & 0x03) == 3:
if not swung:
tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)).transpose(Image.FLIP_LEFT_RIGHT)
composite.alpha_over(img, tex, (12,6), tex)
else:
tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT))
composite.alpha_over(img, tex, (0,6), tex)
return (img.convert("RGB"), img.split()[3])
# TODO ladders, stairs, levers, buttons, and signs
# all need to behandled here (and in chunkpy)
if blockID == 2: # grass
top = tintTexture(terrain_images[0],(115,175,71))
img = _build_block(top, terrain_images[3], 2)
return (img.convert("RGB"), img.split()[3])
if blockID == 51: # fire
firetexture = _load_image("fire.png")
side1 = transform_image_side(firetexture)
side2 = transform_image_side(firetexture).transpose(Image.FLIP_LEFT_RIGHT)
img = Image.new("RGBA", (24,24), (38,92,255,0))
if blockID == 9: # spring water, flowing water and waterfall water
composite.alpha_over(img, side1, (12,0), side1)
composite.alpha_over(img, side2, (0,0), side2)
watertexture = _load_image("water.png")
composite.alpha_over(img, side1, (0,6), side1)
composite.alpha_over(img, side2, (12,6), side2)
if (data & 0b10000) == 16:
top = watertexture
return (img.convert("RGB"), img.split()[3])
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 == 18: # leaves
t = tintTexture(terrain_images[52], (37, 118, 25))
img = _build_block(t, t, 18)
return (img.convert("RGB"), img.split()[3])
if blockID == 17: # wood: normal, birch and pines
top = terrain_images[21]
@@ -682,6 +483,25 @@ def generate_special_texture(blockID, data):
img = _build_block(top, side, 17)
return (img.convert("RGB"), img.split()[3])
if blockID == 18: # leaves
t = tintTexture(terrain_images[52], (37, 118, 25))
img = _build_block(t, t, 18)
return (img.convert("RGB"), img.split()[3])
if blockID == 23: # dispenser
top = transform_image(terrain_images[62])
side1 = transform_image_side(terrain_images[46])
side2 = transform_image_side(terrain_images[45]).transpose(Image.FLIP_LEFT_RIGHT)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, side1, (0,6), side1)
composite.alpha_over(img, side2, (12,6), side2)
composite.alpha_over(img, top, (0,0), top)
return (img.convert("RGB"), img.split()[3])
if blockID == 35: # wool
if data == 0: # white
top = side = terrain_images[64]
@@ -749,6 +569,369 @@ def generate_special_texture(blockID, data):
return (img.convert("RGB"), img.split()[3])
if blockID in (43,44): # slab and double-slab
if data == 0: # stone slab
top = terrain_images[6]
side = terrain_images[5]
img = _build_block(top, side, blockID)
return (img.convert("RGB"), img.split()[3])
if data == 1: # stone slab
top = terrain_images[176]
side = terrain_images[192]
img = _build_block(top, side, blockID)
return (img.convert("RGB"), img.split()[3])
if data == 2: # wooden slab
top = side = terrain_images[4]
img = _build_block(top, side, blockID)
return (img.convert("RGB"), img.split()[3])
if data == 3: # cobblestone slab
top = side = terrain_images[16]
img = _build_block(top, side, blockID)
return (img.convert("RGB"), img.split()[3])
if blockID in (50,75,76): # torch, off redstone torch, on redstone torch
# choose the proper texture
if blockID == 50: # torch
small = terrain_images[80]
elif blockID == 75: # off redstone torch
small = terrain_images[115]
else: # on redstone torch
small = terrain_images[99]
# compose a torch bigger than the normal
# (better for doing transformations)
torch = Image.new("RGBA", (16,16), (38,92,255,0))
composite.alpha_over(torch,small,(-4,-3))
composite.alpha_over(torch,small,(-5,-2))
composite.alpha_over(torch,small,(-3,-2))
# angle of inclination of the texture
rotation = 15
if data == 1: # pointing south
torch = torch.rotate(-rotation, Image.NEAREST) # nearest filter is more nitid.
img = _build_full_block(None, None, None, torch, None, None, blockID)
elif data == 2: # pointing north
torch = torch.rotate(rotation, Image.NEAREST)
img = _build_full_block(None, None, torch, None, None, None, blockID)
elif data == 3: # pointing west
torch = torch.rotate(rotation, Image.NEAREST)
img = _build_full_block(None, torch, None, None, None, None, blockID)
elif data == 4: # pointing east
torch = torch.rotate(-rotation, Image.NEAREST)
img = _build_full_block(None, None, None, None, torch, None, blockID)
elif data == 5: # standing on the floor
# compose a "3d torch".
img = Image.new("RGBA", (24,24), (38,92,255,0))
small_crop = small.crop((2,2,14,14))
slice = small_crop.copy()
ImageDraw.Draw(slice).rectangle((6,0,12,12),outline=(0,0,0,0),fill=(0,0,0,0))
ImageDraw.Draw(slice).rectangle((0,0,4,12),outline=(0,0,0,0),fill=(0,0,0,0))
composite.alpha_over(img, slice, (6,4))
composite.alpha_over(img, small_crop, (5,5))
composite.alpha_over(img, small_crop, (6,5))
composite.alpha_over(img, slice, (6,6))
return (img.convert("RGB"), img.split()[3])
if blockID == 51: # fire
firetexture = _load_image("fire.png")
side1 = transform_image_side(firetexture)
side2 = transform_image_side(firetexture).transpose(Image.FLIP_LEFT_RIGHT)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, side1, (12,0), side1)
composite.alpha_over(img, side2, (0,0), side2)
composite.alpha_over(img, side1, (0,6), side1)
composite.alpha_over(img, side2, (12,6), side2)
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])
if blockID == 58: # crafting table
top = terrain_images[43]
side3 = terrain_images[43+16]
side4 = terrain_images[43+16+1]
img = _build_full_block(top, None, None, side3, side4, None, 58)
return (img.convert("RGB"), img.split()[3])
if blockID == 59: # crops
raw_crop = terrain_images[88+data]
crop1 = transform_image(raw_crop, blockID)
crop2 = transform_image_side(raw_crop, blockID)
crop3 = crop2.transpose(Image.FLIP_LEFT_RIGHT)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, crop1, (0,12), crop1)
composite.alpha_over(img, crop2, (6,3), crop2)
composite.alpha_over(img, crop3, (6,3), crop3)
return (img.convert("RGB"), img.split()[3])
if blockID == 61: #furnace
top = transform_image(terrain_images[62])
side1 = transform_image_side(terrain_images[45])
side2 = transform_image_side(terrain_images[44]).transpose(Image.FLIP_LEFT_RIGHT)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, side1, (0,6), side1)
composite.alpha_over(img, side2, (12,6), side2)
composite.alpha_over(img, top, (0,0), top)
return (img.convert("RGB"), img.split()[3])
if blockID == 62: # lit furnace
top = transform_image(terrain_images[62])
side1 = transform_image_side(terrain_images[45])
side2 = transform_image_side(terrain_images[45+16]).transpose(Image.FLIP_LEFT_RIGHT)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, side1, (0,6), side1)
composite.alpha_over(img, side2, (12,6), side2)
composite.alpha_over(img, top, (0,0), top)
return (img.convert("RGB"), img.split()[3])
if blockID in (64,71): #wooden door, or iron door
if data & 0x8 == 0x8: # top of the door
raw_door = terrain_images[81 if blockID == 64 else 82]
else: # bottom of the door
raw_door = terrain_images[97 if blockID == 64 else 98]
# if you want to render all doors as closed, then force
# force swung to be False
if data & 0x4 == 0x4:
swung=True
else:
swung=False
# mask out the high bits to figure out the orientation
img = Image.new("RGBA", (24,24), (38,92,255,0))
if (data & 0x03) == 0:
if not swung:
tex = transform_image_side(raw_door)
composite.alpha_over(img, tex, (0,6), tex)
else:
# flip first to set the doornob on the correct side
tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT))
tex = tex.transpose(Image.FLIP_LEFT_RIGHT)
composite.alpha_over(img, tex, (0,0), tex)
if (data & 0x03) == 1:
if not swung:
tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT)
composite.alpha_over(img, tex, (0,0), tex)
else:
tex = transform_image_side(raw_door)
composite.alpha_over(img, tex, (12,0), tex)
if (data & 0x03) == 2:
if not swung:
tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT))
composite.alpha_over(img, tex, (12,0), tex)
else:
tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT)
composite.alpha_over(img, tex, (12,6), tex)
if (data & 0x03) == 3:
if not swung:
tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)).transpose(Image.FLIP_LEFT_RIGHT)
composite.alpha_over(img, tex, (12,6), tex)
else:
tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT))
composite.alpha_over(img, tex, (0,6), tex)
return (img.convert("RGB"), img.split()[3])
if blockID == 65: # ladder
raw_texture = terrain_images[83]
#print "ladder is facing: %d" % data
if data == 5:
# normally this ladder would be obsured by the block it's attached to
# but since ladders can apparently be placed on transparent blocks, we
# have to render this thing anyway. same for data == 2
tex = transform_image_side(raw_texture)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, tex, (0,6), tex)
return (img.convert("RGB"), img.split()[3])
if data == 2:
tex = transform_image_side(raw_texture).transpose(Image.FLIP_LEFT_RIGHT)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, tex, (12,6), tex)
return (img.convert("RGB"), img.split()[3])
if data == 3:
tex = transform_image_side(raw_texture).transpose(Image.FLIP_LEFT_RIGHT)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, tex, (0,0), tex)
return (img.convert("RGB"), img.split()[3])
if data == 4:
tex = transform_image_side(raw_texture)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, tex, (12,0), tex)
return (img.convert("RGB"), img.split()[3])
if blockID == 66: # minetrack:
raw_straight = terrain_images[128]
raw_corner = terrain_images[112]
## use transform_image to scale and shear
if data == 0:
track = transform_image(raw_straight, blockID)
elif data == 6:
track = transform_image(raw_corner, blockID)
elif data == 7:
track = transform_image(raw_corner.rotate(270), blockID)
elif data == 8:
# flip
track = transform_image(raw_corner.transpose(Image.FLIP_TOP_BOTTOM).rotate(90),
blockID)
elif data == 9:
track = transform_image(raw_corner.transpose(Image.FLIP_TOP_BOTTOM),
blockID)
elif data == 1:
track = transform_image(raw_straight.rotate(90), blockID)
#slopes
elif data == 2: # slope going up in +x direction
track = transform_image_slope(raw_straight,blockID)
track = track.transpose(Image.FLIP_LEFT_RIGHT)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, track, (2,0), track)
# the 2 pixels move is needed to fit with the adjacent tracks
return (img.convert("RGB"), img.split()[3])
elif data == 3: # slope going up in -x direction
# tracks are sprites, in this case we are seeing the "side" of
# the sprite, so draw a line to make it beautiful.
img = Image.new("RGBA", (24,24), (38,92,255,0))
ImageDraw.Draw(img).line([(11,11),(23,17)],fill=(164,164,164))
# grey from track texture (exterior grey).
# the track doesn't start from image corners, be carefull drawing the line!
return (img.convert("RGB"), img.split()[3])
elif data == 4: # slope going up in -y direction
track = transform_image_slope(raw_straight,blockID)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, track, (0,0), track)
return (img.convert("RGB"), img.split()[3])
elif data == 5: # slope going up in +y direction
# same as "data == 3"
img = Image.new("RGBA", (24,24), (38,92,255,0))
ImageDraw.Draw(img).line([(1,17),(12,11)],fill=(164,164,164))
return (img.convert("RGB"), img.split()[3])
else: # just in case
track = transform_image(raw_straight, blockID)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, track, (0,12), track)
return (img.convert("RGB"), img.split()[3])
if blockID == 85: # fences
# create needed images for Big stick fence
raw_texture = terrain_images[4]
@@ -845,138 +1028,19 @@ def generate_special_texture(blockID, data):
return (img.convert("RGB"),img.split()[3])
if blockID in (43,44): # slab and double-slab
if blockID in (86,91): # pumpkins, jack-o-lantern
top = transform_image(terrain_images[102])
frontID = 119 if blockID == 86 else 120
side1 = transform_image_side(terrain_images[frontID])
side2 = transform_image_side(terrain_images[118]).transpose(Image.FLIP_LEFT_RIGHT)
if data == 0: # stone slab
top = terrain_images[6]
side = terrain_images[5]
img = _build_block(top, side, blockID)
img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, side1, (0,6), side1)
composite.alpha_over(img, side2, (12,6), side2)
composite.alpha_over(img, top, (0,0), top)
return (img.convert("RGB"), img.split()[3])
if data == 1: # stone slab
top = terrain_images[176]
side = terrain_images[192]
img = _build_block(top, side, blockID)
return (img.convert("RGB"), img.split()[3])
if data == 2: # wooden slab
top = side = terrain_images[4]
img = _build_block(top, side, blockID)
return (img.convert("RGB"), img.split()[3])
if data == 3: # cobblestone slab
top = side = terrain_images[16]
img = _build_block(top, side, blockID)
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])
if blockID == 92: # cake! (without bites, at the moment)
@@ -1077,43 +1141,52 @@ def getBiomeData(worlddir, chunkX, chunkY):
# 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)
# A good source of information is:
# http://www.minecraftwiki.net/wiki/Data_values
# (when adding new blocks here and in generate_special_textures,
# please, if possible, keep the ascending order of blockid value)
special_blocks = set([66,59,61,62, 65,64,71,91,86,2,18,85,17,23,35,51,43,44,9,55,58,92])
special_blocks = set([2, 9, 17, 18, 23, 35, 43, 44, 50, 51, 55, 58, 59, \
61, 62, 64, 65, 66, 71, 75, 76, 85, 86, 91, 92])
# this is a map of special blockIDs to a list of all
# possible values for ancillary data that it might have.
special_map = {}
special_map[66] = range(10) # minecrart tracks
special_map[59] = range(8) # crops
special_map[61] = range(6) # furnace
special_map[62] = range(6) # burning furnace
special_map[65] = (2,3,4,5) # ladder
special_map[64] = range(16) # wooden door
special_map[71] = range(16) # iron door
special_map[91] = range(5) # jack-o-lantern
special_map[86] = range(5) # pumpkin
special_map[85] = range(17) # fences
special_map[9] = range(32) # water: spring,flowing, waterfall, and others (unknown) ancildata values.
special_map[17] = range(4) # wood: normal, birch and pine
special_map[23] = range(6) # dispensers
special_map[23] = range(6) # dispensers, orientation
special_map[35] = range(16) # wool, colored and white
special_map[51] = range(16) # fire
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[9] = range(32) # water: spring,flowing, waterfall, and others (unknown) ancildata values.
special_map[55] = range(128) # redstone wire
special_map[50] = (1,2,3,4,5) # torch, position in the block
special_map[51] = range(16) # fire, position in the block (not implemented)
special_map[55] = range(128) # redstone wire, all the possible combinations
special_map[58] = (0,) # crafting table
special_map[59] = range(8) # crops, grow from 0 to 7
special_map[61] = range(6) # furnace, orientation (not implemented)
special_map[62] = range(6) # burning furnace, orientation (not implemented)
special_map[64] = range(16) # wooden door, open/close and orientation
special_map[65] = (2,3,4,5) # ladder, orientation (not implemented)
special_map[66] = range(10) # minecrart tracks, orientation, slope
special_map[71] = range(16) # iron door, open/close and orientation
special_map[75] = (1,2,3,4,5) # off redstone torch, orientation
special_map[76] = (1,2,3,4,5) # on redstone torch, orientation
special_map[85] = range(17) # fences, all the possible combination
special_map[86] = range(5) # pumpkin, orientation (not implemented)
special_map[91] = range(5) # jack-o-lantern, orientation (not implemented)
special_map[92] = range(6) # cake!
# 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
# like torches
special_map[2] = (0,) # grass
special_map[18] = range(16) # leaves
# grass and leaves are now graysacle in terrain.png
# grass and leaves are graysacle in terrain.png
# we treat them as special so we can manually tint them
# it is unknown how the specific tint (biomes) is calculated
special_map[2] = range(11) # grass, grass has not ancildata but is used
# in the mod WildGrass, and this small fix
# shows the map as expected, and is harmless
# for normal maps
special_map[18] = range(16) # leaves, birch, normal or pine leaves (not implemented)
# leaves have ancilary data, but its meaning is unknown (age perhaps?)
specialblockmap = {}

View File

@@ -36,11 +36,14 @@ def get_program_path():
def findGitVersion():
if os.path.exists(".git"):
with open(os.path.join(".git","HEAD")) as f:
this_dir = get_program_path()
if os.path.exists(os.path.join(this_dir,".git")):
with open(os.path.join(this_dir,".git","HEAD")) as f:
data = f.read().strip()
if data.startswith("ref: "):
with open(os.path.join(".git", data[5:])) as g:
if not os.path.exists(os.path.join(this_dir,data[5:])):
return data
with open(os.path.join(this_dir, ".git", data[5:])) as g:
return g.read().strip()
else:
return data