Merge remote-tracking branch 'upstream/master'
This commit is contained in:
8
chunk.py
8
chunk.py
@@ -114,10 +114,10 @@ def get_tileentity_data(level):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
# This set holds blocks ids that can be seen through, for occlusion calculations
|
# This set holds blocks ids that can be seen through, for occlusion calculations
|
||||||
transparent_blocks = set([ 0, 6, 8, 9, 18, 20, 26, 27, 28, 30, 37, 38, 39, 40,
|
transparent_blocks = set([ 0, 6, 8, 9, 18, 20, 26, 27, 28, 30, 31, 32, 37, 38,
|
||||||
44, 50, 51, 52, 53, 55, 59, 63, 64, 65, 66, 67, 68, 69,
|
39, 40, 44, 50, 51, 52, 53, 55, 59, 63, 64, 65, 66, 67,
|
||||||
70, 71, 72, 74, 75, 76, 77, 78, 79, 81, 83, 85, 90, 92,
|
68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 79, 81, 83, 85,
|
||||||
93, 94])
|
90, 92, 93, 94, 96])
|
||||||
|
|
||||||
# This set holds block ids that are solid blocks
|
# This set holds block ids that are solid blocks
|
||||||
solid_blocks = set([1, 2, 3, 4, 5, 7, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
|
solid_blocks = set([1, 2, 3, 4, 5, 7, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
|
||||||
|
|||||||
@@ -81,6 +81,10 @@ class ConfigOptionParser(object):
|
|||||||
|
|
||||||
if os.path.exists(self.configFile):
|
if os.path.exists(self.configFile):
|
||||||
execfile(self.configFile, g, l)
|
execfile(self.configFile, g, l)
|
||||||
|
elif options.config_file:
|
||||||
|
# file does not exist, but *was* specified on the command line
|
||||||
|
logging.error("Could not open %s." % self.configFile)
|
||||||
|
sys.exit(1)
|
||||||
except NameError, ex:
|
except NameError, ex:
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import sys
|
|||||||
sys.path.insert(0,".")
|
sys.path.insert(0,".")
|
||||||
|
|
||||||
import nbt
|
import nbt
|
||||||
from chunk import get_blockarray_fromfile
|
from chunk import get_blockarray_fromfile, get_blockarray
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|||||||
16
googlemap.py
16
googlemap.py
@@ -19,7 +19,7 @@ import stat
|
|||||||
import cPickle
|
import cPickle
|
||||||
import Image
|
import Image
|
||||||
import shutil
|
import shutil
|
||||||
from time import strftime, gmtime
|
from time import strftime, localtime
|
||||||
import json
|
import json
|
||||||
|
|
||||||
import util
|
import util
|
||||||
@@ -66,7 +66,8 @@ class MapGen(object):
|
|||||||
image format, and world.
|
image format, and world.
|
||||||
Note:tiledir for each quadtree should be unique. By default the tiledir is determined by the rendermode"""
|
Note:tiledir for each quadtree should be unique. By default the tiledir is determined by the rendermode"""
|
||||||
|
|
||||||
self.skipjs = configInfo.get('skipjs', None)
|
self.skipjs = configInfo.get('skipjs', False)
|
||||||
|
self.nosigns = configInfo.get('nosigns', False)
|
||||||
self.web_assets_hook = configInfo.get('web_assets_hook', None)
|
self.web_assets_hook = configInfo.get('web_assets_hook', None)
|
||||||
self.web_assets_path = configInfo.get('web_assets_path', None)
|
self.web_assets_path = configInfo.get('web_assets_path', None)
|
||||||
self.bg_color = configInfo.get('bg_color')
|
self.bg_color = configInfo.get('bg_color')
|
||||||
@@ -131,7 +132,7 @@ class MapGen(object):
|
|||||||
|
|
||||||
index = open(indexpath, 'r').read()
|
index = open(indexpath, 'r').read()
|
||||||
index = index.replace(
|
index = index.replace(
|
||||||
"{time}", str(strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime())))
|
"{time}", str(strftime("%a, %d %b %Y %H:%M:%S %Z", localtime())))
|
||||||
index = index.replace("{version}", util.findGitVersion())
|
index = index.replace("{version}", util.findGitVersion())
|
||||||
|
|
||||||
with open(os.path.join(self.destdir, "index.html"), 'w') as output:
|
with open(os.path.join(self.destdir, "index.html"), 'w') as output:
|
||||||
@@ -153,13 +154,18 @@ class MapGen(object):
|
|||||||
# we need to merge self.world.POI with the persistant data in world.PersistentData
|
# we need to merge self.world.POI with the persistant data in world.PersistentData
|
||||||
|
|
||||||
self.world.POI += filter(lambda x: x['type'] != 'spawn', self.world.persistentData['POI'])
|
self.world.POI += filter(lambda x: x['type'] != 'spawn', self.world.persistentData['POI'])
|
||||||
|
|
||||||
|
if self.nosigns:
|
||||||
|
markers = filter(lambda x: x['type'] != 'sign', self.world.POI)
|
||||||
|
else:
|
||||||
|
markers = self.world.POI
|
||||||
|
|
||||||
# write out the default marker table
|
# write out the default marker table
|
||||||
with open(os.path.join(self.destdir, "markers.js"), 'w') as output:
|
with open(os.path.join(self.destdir, "markers.js"), 'w') as output:
|
||||||
output.write("overviewer.collections.markerDatas.push([\n")
|
output.write("overviewer.collections.markerDatas.push([\n")
|
||||||
for marker in self.world.POI:
|
for marker in markers:
|
||||||
output.write(json.dumps(marker))
|
output.write(json.dumps(marker))
|
||||||
if marker != self.world.POI[-1]:
|
if marker != markers[-1]:
|
||||||
output.write(",")
|
output.write(",")
|
||||||
output.write("\n")
|
output.write("\n")
|
||||||
output.write("]);\n")
|
output.write("]);\n")
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ def check_programs(level):
|
|||||||
result = filter(lambda x: os.path.exists(os.path.join(x, prog)), path)
|
result = filter(lambda x: os.path.exists(os.path.join(x, prog)), path)
|
||||||
return len(result) != 0
|
return len(result) != 0
|
||||||
|
|
||||||
for prog,l in [(pngcrush,1), (optipng,2), (advdef,2)]:
|
for prog,l in [(pngcrush,1), (advdef,2)]:
|
||||||
if l <= level:
|
if l <= level:
|
||||||
if (not exists_in_path(prog)) and (not exists_in_path(prog + ".exe")):
|
if (not exists_in_path(prog)) and (not exists_in_path(prog + ".exe")):
|
||||||
raise Exception("Optimization prog %s for level %d not found!" % (prog, l))
|
raise Exception("Optimization prog %s for level %d not found!" % (prog, l))
|
||||||
@@ -45,8 +45,8 @@ def optimize_image(imgpath, imgformat, optimizeimg):
|
|||||||
os.rename(imgpath+".tmp", imgpath)
|
os.rename(imgpath+".tmp", imgpath)
|
||||||
|
|
||||||
if optimizeimg >= 2:
|
if optimizeimg >= 2:
|
||||||
subprocess.Popen([optipng, imgpath], stderr=subprocess.STDOUT,
|
# the "-nc" it's needed to no broke the transparency of tiles
|
||||||
stdout=subprocess.PIPE).communicate()[0]
|
recompress_option = "-z2" if optimizeimg == 2 else "-z4"
|
||||||
subprocess.Popen([advdef, "-z4",imgpath], stderr=subprocess.STDOUT,
|
subprocess.Popen([advdef, recompress_option,imgpath], stderr=subprocess.STDOUT,
|
||||||
stdout=subprocess.PIPE).communicate()[0]
|
stdout=subprocess.PIPE).communicate()[0]
|
||||||
|
|
||||||
|
|||||||
@@ -94,18 +94,20 @@ def main():
|
|||||||
parser.add_option("-z", "--zoom", dest="zoom", help="Sets the zoom level manually instead of calculating it. This can be useful if you have outlier chunks that make your world too big. This value will make the highest zoom level contain (2**ZOOM)^2 tiles", action="store", type="int", configFileOnly=True)
|
parser.add_option("-z", "--zoom", dest="zoom", help="Sets the zoom level manually instead of calculating it. This can be useful if you have outlier chunks that make your world too big. This value will make the highest zoom level contain (2**ZOOM)^2 tiles", action="store", type="int", configFileOnly=True)
|
||||||
parser.add_option("-d", "--delete", dest="delete", help="Clear all caches. Next time you render your world, it will have to start completely over again. This is probably not a good idea for large worlds. Use this if you change texture packs and want to re-render everything.", action="store_true", commandLineOnly=True)
|
parser.add_option("-d", "--delete", dest="delete", help="Clear all caches. Next time you render your world, it will have to start completely over again. This is probably not a good idea for large worlds. Use this if you change texture packs and want to re-render everything.", action="store_true", commandLineOnly=True)
|
||||||
parser.add_option("--regionlist", dest="regionlist", help="A file containing, on each line, a path to a regionlist to update. Instead of scanning the world directory for regions, it will just use this list. Normal caching rules still apply.")
|
parser.add_option("--regionlist", dest="regionlist", help="A file containing, on each line, a path to a regionlist to update. Instead of scanning the world directory for regions, it will just use this list. Normal caching rules still apply.")
|
||||||
|
parser.add_option("--forcerender", dest="forcerender", help="Force re-rendering the entire map (or the given regionlist). Useful for re-rendering without deleting the entire map with --delete.", action="store_true")
|
||||||
parser.add_option("--rendermodes", dest="rendermode", help="Specifies the render types, separated by commas. Use --list-rendermodes to list them all.", type="choice", choices=avail_rendermodes, required=True, default=avail_rendermodes[0], listify=True)
|
parser.add_option("--rendermodes", dest="rendermode", help="Specifies the render types, separated by commas. Use --list-rendermodes to list them all.", type="choice", choices=avail_rendermodes, required=True, default=avail_rendermodes[0], listify=True)
|
||||||
parser.add_option("--list-rendermodes", dest="list_rendermodes", action="store_true", help="List available render modes and exit.", commandLineOnly=True)
|
parser.add_option("--list-rendermodes", dest="list_rendermodes", action="store_true", help="List available render modes and exit.", commandLineOnly=True)
|
||||||
parser.add_option("--imgformat", dest="imgformat", help="The image output format to use. Currently supported: png(default), jpg.", configFileOnly=True )
|
parser.add_option("--imgformat", dest="imgformat", help="The image output format to use. Currently supported: png(default), jpg.", configFileOnly=True )
|
||||||
parser.add_option("--imgquality", dest="imgquality", default=95, help="Specify the quality of image output when using imgformat=\"jpg\".", type="int", configFileOnly=True)
|
parser.add_option("--imgquality", dest="imgquality", default=95, help="Specify the quality of image output when using imgformat=\"jpg\".", type="int", configFileOnly=True)
|
||||||
parser.add_option("--bg_color", dest="bg_color", help="Configures the background color for the GoogleMap output. Specify in #RRGGBB format", configFileOnly=True, type="string", default="#1A1A1A")
|
parser.add_option("--bg_color", dest="bg_color", help="Configures the background color for the GoogleMap output. Specify in #RRGGBB format", configFileOnly=True, type="string", default="#1A1A1A")
|
||||||
parser.add_option("--optimize-img", dest="optimizeimg", help="If using png, perform image file size optimizations on the output. Specify 1 for pngcrush, 2 for pngcrush+optipng+advdef. This may double (or more) render times, but will produce up to 30% smaller images. NOTE: requires corresponding programs in $PATH or %PATH%", configFileOnly=True)
|
parser.add_option("--optimize-img", dest="optimizeimg", help="If using png, perform image file size optimizations on the output. Specify 1 for pngcrush, 2 for pngcrush+advdef and 3 for pngcrush-advdef with more agressive settings. This may double (or more) render times, but will produce up to 30% smaller images. NOTE: requires corresponding programs in $PATH or %PATH%", configFileOnly=True)
|
||||||
parser.add_option("--web-assets-hook", dest="web_assets_hook", help="If provided, run this function after the web assets have been copied, but before actual tile rendering begins. It should accept a QuadtreeGen object as its only argument.", action="store", metavar="SCRIPT", type="function", configFileOnly=True)
|
parser.add_option("--web-assets-hook", dest="web_assets_hook", help="If provided, run this function after the web assets have been copied, but before actual tile rendering begins. It should accept a QuadtreeGen object as its only argument.", action="store", metavar="SCRIPT", type="function", configFileOnly=True)
|
||||||
parser.add_option("--web-assets-path", dest="web_assets_path", help="Specifies a non-standard web_assets directory to use. Files here will overwrite the default web assets.", metavar="PATH", type="string", configFileOnly=True)
|
parser.add_option("--web-assets-path", dest="web_assets_path", help="Specifies a non-standard web_assets directory to use. Files here will overwrite the default web assets.", metavar="PATH", type="string", configFileOnly=True)
|
||||||
parser.add_option("--textures-path", dest="textures_path", help="Specifies a non-standard textures path, from which terrain.png and other textures are loaded.", metavar="PATH", type="string", configFileOnly=True)
|
parser.add_option("--textures-path", dest="textures_path", help="Specifies a non-standard textures path, from which terrain.png and other textures are loaded.", metavar="PATH", type="string", configFileOnly=True)
|
||||||
parser.add_option("-q", "--quiet", dest="quiet", action="count", default=0, help="Print less output. You can specify this option multiple times.")
|
parser.add_option("-q", "--quiet", dest="quiet", action="count", default=0, help="Print less output. You can specify this option multiple times.")
|
||||||
parser.add_option("-v", "--verbose", dest="verbose", action="count", default=0, help="Print more output. You can specify this option multiple times.")
|
parser.add_option("-v", "--verbose", dest="verbose", action="count", default=0, help="Print more output. You can specify this option multiple times.")
|
||||||
parser.add_option("--skip-js", dest="skipjs", action="store_true", help="Don't output marker.js or regions.js")
|
parser.add_option("--skip-js", dest="skipjs", action="store_true", help="Don't output marker.js or regions.js")
|
||||||
|
parser.add_option("--no-signs", dest="nosigns", action="store_true", help="Don't output signs to markers.js")
|
||||||
parser.add_option("--display-config", dest="display_config", action="store_true", help="Display the configuration parameters, but don't render the map. Requires all required options to be specified", commandLineOnly=True)
|
parser.add_option("--display-config", dest="display_config", action="store_true", help="Display the configuration parameters, but don't render the map. Requires all required options to be specified", commandLineOnly=True)
|
||||||
#parser.add_option("--write-config", dest="write_config", action="store_true", help="Writes out a sample config file", commandLineOnly=True)
|
#parser.add_option("--write-config", dest="write_config", action="store_true", help="Writes out a sample config file", commandLineOnly=True)
|
||||||
|
|
||||||
@@ -231,7 +233,7 @@ def main():
|
|||||||
# create the quadtrees
|
# create the quadtrees
|
||||||
# TODO chunklist
|
# TODO chunklist
|
||||||
q = []
|
q = []
|
||||||
qtree_args = {'depth' : options.zoom, 'imgformat' : imgformat, 'imgquality' : options.imgquality, 'optimizeimg' : optimizeimg, 'bgcolor' : bgcolor}
|
qtree_args = {'depth' : options.zoom, 'imgformat' : imgformat, 'imgquality' : options.imgquality, 'optimizeimg' : optimizeimg, 'bgcolor' : bgcolor, 'forcerender' : options.forcerender}
|
||||||
for rendermode in options.rendermode:
|
for rendermode in options.rendermode:
|
||||||
if rendermode == 'normal':
|
if rendermode == 'normal':
|
||||||
qtree = quadtree.QuadtreeGen(w, destdir, rendermode=rendermode, tiledir='tiles', **qtree_args)
|
qtree = quadtree.QuadtreeGen(w, destdir, rendermode=rendermode, tiledir='tiles', **qtree_args)
|
||||||
|
|||||||
19
quadtree.py
19
quadtree.py
@@ -49,7 +49,7 @@ def iterate_base4(d):
|
|||||||
return itertools.product(xrange(4), repeat=d)
|
return itertools.product(xrange(4), repeat=d)
|
||||||
|
|
||||||
class QuadtreeGen(object):
|
class QuadtreeGen(object):
|
||||||
def __init__(self, worldobj, destdir, bgcolor, depth=None, tiledir=None, imgformat=None, imgquality=95, optimizeimg=None, rendermode="normal"):
|
def __init__(self, worldobj, destdir, bgcolor, depth=None, tiledir=None, forcerender=False, imgformat=None, imgquality=95, optimizeimg=None, rendermode="normal"):
|
||||||
"""Generates a quadtree from the world given into the
|
"""Generates a quadtree from the world given into the
|
||||||
given dest directory
|
given dest directory
|
||||||
|
|
||||||
@@ -60,6 +60,7 @@ class QuadtreeGen(object):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
assert(imgformat)
|
assert(imgformat)
|
||||||
|
self.forcerender = forcerender
|
||||||
self.imgformat = imgformat
|
self.imgformat = imgformat
|
||||||
self.imgquality = imgquality
|
self.imgquality = imgquality
|
||||||
self.optimizeimg = optimizeimg
|
self.optimizeimg = optimizeimg
|
||||||
@@ -425,13 +426,21 @@ class QuadtreeGen(object):
|
|||||||
needs_rerender = False
|
needs_rerender = False
|
||||||
get_region_mtime = world.get_region_mtime
|
get_region_mtime = world.get_region_mtime
|
||||||
for col, row, chunkx, chunky, regionfile in chunks:
|
for col, row, chunkx, chunky, regionfile in chunks:
|
||||||
|
|
||||||
|
# bail early if forcerender is set
|
||||||
|
if self.forcerender:
|
||||||
|
needs_rerender = True
|
||||||
|
break
|
||||||
|
|
||||||
# check region file mtime first.
|
# check region file mtime first.
|
||||||
region,regionMtime = get_region_mtime(regionfile)
|
region,regionMtime = get_region_mtime(regionfile)
|
||||||
if self.world.regionlist and region._filename not in self.world.regionlist:
|
|
||||||
continue
|
|
||||||
if regionMtime <= tile_mtime:
|
if regionMtime <= tile_mtime:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# don't even check if it's not in the regionlist
|
||||||
|
if self.world.regionlist and os.path.abspath(region._filename) not in self.world.regionlist:
|
||||||
|
continue
|
||||||
|
|
||||||
# checking chunk mtime
|
# checking chunk mtime
|
||||||
if region.get_chunk_timestamp(chunkx, chunky) > tile_mtime:
|
if region.get_chunk_timestamp(chunkx, chunky) > tile_mtime:
|
||||||
needs_rerender = True
|
needs_rerender = True
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
# provide examples of interesting things you can do with the settings file. Most
|
# provide examples of interesting things you can do with the settings file. Most
|
||||||
# of the time, a simple 'setting_name = value' will work.
|
# of the time, a simple 'setting_name = value' will work.
|
||||||
|
|
||||||
# This file is a python script, so you can import and python module you wish or
|
# This file is a python script, so you can import any python module you wish or
|
||||||
# use any built-in python function, though this is not normally necessary
|
# use any built-in python function, though this is not normally necessary
|
||||||
|
|
||||||
# Lines that start with a hash mark are comments
|
# Lines that start with a hash mark are comments
|
||||||
@@ -50,10 +50,13 @@ zoom = 9
|
|||||||
## Example: Dynamically create regionlist of only regions older than 2 days
|
## Example: Dynamically create regionlist of only regions older than 2 days
|
||||||
|
|
||||||
import os, time
|
import os, time
|
||||||
|
# the following two lines are needed to the lambda to work
|
||||||
|
globals()['os'] = os
|
||||||
|
globals()['time'] = time
|
||||||
regionDir = os.path.join(args[0], "region")
|
regionDir = os.path.join(args[0], "region")
|
||||||
regionFiles = filter(lambda x: x.endswith(".mcr"), os.listdir(regionDir))
|
regionFiles = filter(lambda x: x.endswith(".mcr"), os.listdir(regionDir))
|
||||||
def olderThanTwoDays(f):
|
def olderThanTwoDays(f):
|
||||||
return time.time() - os.stat(f).st_mtime > (60*60*24*2)
|
return time.time() - os.stat(os.path.join(args[0], 'region',f)).st_mtime > (60*60*24*2)
|
||||||
oldRegionFiles = filter(olderThanTwoDays, regionFiles)
|
oldRegionFiles = filter(olderThanTwoDays, regionFiles)
|
||||||
with open("regionlist.txt", "w") as f:
|
with open("regionlist.txt", "w") as f:
|
||||||
f.write("\n".join(oldRegionFiles))
|
f.write("\n".join(oldRegionFiles))
|
||||||
@@ -89,9 +92,11 @@ imgformat = "jpg"
|
|||||||
################################################################################
|
################################################################################
|
||||||
### optimizeimg
|
### optimizeimg
|
||||||
## If using png, perform image file size optimizations on the output. Specify 1
|
## If using png, perform image file size optimizations on the output. Specify 1
|
||||||
## for pngcrush, 2 for pngcrush+optipng+advdef. This may double (or more)
|
## for pngcrush, 2 for pngcrush+advdef, 3 for pngcrush+advdef with more agressive
|
||||||
## render times, but will produce up to 30% smaller images. NOTE: requires
|
## options. Option 1 gives around 19% of reduction, option 2 gives around 21%
|
||||||
## corresponding programs in $PATH or %PATH%
|
## (it doubles the optimizing time) and option 3 gives around 23% (it doubles,
|
||||||
|
## again, the optimizing time). Using this option may double (or more)
|
||||||
|
## render times. NOTE: requires corresponding programs in $PATH or %PATH%
|
||||||
## Default: not set
|
## Default: not set
|
||||||
## Type: integer
|
## Type: integer
|
||||||
## Example:
|
## Example:
|
||||||
@@ -148,3 +153,9 @@ if "web_assets_hook" in locals():
|
|||||||
skipjs = True
|
skipjs = True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### As a reminder, don't use this file verbatim, it should only be used as
|
||||||
|
### a guide.
|
||||||
|
import sys
|
||||||
|
sys.exit("This sample-settings file shouldn't be used directly!")
|
||||||
|
|||||||
@@ -160,13 +160,17 @@ generate_pseudo_data(RenderState *state, unsigned char ancilData) {
|
|||||||
return ancilData;
|
return ancilData;
|
||||||
} else if (state->block == 9) { /* water */
|
} else if (state->block == 9) { /* water */
|
||||||
/* an aditional bit for top is added to the 4 bits of check_adjacent_blocks */
|
/* an aditional bit for top is added to the 4 bits of check_adjacent_blocks */
|
||||||
if ((ancilData == 0) || (ancilData >= 10)) { /* static water, only top, and unkown ancildata values */
|
if (ancilData == 0) { /* static water */
|
||||||
data = 16;
|
if ((z != 127) && (getArrayByte3D(state->blocks, x, y, z+1) == 9)) {
|
||||||
|
data = 0;
|
||||||
|
} else {
|
||||||
|
data = 16;
|
||||||
|
}
|
||||||
return data; /* = 0b10000 */
|
return data; /* = 0b10000 */
|
||||||
} else if ((ancilData > 0) && (ancilData < 8)) { /* flowing water */
|
} else if ((ancilData > 0) && (ancilData < 8)) { /* flowing water */
|
||||||
data = (check_adjacent_blocks(state, x, y, z, state->block) ^ 0x0f) | 0x10;
|
data = (check_adjacent_blocks(state, x, y, z, state->block) ^ 0x0f) | 0x10;
|
||||||
return data;
|
return data;
|
||||||
} else if ((ancilData == 8) || (ancilData == 9)) { /* falling water */
|
} else if (ancilData >= 8) { /* falling water */
|
||||||
data = (check_adjacent_blocks(state, x, y, z, state->block) ^ 0x0f);
|
data = (check_adjacent_blocks(state, x, y, z, state->block) ^ 0x0f);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
@@ -289,7 +293,6 @@ PyObject*
|
|||||||
chunk_render(PyObject *self, PyObject *args) {
|
chunk_render(PyObject *self, PyObject *args) {
|
||||||
RenderState state;
|
RenderState state;
|
||||||
|
|
||||||
PyObject *blockdata_expanded;
|
|
||||||
int xoff, yoff;
|
int xoff, yoff;
|
||||||
|
|
||||||
PyObject *imgsize, *imgsize0_py, *imgsize1_py;
|
PyObject *imgsize, *imgsize0_py, *imgsize1_py;
|
||||||
@@ -307,7 +310,7 @@ chunk_render(PyObject *self, PyObject *args) {
|
|||||||
|
|
||||||
PyObject *t = NULL;
|
PyObject *t = NULL;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "OOiiO", &state.self, &state.img, &xoff, &yoff, &blockdata_expanded))
|
if (!PyArg_ParseTuple(args, "OOiiO", &state.self, &state.img, &xoff, &yoff, &state.blockdata_expanded))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* fill in important modules */
|
/* fill in important modules */
|
||||||
@@ -398,7 +401,7 @@ chunk_render(PyObject *self, PyObject *args) {
|
|||||||
} else {
|
} else {
|
||||||
PyObject *tmp;
|
PyObject *tmp;
|
||||||
|
|
||||||
unsigned char ancilData = getArrayByte3D(blockdata_expanded, state.x, state.y, state.z);
|
unsigned char ancilData = getArrayByte3D(state.blockdata_expanded, state.x, state.y, state.z);
|
||||||
if ((state.block == 85) || (state.block == 9) || (state.block == 55) || (state.block == 54) || (state.block == 2) || (state.block == 90)) {
|
if ((state.block == 85) || (state.block == 9) || (state.block == 55) || (state.block == 54) || (state.block == 2) || (state.block == 90)) {
|
||||||
ancilData = generate_pseudo_data(&state, ancilData);
|
ancilData = generate_pseudo_data(&state, ancilData);
|
||||||
}
|
}
|
||||||
@@ -417,14 +420,15 @@ chunk_render(PyObject *self, PyObject *args) {
|
|||||||
/* if we found a proper texture, render it! */
|
/* if we found a proper texture, render it! */
|
||||||
if (t != NULL && t != Py_None)
|
if (t != NULL && t != Py_None)
|
||||||
{
|
{
|
||||||
PyObject *src, *mask;
|
PyObject *src, *mask, *mask_light;
|
||||||
src = PyTuple_GetItem(t, 0);
|
src = PyTuple_GetItem(t, 0);
|
||||||
mask = PyTuple_GetItem(t, 1);
|
mask = PyTuple_GetItem(t, 1);
|
||||||
|
mask_light = PyTuple_GetItem(t, 2);
|
||||||
|
|
||||||
if (mask == Py_None)
|
if (mask == Py_None)
|
||||||
mask = src;
|
mask = src;
|
||||||
|
|
||||||
rendermode->draw(rm_data, &state, src, mask);
|
rendermode->draw(rm_data, &state, src, mask, mask_light);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
// increment this value if you've made a change to the c extesion
|
// increment this value if you've made a change to the c extesion
|
||||||
// and want to force users to rebuild
|
// and want to force users to rebuild
|
||||||
#define OVERVIEWER_EXTENSION_VERSION 6
|
#define OVERVIEWER_EXTENSION_VERSION 8
|
||||||
|
|
||||||
/* Python PIL, and numpy headers */
|
/* Python PIL, and numpy headers */
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
@@ -70,6 +70,7 @@ typedef struct {
|
|||||||
/* the block position and type, and the block array */
|
/* the block position and type, and the block array */
|
||||||
int x, y, z;
|
int x, y, z;
|
||||||
unsigned char block;
|
unsigned char block;
|
||||||
|
PyObject *blockdata_expanded;
|
||||||
PyObject *blocks;
|
PyObject *blocks;
|
||||||
PyObject *up_left_blocks;
|
PyObject *up_left_blocks;
|
||||||
PyObject *up_right_blocks;
|
PyObject *up_right_blocks;
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ rendermode_cave_finish(void *data, RenderState *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rendermode_cave_draw(void *data, RenderState *state, PyObject *src, PyObject *mask) {
|
rendermode_cave_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
|
||||||
RenderModeCave* self;
|
RenderModeCave* self;
|
||||||
int z, r, g, b;
|
int z, r, g, b;
|
||||||
self = (RenderModeCave *)data;
|
self = (RenderModeCave *)data;
|
||||||
@@ -211,7 +211,7 @@ rendermode_cave_draw(void *data, RenderState *state, PyObject *src, PyObject *ma
|
|||||||
r = 0, g = 0, b = 0;
|
r = 0, g = 0, b = 0;
|
||||||
|
|
||||||
/* draw the normal block */
|
/* draw the normal block */
|
||||||
rendermode_normal.draw(data, state, src, mask);
|
rendermode_normal.draw(data, state, src, mask, mask_light);
|
||||||
|
|
||||||
/* get the colors and tint and tint */
|
/* get the colors and tint and tint */
|
||||||
/* TODO TODO for a nether mode there isn't tinting! */
|
/* TODO TODO for a nether mode there isn't tinting! */
|
||||||
|
|||||||
@@ -33,21 +33,108 @@ static float calculate_darkness(unsigned char skylight, unsigned char blocklight
|
|||||||
* was calculated correctly from available light data, it will be true. You
|
* was calculated correctly from available light data, it will be true. You
|
||||||
* may (and probably should) pass NULL.
|
* may (and probably should) pass NULL.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
inline unsigned char
|
||||||
|
estimate_blocklevel(RenderModeLighting *self, RenderState *state,
|
||||||
|
int x, int y, int z, int *authoratative) {
|
||||||
|
|
||||||
|
/* placeholders for later data arrays, coordinates */
|
||||||
|
PyObject *blocks = NULL;
|
||||||
|
PyObject *blocklight = NULL;
|
||||||
|
int local_x = x, local_y = y, local_z = z;
|
||||||
|
unsigned char block, blocklevel;
|
||||||
|
unsigned int average_count = 0, average_gather = 0, coeff = 0;
|
||||||
|
|
||||||
|
/* defaults to "guess" until told otherwise */
|
||||||
|
if (authoratative)
|
||||||
|
*authoratative = 0;
|
||||||
|
|
||||||
|
/* find out what chunk we're in, and translate accordingly */
|
||||||
|
if (x >= 0 && y < 16) {
|
||||||
|
blocks = state->blocks;
|
||||||
|
blocklight = self->blocklight;
|
||||||
|
} else if (x < 0) {
|
||||||
|
local_x += 16;
|
||||||
|
blocks = state->left_blocks;
|
||||||
|
blocklight = self->left_blocklight;
|
||||||
|
} else if (y >= 16) {
|
||||||
|
local_y -= 16;
|
||||||
|
blocks = state->right_blocks;
|
||||||
|
blocklight = self->right_blocklight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make sure we have correctly-ranged coordinates */
|
||||||
|
if (!(local_x >= 0 && local_x < 16 &&
|
||||||
|
local_y >= 0 && local_y < 16 &&
|
||||||
|
local_z >= 0 && local_z < 128)) {
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* also, make sure we have enough info to correctly calculate lighting */
|
||||||
|
if (blocks == Py_None || blocks == NULL ||
|
||||||
|
blocklight == Py_None || blocklight == NULL) {
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
block = getArrayByte3D(blocks, local_x, local_y, local_z);
|
||||||
|
|
||||||
|
if (authoratative == NULL) {
|
||||||
|
int auth;
|
||||||
|
|
||||||
|
/* iterate through all surrounding blocks to take an average */
|
||||||
|
int dx, dy, dz, local_block;
|
||||||
|
for (dx = -1; dx <= 1; dx += 2) {
|
||||||
|
for (dy = -1; dy <= 1; dy += 2) {
|
||||||
|
for (dz = -1; dz <= 1; dz += 2) {
|
||||||
|
|
||||||
|
/* skip if block is out of range */
|
||||||
|
if (x+dx < 0 || x+dx >= 16 ||
|
||||||
|
y+dy < 0 || y+dy >= 16 ||
|
||||||
|
z+dz < 0 || z+dz >= 128) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
coeff = estimate_blocklevel(self, state, x+dx, y+dy, z+dz, &auth);
|
||||||
|
local_block = getArrayByte3D(blocks, x+dx, y+dy, z+dz);
|
||||||
|
/* only add if the block is transparent, this seems to look better than
|
||||||
|
using every block */
|
||||||
|
if (auth && is_transparent(local_block)) {
|
||||||
|
average_gather += coeff;
|
||||||
|
average_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* only return the average if at least one was authoratative */
|
||||||
|
if (average_count > 0) {
|
||||||
|
return average_gather / average_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
blocklevel = getArrayByte3D(blocklight, local_x, local_y, local_z);
|
||||||
|
|
||||||
|
/* no longer a guess */
|
||||||
|
if (!(block == 44 || block == 53 || block == 67) && authoratative) {
|
||||||
|
*authoratative = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return blocklevel;
|
||||||
|
}
|
||||||
|
|
||||||
inline float
|
inline float
|
||||||
get_lighting_coefficient(RenderModeLighting *self, RenderState *state,
|
get_lighting_coefficient(RenderModeLighting *self, RenderState *state,
|
||||||
int x, int y, int z, int *authoratative) {
|
int x, int y, int z) {
|
||||||
|
|
||||||
/* placeholders for later data arrays, coordinates */
|
/* placeholders for later data arrays, coordinates */
|
||||||
PyObject *blocks = NULL;
|
PyObject *blocks = NULL;
|
||||||
PyObject *skylight = NULL;
|
PyObject *skylight = NULL;
|
||||||
PyObject *blocklight = NULL;
|
PyObject *blocklight = NULL;
|
||||||
int local_x = x, local_y = y, local_z = z;
|
int local_x = x, local_y = y, local_z = z;
|
||||||
unsigned char block, skylevel, blocklevel;
|
unsigned char block, skylevel, blocklevel;
|
||||||
|
|
||||||
/* defaults to "guess" until told otherwise */
|
|
||||||
if (authoratative)
|
|
||||||
*authoratative = 0;
|
|
||||||
|
|
||||||
/* find out what chunk we're in, and translate accordingly */
|
/* find out what chunk we're in, and translate accordingly */
|
||||||
if (x >= 0 && y < 16) {
|
if (x >= 0 && y < 16) {
|
||||||
blocks = state->blocks;
|
blocks = state->blocks;
|
||||||
@@ -64,7 +151,7 @@ get_lighting_coefficient(RenderModeLighting *self, RenderState *state,
|
|||||||
skylight = self->right_skylight;
|
skylight = self->right_skylight;
|
||||||
blocklight = self->right_blocklight;
|
blocklight = self->right_blocklight;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* make sure we have correctly-ranged coordinates */
|
/* make sure we have correctly-ranged coordinates */
|
||||||
if (!(local_x >= 0 && local_x < 16 &&
|
if (!(local_x >= 0 && local_x < 16 &&
|
||||||
local_y >= 0 && local_y < 16 &&
|
local_y >= 0 && local_y < 16 &&
|
||||||
@@ -72,7 +159,7 @@ get_lighting_coefficient(RenderModeLighting *self, RenderState *state,
|
|||||||
|
|
||||||
return self->calculate_darkness(15, 0);
|
return self->calculate_darkness(15, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* also, make sure we have enough info to correctly calculate lighting */
|
/* also, make sure we have enough info to correctly calculate lighting */
|
||||||
if (blocks == Py_None || blocks == NULL ||
|
if (blocks == Py_None || blocks == NULL ||
|
||||||
skylight == Py_None || skylight == NULL ||
|
skylight == Py_None || skylight == NULL ||
|
||||||
@@ -89,31 +176,28 @@ get_lighting_coefficient(RenderModeLighting *self, RenderState *state,
|
|||||||
return self->calculate_darkness(15, 0);
|
return self->calculate_darkness(15, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* only do special half-step handling if no authoratative pointer was
|
skylevel = getArrayByte3D(skylight, local_x, local_y, local_z);
|
||||||
passed in, which is a sign that we're recursing */
|
blocklevel = getArrayByte3D(blocklight, local_x, local_y, local_z);
|
||||||
if (block == 44 && authoratative == NULL) {
|
|
||||||
float average_gather = 0.0f;
|
/* special half-step handling */
|
||||||
unsigned int average_count = 0;
|
if (block == 44 || block == 53 || block == 67) {
|
||||||
int auth;
|
unsigned int upper_block;
|
||||||
float coeff;
|
|
||||||
|
|
||||||
/* iterate through all surrounding blocks to take an average */
|
/* stairs and half-blocks take the skylevel from the upper block if it's transparent */
|
||||||
int dx, dy, dz;
|
if (local_z != 127) {
|
||||||
for (dx = -1; dx <= 1; dx += 2) {
|
upper_block = getArrayByte3D(blocks, local_x, local_y, local_z + 1);
|
||||||
for (dy = -1; dy <= 1; dy += 2) {
|
if (is_transparent(upper_block)) {
|
||||||
for (dz = -1; dz <= 1; dz += 2) {
|
skylevel = getArrayByte3D(skylight, local_x, local_y, local_z + 1);
|
||||||
coeff = get_lighting_coefficient(self, state, x+dx, y+dy, z+dz, &auth);
|
|
||||||
if (auth) {
|
|
||||||
average_gather += coeff;
|
|
||||||
average_count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
upper_block = 0;
|
||||||
|
skylevel = 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* only return the average if at least one was authoratative */
|
/* the block has a bad blocklevel, estimate it from neigborhood
|
||||||
if (average_count > 0)
|
/* use given coordinates, no local ones! */
|
||||||
return average_gather / average_count;
|
blocklevel = estimate_blocklevel(self, state, x, y, z, NULL);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block == 10 || block == 11) {
|
if (block == 10 || block == 11) {
|
||||||
@@ -121,13 +205,6 @@ get_lighting_coefficient(RenderModeLighting *self, RenderState *state,
|
|||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
skylevel = getArrayByte3D(skylight, local_x, local_y, local_z);
|
|
||||||
blocklevel = getArrayByte3D(blocklight, local_x, local_y, local_z);
|
|
||||||
|
|
||||||
/* no longer a guess */
|
|
||||||
if (authoratative)
|
|
||||||
*authoratative = 1;
|
|
||||||
|
|
||||||
return self->calculate_darkness(skylevel, blocklevel);
|
return self->calculate_darkness(skylevel, blocklevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,7 +224,7 @@ do_shading_with_mask(RenderModeLighting *self, RenderState *state,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
black_coeff = get_lighting_coefficient(self, state, x, y, z, NULL);
|
black_coeff = get_lighting_coefficient(self, state, x, y, z);
|
||||||
alpha_over_full(state->img, self->black_color, mask, black_coeff, state->imgx, state->imgy, 0, 0);
|
alpha_over_full(state->img, self->black_color, mask, black_coeff, state->imgx, state->imgy, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,19 +283,19 @@ rendermode_lighting_occluded(void *data, RenderState *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rendermode_lighting_draw(void *data, RenderState *state, PyObject *src, PyObject *mask) {
|
rendermode_lighting_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
|
||||||
RenderModeLighting* self;
|
RenderModeLighting* self;
|
||||||
int x, y, z;
|
int x, y, z;
|
||||||
|
|
||||||
/* first, chain up */
|
/* first, chain up */
|
||||||
rendermode_normal.draw(data, state, src, mask);
|
rendermode_normal.draw(data, state, src, mask, mask_light);
|
||||||
|
|
||||||
self = (RenderModeLighting *)data;
|
self = (RenderModeLighting *)data;
|
||||||
x = state->x, y = state->y, z = state->z;
|
x = state->x, y = state->y, z = state->z;
|
||||||
|
|
||||||
if (is_transparent(state->block)) {
|
if (is_transparent(state->block)) {
|
||||||
/* transparent: do shading on whole block */
|
/* transparent: do shading on whole block */
|
||||||
do_shading_with_mask(self, state, x, y, z, mask);
|
do_shading_with_mask(self, state, x, y, z, mask_light);
|
||||||
} else {
|
} else {
|
||||||
/* opaque: do per-face shading */
|
/* opaque: do per-face shading */
|
||||||
do_shading_with_mask(self, state, x, y, z+1, self->facemasks[0]);
|
do_shading_with_mask(self, state, x, y, z+1, self->facemasks[0]);
|
||||||
|
|||||||
@@ -54,9 +54,9 @@ rendermode_night_occluded(void *data, RenderState *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rendermode_night_draw(void *data, RenderState *state, PyObject *src, PyObject *mask) {
|
rendermode_night_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
|
||||||
/* nothing special to do */
|
/* nothing special to do */
|
||||||
rendermode_lighting.draw(data, state, src, mask);
|
rendermode_lighting.draw(data, state, src, mask, mask_light);
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderModeInterface rendermode_night = {
|
RenderModeInterface rendermode_night = {
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ rendermode_normal_start(void *data, RenderState *state) {
|
|||||||
|
|
||||||
self->leaf_texture = NULL;
|
self->leaf_texture = NULL;
|
||||||
self->grass_texture = NULL;
|
self->grass_texture = NULL;
|
||||||
|
self->tall_grass_texture = NULL;
|
||||||
self->facemask_top = NULL;
|
self->facemask_top = NULL;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@@ -64,6 +65,8 @@ rendermode_normal_start(void *data, RenderState *state) {
|
|||||||
|
|
||||||
self->leaf_texture = PyObject_GetAttrString(state->textures, "biome_leaf_texture");
|
self->leaf_texture = PyObject_GetAttrString(state->textures, "biome_leaf_texture");
|
||||||
self->grass_texture = PyObject_GetAttrString(state->textures, "biome_grass_texture");
|
self->grass_texture = PyObject_GetAttrString(state->textures, "biome_grass_texture");
|
||||||
|
self->tall_grass_texture = PyObject_GetAttrString(state->textures, "biome_tall_grass_texture");
|
||||||
|
self->tall_fern_texture = PyObject_GetAttrString(state->textures, "biome_tall_fern_texture");
|
||||||
|
|
||||||
facemasks_py = PyObject_GetAttrString(state->chunk, "facemasks");
|
facemasks_py = PyObject_GetAttrString(state->chunk, "facemasks");
|
||||||
/* borrowed reference, needs to be incref'd if we keep it */
|
/* borrowed reference, needs to be incref'd if we keep it */
|
||||||
@@ -78,6 +81,8 @@ rendermode_normal_start(void *data, RenderState *state) {
|
|||||||
|
|
||||||
self->leaf_texture = NULL;
|
self->leaf_texture = NULL;
|
||||||
self->grass_texture = NULL;
|
self->grass_texture = NULL;
|
||||||
|
self->tall_grass_texture = NULL;
|
||||||
|
self->tall_fern_texture = NULL;
|
||||||
self->facemask_top = NULL;
|
self->facemask_top = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,6 +103,8 @@ rendermode_normal_finish(void *data, RenderState *state) {
|
|||||||
Py_XDECREF(self->grasscolor);
|
Py_XDECREF(self->grasscolor);
|
||||||
Py_XDECREF(self->leaf_texture);
|
Py_XDECREF(self->leaf_texture);
|
||||||
Py_XDECREF(self->grass_texture);
|
Py_XDECREF(self->grass_texture);
|
||||||
|
Py_XDECREF(self->tall_grass_texture);
|
||||||
|
Py_XDECREF(self->tall_fern_texture);
|
||||||
Py_XDECREF(self->facemask_top);
|
Py_XDECREF(self->facemask_top);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,12 +123,28 @@ rendermode_normal_occluded(void *data, RenderState *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject *mask) {
|
rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
|
||||||
RenderModeNormal *self = (RenderModeNormal *)data;
|
RenderModeNormal *self = (RenderModeNormal *)data;
|
||||||
|
int randx = 0,randy = 0;
|
||||||
|
unsigned char data_byte;
|
||||||
|
|
||||||
/* first, check to see if we should use biome-compatible src, mask */
|
/* first, check to see if we should use biome-compatible src, mask */
|
||||||
if (self->biome_data && state->block == 18) {
|
if (self->biome_data) {
|
||||||
src = mask = self->leaf_texture;
|
if (state->block == 18) {
|
||||||
|
src = mask = self->leaf_texture;
|
||||||
|
} else if (state->block == 31) {
|
||||||
|
/* add a random offset to the postion of the tall grass to make it more wild */
|
||||||
|
randx = rand() % 6 + 1 - 3;
|
||||||
|
randy = rand() % 6 + 1 - 3;
|
||||||
|
state->imgx = state->imgx + randx;
|
||||||
|
state->imgy = state->imgy + randy;
|
||||||
|
data_byte = getArrayByte3D(state->blockdata_expanded, state->x, state->y, state->z);
|
||||||
|
if (data_byte == 1) {
|
||||||
|
src = mask = self->tall_grass_texture;
|
||||||
|
} else if (data_byte == 2) {
|
||||||
|
src = mask = self->tall_fern_texture;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* draw the block! */
|
/* draw the block! */
|
||||||
@@ -150,6 +173,15 @@ rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject *
|
|||||||
color = PySequence_GetItem(self->foliagecolor, index);
|
color = PySequence_GetItem(self->foliagecolor, index);
|
||||||
facemask = mask;
|
facemask = mask;
|
||||||
break;
|
break;
|
||||||
|
case 31:
|
||||||
|
/* tall grass */
|
||||||
|
if ( getArrayByte3D(state->blockdata_expanded, state->x, state->y, state->z) != 0 )
|
||||||
|
{ /* do not tint dead shrubs */
|
||||||
|
color = PySequence_GetItem(self->grasscolor, index);
|
||||||
|
facemask = mask;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ rendermode_overlay_occluded(void *data, RenderState *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rendermode_overlay_draw(void *data, RenderState *state, PyObject *src, PyObject *mask) {
|
rendermode_overlay_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
|
||||||
RenderModeOverlay *self = (RenderModeOverlay *)data;
|
RenderModeOverlay *self = (RenderModeOverlay *)data;
|
||||||
unsigned char r, g, b, a;
|
unsigned char r, g, b, a;
|
||||||
PyObject *top_block_py, *block_py;
|
PyObject *top_block_py, *block_py;
|
||||||
|
|||||||
@@ -102,9 +102,9 @@ rendermode_spawn_occluded(void *data, RenderState *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rendermode_spawn_draw(void *data, RenderState *state, PyObject *src, PyObject *mask) {
|
rendermode_spawn_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
|
||||||
/* draw normally */
|
/* draw normally */
|
||||||
rendermode_overlay.draw(data, state, src, mask);
|
rendermode_overlay.draw(data, state, src, mask, mask_light);
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderModeInterface rendermode_spawn = {
|
RenderModeInterface rendermode_spawn = {
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ struct _RenderModeInterface {
|
|||||||
/* returns non-zero to skip rendering this block */
|
/* returns non-zero to skip rendering this block */
|
||||||
int (*occluded)(void *, RenderState *);
|
int (*occluded)(void *, RenderState *);
|
||||||
/* last two arguments are img and mask, from texture lookup */
|
/* last two arguments are img and mask, from texture lookup */
|
||||||
void (*draw)(void *, RenderState *, PyObject *, PyObject *);
|
void (*draw)(void *, RenderState *, PyObject *, PyObject *, PyObject *);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* figures out the render mode to use from the given ChunkRenderer */
|
/* figures out the render mode to use from the given ChunkRenderer */
|
||||||
@@ -79,7 +79,7 @@ typedef struct {
|
|||||||
/* grasscolor and foliagecolor lookup tables */
|
/* grasscolor and foliagecolor lookup tables */
|
||||||
PyObject *grasscolor, *foliagecolor;
|
PyObject *grasscolor, *foliagecolor;
|
||||||
/* biome-compatible grass/leaf textures */
|
/* biome-compatible grass/leaf textures */
|
||||||
PyObject *grass_texture, *leaf_texture;
|
PyObject *grass_texture, *leaf_texture, *tall_grass_texture, *tall_fern_texture;
|
||||||
/* top facemask for grass biome tinting */
|
/* top facemask for grass biome tinting */
|
||||||
PyObject *facemask_top;
|
PyObject *facemask_top;
|
||||||
} RenderModeNormal;
|
} RenderModeNormal;
|
||||||
@@ -118,7 +118,7 @@ typedef struct {
|
|||||||
} RenderModeLighting;
|
} RenderModeLighting;
|
||||||
extern RenderModeInterface rendermode_lighting;
|
extern RenderModeInterface rendermode_lighting;
|
||||||
inline float get_lighting_coefficient(RenderModeLighting *self, RenderState *state,
|
inline float get_lighting_coefficient(RenderModeLighting *self, RenderState *state,
|
||||||
int x, int y, int z, int *authoratative);
|
int x, int y, int z);
|
||||||
|
|
||||||
/* NIGHT */
|
/* NIGHT */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
309
textures.py
309
textures.py
@@ -236,7 +236,8 @@ def _build_block(top, side, blockID=None):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
img = Image.new("RGBA", (24,24), (38,92,255,0))
|
img = Image.new("RGBA", (24,24), (38,92,255,0))
|
||||||
|
|
||||||
|
original_texture = top.copy()
|
||||||
top = transform_image(top, blockID)
|
top = transform_image(top, blockID)
|
||||||
|
|
||||||
if not side:
|
if not side:
|
||||||
@@ -256,6 +257,12 @@ def _build_block(top, side, blockID=None):
|
|||||||
otherside = ImageEnhance.Brightness(otherside).enhance(0.8)
|
otherside = ImageEnhance.Brightness(otherside).enhance(0.8)
|
||||||
otherside.putalpha(othersidealpha)
|
otherside.putalpha(othersidealpha)
|
||||||
|
|
||||||
|
## special case for tall-grass, fern and dead shrub,
|
||||||
|
if blockID in (31,32):
|
||||||
|
front = original_texture.resize((14,11), Image.ANTIALIAS)
|
||||||
|
composite.alpha_over(img, front, (5,9))
|
||||||
|
return img
|
||||||
|
|
||||||
## special case for non-block things
|
## special case for non-block things
|
||||||
if blockID in (37,38,6,39,40,83,30): ## flowers, sapling, mushrooms, reeds, web
|
if blockID in (37,38,6,39,40,83,30): ## flowers, sapling, mushrooms, reeds, web
|
||||||
#
|
#
|
||||||
@@ -265,7 +272,6 @@ def _build_block(top, side, blockID=None):
|
|||||||
composite.alpha_over(img, 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!
|
||||||
composite.alpha_over(img, side, (1,6), side)
|
composite.alpha_over(img, side, (1,6), side)
|
||||||
composite.alpha_over(img, otherside, (11,6), otherside)
|
composite.alpha_over(img, otherside, (11,6), otherside)
|
||||||
@@ -410,7 +416,7 @@ def _build_blockimages():
|
|||||||
# 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
# 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
||||||
34, -1, 52, 48, 49,160,144, -1,176, 74, -1, -1, -1, -1, 11, -1,
|
34, -1, 52, 48, 49,160,144, -1,176, 74, -1, -1, -1, -1, 11, -1,
|
||||||
# 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
|
# 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, 9, 4,
|
55, -1, -1, -1, -1, 13, 12, 29, 28, 23, 22, -1, -1, 7, 9, 4,
|
||||||
# 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
# 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
||||||
36, 37, -1, -1, 65, -1, -1, -1, 50, 24, -1, -1, 86, -1, -1, -1,
|
36, 37, -1, -1, 65, -1, -1, -1, 50, 24, -1, -1, 86, -1, -1, -1,
|
||||||
# 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
|
# 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
|
||||||
@@ -427,7 +433,7 @@ def _build_blockimages():
|
|||||||
# 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
# 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
||||||
34, -1, 52, 48, 49,160,144, -1,192, 74, -1, -1,- 1, -1, 11, -1,
|
34, -1, 52, 48, 49,160,144, -1,192, 74, -1, -1,- 1, -1, 11, -1,
|
||||||
# 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
|
# 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,
|
55, -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
|
# 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
||||||
36, 37, -1, -1, 65, -1, -1,101, 50, 24, -1, -1, 86, -1, -1, -1,
|
36, 37, -1, -1, 65, -1, -1,101, 50, 24, -1, -1, 86, -1, -1, -1,
|
||||||
# 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
|
# 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
|
||||||
@@ -453,7 +459,7 @@ def _build_blockimages():
|
|||||||
## of the block or the texture ID
|
## of the block or the texture ID
|
||||||
img = _build_block(toptexture, sidetexture, blockID)
|
img = _build_block(toptexture, sidetexture, blockID)
|
||||||
|
|
||||||
allimages.append((img.convert("RGB"), img.split()[3]))
|
allimages.append(generate_texture_tuple(img, blockID))
|
||||||
|
|
||||||
# Future block types:
|
# Future block types:
|
||||||
while len(allimages) < 256:
|
while len(allimages) < 256:
|
||||||
@@ -472,15 +478,28 @@ def load_water():
|
|||||||
|
|
||||||
watertexture = _load_image("water.png")
|
watertexture = _load_image("water.png")
|
||||||
w1 = _build_block(watertexture, None)
|
w1 = _build_block(watertexture, None)
|
||||||
blockmap[9] = w1.convert("RGB"), w1
|
blockmap[9] = generate_texture_tuple(w1,9)
|
||||||
w2 = _build_block(watertexture, watertexture)
|
w2 = _build_block(watertexture, watertexture)
|
||||||
blockmap[8] = w2.convert("RGB"), w2
|
blockmap[8] = generate_texture_tuple(w2,8)
|
||||||
|
|
||||||
lavatexture = _load_image("lava.png")
|
lavatexture = _load_image("lava.png")
|
||||||
lavablock = _build_block(lavatexture, lavatexture)
|
lavablock = _build_block(lavatexture, lavatexture)
|
||||||
blockmap[10] = lavablock.convert("RGB"), lavablock
|
blockmap[10] = generate_texture_tuple(lavablock,10)
|
||||||
blockmap[11] = blockmap[10]
|
blockmap[11] = blockmap[10]
|
||||||
|
|
||||||
|
def generate_opaque_mask(img):
|
||||||
|
""" Takes the alpha channel of the image and generates a mask
|
||||||
|
(used for lighting the block) that deprecates values of alpha
|
||||||
|
smallers than 50, and sets every other value to 255. """
|
||||||
|
|
||||||
|
alpha = img.split()[3]
|
||||||
|
return alpha.point(lambda a: int(min(a, 25.5) * 10))
|
||||||
|
|
||||||
|
def generate_texture_tuple(img, blockid):
|
||||||
|
""" This takes an image and returns the needed tuple for the
|
||||||
|
blockmap list and specialblockmap dictionary."""
|
||||||
|
return (img.convert("RGB"), img.split()[3], generate_opaque_mask(img))
|
||||||
|
|
||||||
def generate_special_texture(blockID, data):
|
def generate_special_texture(blockID, data):
|
||||||
"""Generates a special texture, such as a correctly facing minecraft track"""
|
"""Generates a special texture, such as a correctly facing minecraft track"""
|
||||||
#print "%s has ancillary data: %X" %(blockID, data)
|
#print "%s has ancillary data: %X" %(blockID, data)
|
||||||
@@ -496,7 +515,7 @@ def generate_special_texture(blockID, data):
|
|||||||
if not data & 0x10:
|
if not data & 0x10:
|
||||||
colored = tintTexture(biome_grass_texture, (115, 175, 71))
|
colored = tintTexture(biome_grass_texture, (115, 175, 71))
|
||||||
composite.alpha_over(img, colored, (0, 0), colored)
|
composite.alpha_over(img, colored, (0, 0), colored)
|
||||||
return (img.convert("RGB"), img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID == 6: # saplings
|
if blockID == 6: # saplings
|
||||||
@@ -520,7 +539,7 @@ def generate_special_texture(blockID, data):
|
|||||||
sidetexture = terrain_images[15]
|
sidetexture = terrain_images[15]
|
||||||
|
|
||||||
img = _build_block(toptexture, sidetexture, blockID)
|
img = _build_block(toptexture, sidetexture, blockID)
|
||||||
return (img.convert("RGB"),img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID == 9: # spring water, flowing water and waterfall water
|
if blockID == 9: # spring water, flowing water and waterfall water
|
||||||
@@ -548,9 +567,9 @@ def generate_special_texture(blockID, data):
|
|||||||
side4 = watertexture # bottom right
|
side4 = watertexture # bottom right
|
||||||
else: side4 = None
|
else: side4 = None
|
||||||
|
|
||||||
img = _build_full_block(top,side1,side2,side3,side4)
|
img = _build_full_block(top,None,None,side3,side4)
|
||||||
|
|
||||||
return (img.convert("RGB"),img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID == 17: # wood: normal, birch and pines
|
if blockID == 17: # wood: normal, birch and pines
|
||||||
@@ -558,21 +577,20 @@ def generate_special_texture(blockID, data):
|
|||||||
if data == 0:
|
if data == 0:
|
||||||
side = terrain_images[20]
|
side = terrain_images[20]
|
||||||
img = _build_block(top, side, 17)
|
img = _build_block(top, side, 17)
|
||||||
return (img.convert("RGB"), img.split()[3])
|
|
||||||
if data == 1:
|
if data == 1:
|
||||||
side = terrain_images[116]
|
side = terrain_images[116]
|
||||||
img = _build_block(top, side, 17)
|
img = _build_block(top, side, 17)
|
||||||
return (img.convert("RGB"), img.split()[3])
|
|
||||||
if data == 2:
|
if data == 2:
|
||||||
side = terrain_images[117]
|
side = terrain_images[117]
|
||||||
img = _build_block(top, side, 17)
|
img = _build_block(top, side, 17)
|
||||||
return (img.convert("RGB"), img.split()[3])
|
|
||||||
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID == 18: # leaves
|
if blockID == 18: # leaves
|
||||||
t = tintTexture(terrain_images[52], (37, 118, 25))
|
t = tintTexture(terrain_images[52], (37, 118, 25))
|
||||||
img = _build_block(t, t, 18)
|
img = _build_block(t, t, 18)
|
||||||
return (img.convert("RGB"), img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID == 26: # bed
|
if blockID == 26: # bed
|
||||||
@@ -618,74 +636,58 @@ def generate_special_texture(blockID, data):
|
|||||||
top = (top, increment)
|
top = (top, increment)
|
||||||
img = _build_full_block(top, None, None, left_face, right_face)
|
img = _build_full_block(top, None, None, left_face, right_face)
|
||||||
|
|
||||||
return (img.convert("RGB"), img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
|
if blockID == 31: # tall grass
|
||||||
|
if data == 0: # dead shrub
|
||||||
|
texture = terrain_images[55]
|
||||||
|
elif data == 1: # tall grass
|
||||||
|
texture = terrain_images[39].copy()
|
||||||
|
texture = tintTexture(texture, (115, 175, 71))
|
||||||
|
elif data == 2: # fern
|
||||||
|
texture = terrain_images[56].copy()
|
||||||
|
texture = tintTexture(texture, (115, 175, 71))
|
||||||
|
|
||||||
|
img = _build_block(texture, texture, blockID)
|
||||||
|
return generate_texture_tuple(img,31)
|
||||||
|
|
||||||
|
|
||||||
if blockID == 35: # wool
|
if blockID == 35: # wool
|
||||||
if data == 0: # white
|
if data == 0: # white
|
||||||
top = side = terrain_images[64]
|
top = side = terrain_images[64]
|
||||||
img = _build_block(top, side, 35)
|
elif data == 1: # orange
|
||||||
return (img.convert("RGB"), img.split()[3])
|
|
||||||
if data == 1: # orange
|
|
||||||
top = side = terrain_images[210]
|
top = side = terrain_images[210]
|
||||||
img = _build_block(top, side, 35)
|
elif data == 2: # magenta
|
||||||
return (img.convert("RGB"), img.split()[3])
|
|
||||||
if data == 2: # magenta
|
|
||||||
top = side = terrain_images[194]
|
top = side = terrain_images[194]
|
||||||
img = _build_block(top, side, 35)
|
elif data == 3: # light blue
|
||||||
return (img.convert("RGB"), img.split()[3])
|
|
||||||
if data == 3: # light blue
|
|
||||||
top = side = terrain_images[178]
|
top = side = terrain_images[178]
|
||||||
img = _build_block(top, side, 35)
|
elif data == 4: # yellow
|
||||||
return (img.convert("RGB"), img.split()[3])
|
|
||||||
if data == 4: # yellow
|
|
||||||
top = side = terrain_images[162]
|
top = side = terrain_images[162]
|
||||||
img = _build_block(top, side, 35)
|
elif data == 5: # light green
|
||||||
return (img.convert("RGB"), img.split()[3])
|
|
||||||
if data == 5: # light green
|
|
||||||
top = side = terrain_images[146]
|
top = side = terrain_images[146]
|
||||||
img = _build_block(top, side, 35)
|
elif data == 6: # pink
|
||||||
return (img.convert("RGB"), img.split()[3])
|
|
||||||
if data == 6: # pink
|
|
||||||
top = side = terrain_images[130]
|
top = side = terrain_images[130]
|
||||||
img = _build_block(top, side, 35)
|
elif data == 7: # grey
|
||||||
return (img.convert("RGB"), img.split()[3])
|
|
||||||
if data == 7: # grey
|
|
||||||
top = side = terrain_images[114]
|
top = side = terrain_images[114]
|
||||||
img = _build_block(top, side, 35)
|
elif data == 8: # light grey
|
||||||
return (img.convert("RGB"), img.split()[3])
|
|
||||||
if data == 8: # light grey
|
|
||||||
top = side = terrain_images[225]
|
top = side = terrain_images[225]
|
||||||
img = _build_block(top, side, 35)
|
elif data == 9: # cyan
|
||||||
return (img.convert("RGB"), img.split()[3])
|
|
||||||
if data == 9: # cyan
|
|
||||||
top = side = terrain_images[209]
|
top = side = terrain_images[209]
|
||||||
img = _build_block(top, side, 35)
|
elif data == 10: # purple
|
||||||
return (img.convert("RGB"), img.split()[3])
|
|
||||||
if data == 10: # purple
|
|
||||||
top = side = terrain_images[193]
|
top = side = terrain_images[193]
|
||||||
img = _build_block(top, side, 35)
|
elif data == 11: # blue
|
||||||
return (img.convert("RGB"), img.split()[3])
|
|
||||||
if data == 11: # blue
|
|
||||||
top = side = terrain_images[177]
|
top = side = terrain_images[177]
|
||||||
img = _build_block(top, side, 35)
|
elif data == 12: # brown
|
||||||
return (img.convert("RGB"), img.split()[3])
|
|
||||||
if data == 12: # brown
|
|
||||||
top = side = terrain_images[161]
|
top = side = terrain_images[161]
|
||||||
img = _build_block(top, side, 35)
|
elif data == 13: # dark green
|
||||||
return (img.convert("RGB"), img.split()[3])
|
|
||||||
if data == 13: # dark green
|
|
||||||
top = side = terrain_images[145]
|
top = side = terrain_images[145]
|
||||||
img = _build_block(top, side, 35)
|
elif data == 14: # red
|
||||||
return (img.convert("RGB"), img.split()[3])
|
|
||||||
if data == 14: # red
|
|
||||||
top = side = terrain_images[129]
|
top = side = terrain_images[129]
|
||||||
img = _build_block(top, side, 35)
|
elif data == 15: # black
|
||||||
return (img.convert("RGB"), img.split()[3])
|
|
||||||
if data == 15: # black
|
|
||||||
top = side = terrain_images[113]
|
top = side = terrain_images[113]
|
||||||
img = _build_block(top, side, 35)
|
|
||||||
return (img.convert("RGB"), img.split()[3])
|
img = _build_block(top, side, 35)
|
||||||
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID in (43,44): # slab and double-slab
|
if blockID in (43,44): # slab and double-slab
|
||||||
@@ -693,24 +695,16 @@ def generate_special_texture(blockID, data):
|
|||||||
if data == 0: # stone slab
|
if data == 0: # stone slab
|
||||||
top = terrain_images[6]
|
top = terrain_images[6]
|
||||||
side = terrain_images[5]
|
side = terrain_images[5]
|
||||||
img = _build_block(top, side, blockID)
|
|
||||||
return (img.convert("RGB"), img.split()[3])
|
|
||||||
|
|
||||||
if data == 1: # stone slab
|
if data == 1: # stone slab
|
||||||
top = terrain_images[176]
|
top = terrain_images[176]
|
||||||
side = terrain_images[192]
|
side = terrain_images[192]
|
||||||
img = _build_block(top, side, blockID)
|
|
||||||
return (img.convert("RGB"), img.split()[3])
|
|
||||||
|
|
||||||
if data == 2: # wooden slab
|
if data == 2: # wooden slab
|
||||||
top = side = terrain_images[4]
|
top = side = terrain_images[4]
|
||||||
img = _build_block(top, side, blockID)
|
|
||||||
return (img.convert("RGB"), img.split()[3])
|
|
||||||
|
|
||||||
if data == 3: # cobblestone slab
|
if data == 3: # cobblestone slab
|
||||||
top = side = terrain_images[16]
|
top = side = terrain_images[16]
|
||||||
img = _build_block(top, side, blockID)
|
|
||||||
return (img.convert("RGB"), img.split()[3])
|
img = _build_block(top, side, blockID)
|
||||||
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID in (50,75,76): # torch, off redstone torch, on redstone torch
|
if blockID in (50,75,76): # torch, off redstone torch, on redstone torch
|
||||||
@@ -763,7 +757,7 @@ def generate_special_texture(blockID, data):
|
|||||||
composite.alpha_over(img, small_crop, (6,5))
|
composite.alpha_over(img, small_crop, (6,5))
|
||||||
composite.alpha_over(img, slice, (6,6))
|
composite.alpha_over(img, slice, (6,6))
|
||||||
|
|
||||||
return (img.convert("RGB"), img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID == 51: # fire
|
if blockID == 51: # fire
|
||||||
@@ -779,7 +773,7 @@ def generate_special_texture(blockID, data):
|
|||||||
composite.alpha_over(img, side1, (0,6), side1)
|
composite.alpha_over(img, side1, (0,6), side1)
|
||||||
composite.alpha_over(img, side2, (12,6), side2)
|
composite.alpha_over(img, side2, (12,6), side2)
|
||||||
|
|
||||||
return (img.convert("RGB"), img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID in (53,67): # wooden and cobblestone stairs.
|
if blockID in (53,67): # wooden and cobblestone stairs.
|
||||||
@@ -848,7 +842,7 @@ def generate_special_texture(blockID, data):
|
|||||||
# touch up a (horrible) pixel
|
# touch up a (horrible) pixel
|
||||||
img.putpixel((18,3),(0,0,0,0))
|
img.putpixel((18,3),(0,0,0,0))
|
||||||
|
|
||||||
return (img.convert("RGB"), img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
if blockID == 54: # chests
|
if blockID == 54: # chests
|
||||||
# First to bits of the pseudo data store if it's a single chest
|
# First to bits of the pseudo data store if it's a single chest
|
||||||
@@ -890,7 +884,7 @@ def generate_special_texture(blockID, data):
|
|||||||
else:
|
else:
|
||||||
img = _build_full_block(top, None, None, back, side)
|
img = _build_full_block(top, None, None, back, side)
|
||||||
|
|
||||||
return (img.convert("RGB"), img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID == 55: # redstone wire
|
if blockID == 55: # redstone wire
|
||||||
@@ -968,7 +962,7 @@ def generate_special_texture(blockID, data):
|
|||||||
|
|
||||||
img = _build_full_block(None,side1,side2,None,None,bottom)
|
img = _build_full_block(None,side1,side2,None,None,bottom)
|
||||||
|
|
||||||
return (img.convert("RGB"),img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID == 58: # crafting table
|
if blockID == 58: # crafting table
|
||||||
@@ -977,7 +971,7 @@ def generate_special_texture(blockID, data):
|
|||||||
side4 = terrain_images[43+16+1]
|
side4 = terrain_images[43+16+1]
|
||||||
|
|
||||||
img = _build_full_block(top, None, None, side3, side4, None, 58)
|
img = _build_full_block(top, None, None, side3, side4, None, 58)
|
||||||
return (img.convert("RGB"), img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID == 59: # crops
|
if blockID == 59: # crops
|
||||||
@@ -990,7 +984,7 @@ def generate_special_texture(blockID, data):
|
|||||||
composite.alpha_over(img, crop1, (0,12), crop1)
|
composite.alpha_over(img, crop1, (0,12), crop1)
|
||||||
composite.alpha_over(img, crop2, (6,3), crop2)
|
composite.alpha_over(img, crop2, (6,3), crop2)
|
||||||
composite.alpha_over(img, crop3, (6,3), crop3)
|
composite.alpha_over(img, crop3, (6,3), crop3)
|
||||||
return (img.convert("RGB"), img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID in (61, 62, 23): #furnace and burning furnace
|
if blockID in (61, 62, 23): #furnace and burning furnace
|
||||||
@@ -1015,7 +1009,7 @@ def generate_special_texture(blockID, data):
|
|||||||
else: # in any other direction the front can't be seen
|
else: # in any other direction the front can't be seen
|
||||||
img = _build_full_block(top, None, None, side, side)
|
img = _build_full_block(top, None, None, side, side)
|
||||||
|
|
||||||
return (img.convert("RGB"), img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID == 63: # singposts
|
if blockID == 63: # singposts
|
||||||
@@ -1058,7 +1052,7 @@ def generate_special_texture(blockID, data):
|
|||||||
composite.alpha_over(img, post2,(incrementx, -3),post2)
|
composite.alpha_over(img, post2,(incrementx, -3),post2)
|
||||||
composite.alpha_over(img, post, (0,-2), post)
|
composite.alpha_over(img, post, (0,-2), post)
|
||||||
|
|
||||||
return (img.convert("RGB"), img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID in (64,71): #wooden door, or iron door
|
if blockID in (64,71): #wooden door, or iron door
|
||||||
@@ -1110,10 +1104,11 @@ def generate_special_texture(blockID, data):
|
|||||||
tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT))
|
tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT))
|
||||||
composite.alpha_over(img, tex, (0,6), tex)
|
composite.alpha_over(img, tex, (0,6), tex)
|
||||||
|
|
||||||
return (img.convert("RGB"), img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID == 65: # ladder
|
if blockID == 65: # ladder
|
||||||
|
img = Image.new("RGBA", (24,24), (38,92,255,0))
|
||||||
raw_texture = terrain_images[83]
|
raw_texture = terrain_images[83]
|
||||||
#print "ladder is facing: %d" % data
|
#print "ladder is facing: %d" % data
|
||||||
if data == 5:
|
if data == 5:
|
||||||
@@ -1121,28 +1116,25 @@ def generate_special_texture(blockID, data):
|
|||||||
# but since ladders can apparently be placed on transparent blocks, we
|
# but since ladders can apparently be placed on transparent blocks, we
|
||||||
# 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))
|
|
||||||
composite.alpha_over(img, tex, (0,6), tex)
|
composite.alpha_over(img, tex, (0,6), tex)
|
||||||
return (img.convert("RGB"), img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
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))
|
|
||||||
composite.alpha_over(img, tex, (12,6), tex)
|
composite.alpha_over(img, tex, (12,6), tex)
|
||||||
return (img.convert("RGB"), img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
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))
|
|
||||||
composite.alpha_over(img, tex, (0,0), tex)
|
composite.alpha_over(img, tex, (0,0), tex)
|
||||||
return (img.convert("RGB"), img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
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))
|
|
||||||
composite.alpha_over(img, tex, (12,0), tex)
|
composite.alpha_over(img, tex, (12,0), tex)
|
||||||
return (img.convert("RGB"), img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID in (27, 28, 66): # minetrack:
|
if blockID in (27, 28, 66): # minetrack:
|
||||||
|
img = Image.new("RGBA", (24,24), (38,92,255,0))
|
||||||
|
|
||||||
if blockID == 27: # powered rail
|
if blockID == 27: # powered rail
|
||||||
if data & 0x8 == 0: # unpowered
|
if data & 0x8 == 0: # unpowered
|
||||||
raw_straight = terrain_images[163]
|
raw_straight = terrain_images[163]
|
||||||
@@ -1165,58 +1157,48 @@ def generate_special_texture(blockID, data):
|
|||||||
## use transform_image to scale and shear
|
## use transform_image to scale and shear
|
||||||
if data == 0:
|
if data == 0:
|
||||||
track = transform_image(raw_straight, blockID)
|
track = transform_image(raw_straight, blockID)
|
||||||
|
composite.alpha_over(img, track, (0,12), track)
|
||||||
elif data == 6:
|
elif data == 6:
|
||||||
track = transform_image(raw_corner, blockID)
|
track = transform_image(raw_corner, blockID)
|
||||||
|
composite.alpha_over(img, track, (0,12), track)
|
||||||
elif data == 7:
|
elif data == 7:
|
||||||
track = transform_image(raw_corner.rotate(270), blockID)
|
track = transform_image(raw_corner.rotate(270), blockID)
|
||||||
|
composite.alpha_over(img, track, (0,12), track)
|
||||||
elif data == 8:
|
elif data == 8:
|
||||||
# flip
|
# flip
|
||||||
track = transform_image(raw_corner.transpose(Image.FLIP_TOP_BOTTOM).rotate(90),
|
track = transform_image(raw_corner.transpose(Image.FLIP_TOP_BOTTOM).rotate(90),
|
||||||
blockID)
|
blockID)
|
||||||
|
composite.alpha_over(img, track, (0,12), track)
|
||||||
elif data == 9:
|
elif data == 9:
|
||||||
track = transform_image(raw_corner.transpose(Image.FLIP_TOP_BOTTOM),
|
track = transform_image(raw_corner.transpose(Image.FLIP_TOP_BOTTOM),
|
||||||
blockID)
|
blockID)
|
||||||
|
composite.alpha_over(img, track, (0,12), track)
|
||||||
elif data == 1:
|
elif data == 1:
|
||||||
track = transform_image(raw_straight.rotate(90), blockID)
|
track = transform_image(raw_straight.rotate(90), blockID)
|
||||||
|
composite.alpha_over(img, track, (0,12), track)
|
||||||
|
|
||||||
#slopes
|
#slopes
|
||||||
elif data == 2: # slope going up in +x direction
|
elif data == 2: # slope going up in +x direction
|
||||||
track = transform_image_slope(raw_straight,blockID)
|
track = transform_image_slope(raw_straight,blockID)
|
||||||
track = track.transpose(Image.FLIP_LEFT_RIGHT)
|
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)
|
composite.alpha_over(img, track, (2,0), track)
|
||||||
# the 2 pixels move is needed to fit with the adjacent tracks
|
# 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
|
elif data == 3: # slope going up in -x direction
|
||||||
# tracks are sprites, in this case we are seeing the "side" of
|
# tracks are sprites, in this case we are seeing the "side" of
|
||||||
# the sprite, so draw a line to make it beautiful.
|
# 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))
|
ImageDraw.Draw(img).line([(11,11),(23,17)],fill=(164,164,164))
|
||||||
# grey from track texture (exterior grey).
|
# grey from track texture (exterior grey).
|
||||||
# the track doesn't start from image corners, be carefull drawing the line!
|
# 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
|
elif data == 4: # slope going up in -y direction
|
||||||
track = transform_image_slope(raw_straight,blockID)
|
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)
|
composite.alpha_over(img, track, (0,0), track)
|
||||||
return (img.convert("RGB"), img.split()[3])
|
|
||||||
|
|
||||||
elif data == 5: # slope going up in +y direction
|
elif data == 5: # slope going up in +y direction
|
||||||
# same as "data == 3"
|
# 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))
|
ImageDraw.Draw(img).line([(1,17),(12,11)],fill=(164,164,164))
|
||||||
return (img.convert("RGB"), img.split()[3])
|
|
||||||
|
|
||||||
|
|
||||||
else: # just in case
|
return generate_texture_tuple(img, blockID)
|
||||||
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 == 68: # wall sign
|
if blockID == 68: # wall sign
|
||||||
@@ -1254,28 +1236,28 @@ def generate_special_texture(blockID, data):
|
|||||||
composite.alpha_over(img, sign2,(incrementx, 2),sign2)
|
composite.alpha_over(img, sign2,(incrementx, 2),sign2)
|
||||||
composite.alpha_over(img, sign, (0,3), sign)
|
composite.alpha_over(img, sign, (0,3), sign)
|
||||||
|
|
||||||
return (img.convert("RGB"), img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
if blockID == 85: # fences
|
if blockID == 85: # fences
|
||||||
# create needed images for Big stick fence
|
# create needed images for Big stick fence
|
||||||
raw_texture = terrain_images[4]
|
|
||||||
raw_fence_top = Image.new("RGBA", (16,16), (38,92,255,0))
|
|
||||||
raw_fence_side = Image.new("RGBA", (16,16), (38,92,255,0))
|
|
||||||
fence_top_mask = Image.new("RGBA", (16,16), (38,92,255,0))
|
|
||||||
fence_side_mask = Image.new("RGBA", (16,16), (38,92,255,0))
|
|
||||||
|
|
||||||
# generate the masks images for textures of the fence
|
|
||||||
ImageDraw.Draw(fence_top_mask).rectangle((6,6,9,9),outline=(0,0,0),fill=(0,0,0))
|
|
||||||
ImageDraw.Draw(fence_side_mask).rectangle((6,1,9,15),outline=(0,0,0),fill=(0,0,0))
|
|
||||||
|
|
||||||
# create textures top and side for fence big stick
|
fence_top = terrain_images[4].copy()
|
||||||
composite.alpha_over(raw_fence_top,raw_texture,(0,0),fence_top_mask)
|
fence_side = terrain_images[4].copy()
|
||||||
composite.alpha_over(raw_fence_side,raw_texture,(0,0),fence_side_mask)
|
|
||||||
|
# generate the textures of the fence
|
||||||
|
ImageDraw.Draw(fence_top).rectangle((0,0,5,15),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
|
ImageDraw.Draw(fence_top).rectangle((10,0,15,15),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
|
ImageDraw.Draw(fence_top).rectangle((0,0,15,5),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
|
ImageDraw.Draw(fence_top).rectangle((0,10,15,15),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
|
|
||||||
|
ImageDraw.Draw(fence_side).rectangle((0,0,15,0),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
|
ImageDraw.Draw(fence_side).rectangle((0,0,5,15),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
|
ImageDraw.Draw(fence_side).rectangle((10,0,15,15),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
|
|
||||||
# Create the sides and the top of the big stick
|
# Create the sides and the top of the big stick
|
||||||
fence_side = transform_image_side(raw_fence_side,85)
|
fence_side = transform_image_side(fence_side,85)
|
||||||
fence_other_side = fence_side.transpose(Image.FLIP_LEFT_RIGHT)
|
fence_other_side = fence_side.transpose(Image.FLIP_LEFT_RIGHT)
|
||||||
fence_top = transform_image(raw_fence_top,85)
|
fence_top = transform_image(fence_top,85)
|
||||||
|
|
||||||
# Darken the sides slightly. These methods also affect the alpha layer,
|
# Darken the sides slightly. These methods also affect the alpha layer,
|
||||||
# so save them first (we don't want to "darken" the alpha layer making
|
# so save them first (we don't want to "darken" the alpha layer making
|
||||||
@@ -1295,18 +1277,17 @@ def generate_special_texture(blockID, data):
|
|||||||
|
|
||||||
# Now render the small sticks.
|
# Now render the small sticks.
|
||||||
# Create needed images
|
# Create needed images
|
||||||
raw_fence_small_side = Image.new("RGBA", (16,16), (38,92,255,0))
|
fence_small_side = terrain_images[4].copy()
|
||||||
fence_small_side_mask = Image.new("RGBA", (16,16), (38,92,255,0))
|
|
||||||
|
|
||||||
# Generate mask
|
# Generate mask
|
||||||
ImageDraw.Draw(fence_small_side_mask).rectangle((10,1,15,3),outline=(0,0,0),fill=(0,0,0))
|
ImageDraw.Draw(fence_small_side).rectangle((0,0,15,0),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
ImageDraw.Draw(fence_small_side_mask).rectangle((10,7,15,9),outline=(0,0,0),fill=(0,0,0))
|
ImageDraw.Draw(fence_small_side).rectangle((0,4,15,6),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
|
ImageDraw.Draw(fence_small_side).rectangle((0,10,15,16),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
# create the texture for the side of small sticks fence
|
ImageDraw.Draw(fence_small_side).rectangle((0,0,4,15),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
composite.alpha_over(raw_fence_small_side,raw_texture,(0,0),fence_small_side_mask)
|
ImageDraw.Draw(fence_small_side).rectangle((11,0,15,15),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
|
|
||||||
# Create the sides and the top of the small sticks
|
# Create the sides and the top of the small sticks
|
||||||
fence_small_side = transform_image_side(raw_fence_small_side,85)
|
fence_small_side = transform_image_side(fence_small_side,85)
|
||||||
fence_small_other_side = fence_small_side.transpose(Image.FLIP_LEFT_RIGHT)
|
fence_small_other_side = fence_small_side.transpose(Image.FLIP_LEFT_RIGHT)
|
||||||
|
|
||||||
# Darken the sides slightly. These methods also affect the alpha layer,
|
# Darken the sides slightly. These methods also affect the alpha layer,
|
||||||
@@ -1319,18 +1300,16 @@ def generate_special_texture(blockID, data):
|
|||||||
fence_small_side = ImageEnhance.Brightness(fence_small_side).enhance(0.9)
|
fence_small_side = ImageEnhance.Brightness(fence_small_side).enhance(0.9)
|
||||||
fence_small_side.putalpha(sidealpha)
|
fence_small_side.putalpha(sidealpha)
|
||||||
|
|
||||||
|
|
||||||
# Create img to compose the fence
|
# Create img to compose the fence
|
||||||
|
|
||||||
img = Image.new("RGBA", (24,24), (38,92,255,0))
|
img = Image.new("RGBA", (24,24), (38,92,255,0))
|
||||||
|
|
||||||
# Position of fence small sticks in img.
|
# Position of fence small sticks in img.
|
||||||
# These postitions are strange because the small sticks of the
|
# These postitions are strange because the small sticks of the
|
||||||
# fence are at the very left and at the very right of the 16x16 images
|
# fence are at the very left and at the very right of the 16x16 images
|
||||||
pos_top_left = (-2,0)
|
pos_top_left = (2,3)
|
||||||
pos_top_right = (14,0)
|
pos_top_right = (10,3)
|
||||||
pos_bottom_right = (6,4)
|
pos_bottom_right = (10,7)
|
||||||
pos_bottom_left = (6,4)
|
pos_bottom_left = (2,7)
|
||||||
|
|
||||||
# +x axis points top right direction
|
# +x axis points top right direction
|
||||||
# +y axis points bottom right direction
|
# +y axis points bottom right direction
|
||||||
@@ -1349,7 +1328,7 @@ def generate_special_texture(blockID, data):
|
|||||||
if (data & 0b0100) == 4:
|
if (data & 0b0100) == 4:
|
||||||
composite.alpha_over(img,fence_small_side, pos_bottom_right,fence_small_side) # bottom right
|
composite.alpha_over(img,fence_small_side, pos_bottom_right,fence_small_side) # bottom right
|
||||||
|
|
||||||
return (img.convert("RGB"),img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID in (86,91): # pumpkins, jack-o-lantern
|
if blockID in (86,91): # pumpkins, jack-o-lantern
|
||||||
@@ -1367,7 +1346,7 @@ def generate_special_texture(blockID, data):
|
|||||||
else: # in any other direction the front can't be seen
|
else: # in any other direction the front can't be seen
|
||||||
img = _build_full_block(top, None, None, side, side)
|
img = _build_full_block(top, None, None, side, side)
|
||||||
|
|
||||||
return (img.convert("RGB"), img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID == 90: # portal
|
if blockID == 90: # portal
|
||||||
@@ -1383,7 +1362,7 @@ def generate_special_texture(blockID, data):
|
|||||||
if data in (2,8):
|
if data in (2,8):
|
||||||
composite.alpha_over(img, otherside, (5,4), otherside)
|
composite.alpha_over(img, otherside, (5,4), otherside)
|
||||||
|
|
||||||
return (img.convert("RGB"), img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID == 92: # cake! (without bites, at the moment)
|
if blockID == 92: # cake! (without bites, at the moment)
|
||||||
@@ -1408,7 +1387,7 @@ def generate_special_texture(blockID, data):
|
|||||||
composite.alpha_over(img, otherside, (12,12), otherside)
|
composite.alpha_over(img, otherside, (12,12), otherside)
|
||||||
composite.alpha_over(img, top, (0,6), top)
|
composite.alpha_over(img, top, (0,6), top)
|
||||||
|
|
||||||
return (img.convert("RGB"), img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID in (93, 94): # redstone repeaters, ON and OFF
|
if blockID in (93, 94): # redstone repeaters, ON and OFF
|
||||||
@@ -1526,7 +1505,25 @@ def generate_special_texture(blockID, data):
|
|||||||
composite.alpha_over(img, torch, static_torch, torch)
|
composite.alpha_over(img, torch, static_torch, torch)
|
||||||
composite.alpha_over(img, torch, moving_torch, torch)
|
composite.alpha_over(img, torch, moving_torch, torch)
|
||||||
|
|
||||||
return (img.convert("RGB"), img.split()[3])
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
|
if blockID == 96: # trapdoor
|
||||||
|
texture = terrain_images[84]
|
||||||
|
if data & 0x4 == 0x4: # opened trapdoor
|
||||||
|
if data & 0x3 == 0: # west
|
||||||
|
img = _build_full_block(None, None, None, None, texture)
|
||||||
|
if data & 0x3 == 1: # east
|
||||||
|
img = _build_full_block(None, texture, None, None, None)
|
||||||
|
if data & 0x3 == 2: # south
|
||||||
|
img = _build_full_block(None, None, texture, None, None)
|
||||||
|
if data & 0x3 == 3: # north
|
||||||
|
img = _build_full_block(None, None, None, texture, None)
|
||||||
|
|
||||||
|
elif data & 0x4 == 0: # closed trapdoor
|
||||||
|
img = _build_full_block((texture, 9), None, None, texture, texture)
|
||||||
|
|
||||||
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
return None
|
return None
|
||||||
@@ -1601,9 +1598,9 @@ def getBiomeData(worlddir, chunkX, chunkY):
|
|||||||
# (when adding new blocks here and in generate_special_textures,
|
# (when adding new blocks here and in generate_special_textures,
|
||||||
# please, if possible, keep the ascending order of blockid value)
|
# please, if possible, keep the ascending order of blockid value)
|
||||||
|
|
||||||
special_blocks = set([ 2, 6, 9, 17, 18, 26, 23, 27, 28, 35, 43, 44, 50,
|
special_blocks = set([ 2, 6, 9, 17, 18, 26, 23, 27, 28, 31, 35, 43, 44,
|
||||||
51, 53, 54, 55, 58, 59, 61, 62, 63, 64, 65, 66, 67,
|
50, 51, 53, 54, 55, 58, 59, 61, 62, 63, 64, 65, 66,
|
||||||
68, 71, 75, 76, 85, 86, 90, 91, 92, 93, 94])
|
67, 68, 71, 75, 76, 85, 86, 90, 91, 92, 93, 94, 96])
|
||||||
|
|
||||||
# this is a map of special blockIDs to a list of all
|
# this is a map of special blockIDs to a list of all
|
||||||
# possible values for ancillary data that it might have.
|
# possible values for ancillary data that it might have.
|
||||||
@@ -1612,7 +1609,7 @@ special_map = {}
|
|||||||
|
|
||||||
special_map[6] = range(16) # saplings: usual, spruce, birch and future ones (rendered as usual saplings)
|
special_map[6] = range(16) # saplings: usual, spruce, birch and future ones (rendered as usual saplings)
|
||||||
special_map[9] = range(32) # water: spring,flowing, waterfall, and others (unknown) ancildata values, uses pseudo data
|
special_map[9] = range(32) # water: spring,flowing, waterfall, and others (unknown) ancildata values, uses pseudo data
|
||||||
special_map[17] = range(4) # wood: normal, birch and pine
|
special_map[17] = range(3) # wood: normal, birch and pine
|
||||||
special_map[26] = range(12) # bed, orientation
|
special_map[26] = range(12) # bed, orientation
|
||||||
special_map[23] = range(6) # dispensers, orientation
|
special_map[23] = range(6) # dispensers, orientation
|
||||||
special_map[27] = range(14) # powered rail, orientation/slope and powered/unpowered
|
special_map[27] = range(14) # powered rail, orientation/slope and powered/unpowered
|
||||||
@@ -1645,6 +1642,7 @@ special_map[91] = range(5) # jack-o-lantern, orientation
|
|||||||
special_map[92] = range(6) # cake!
|
special_map[92] = range(6) # cake!
|
||||||
special_map[93] = range(16) # OFF redstone repeater, orientation and delay (delay not implemented)
|
special_map[93] = range(16) # OFF redstone repeater, orientation and delay (delay not implemented)
|
||||||
special_map[94] = range(16) # ON redstone repeater, orientation and delay (delay not implemented)
|
special_map[94] = range(16) # ON redstone repeater, orientation and delay (delay not implemented)
|
||||||
|
special_map[96] = range(8) # trapdoor, open, closed, orientation
|
||||||
|
|
||||||
# grass and leaves are graysacle in terrain.png
|
# grass and leaves are graysacle in terrain.png
|
||||||
# we treat them as special so we can manually tint them
|
# we treat them as special so we can manually tint them
|
||||||
@@ -1655,11 +1653,14 @@ special_map[2] = range(11) + [0x10,] # grass, grass has not ancildata but is
|
|||||||
# small fix shows the map as expected,
|
# small fix shows the map as expected,
|
||||||
# and is harmless for normal maps
|
# and is harmless for normal maps
|
||||||
special_map[18] = range(16) # leaves, birch, normal or pine leaves (not implemented)
|
special_map[18] = range(16) # leaves, birch, normal or pine leaves (not implemented)
|
||||||
|
special_map[31] = range(3) # tall grass, dead shrub, fern and tall grass itself
|
||||||
|
|
||||||
# placeholders that are generated in generate()
|
# placeholders that are generated in generate()
|
||||||
terrain_images = None
|
terrain_images = None
|
||||||
blockmap = None
|
blockmap = None
|
||||||
biome_grass_texture = None
|
biome_grass_texture = None
|
||||||
|
biome_tall_grass_texture = None
|
||||||
|
biome_tall_fern_texture = None
|
||||||
biome_leaf_texture = None
|
biome_leaf_texture = None
|
||||||
specialblockmap = None
|
specialblockmap = None
|
||||||
|
|
||||||
@@ -1677,9 +1678,11 @@ def generate(path=None):
|
|||||||
load_water()
|
load_water()
|
||||||
|
|
||||||
# generate biome (still grayscale) leaf, grass textures
|
# generate biome (still grayscale) leaf, grass textures
|
||||||
global biome_grass_texture, biome_leaf_texture
|
global biome_grass_texture, biome_leaf_texture, biome_tall_grass_texture, biome_tall_fern_texture
|
||||||
biome_grass_texture = _build_block(terrain_images[0], terrain_images[38], 2)
|
biome_grass_texture = _build_block(terrain_images[0], terrain_images[38], 2)
|
||||||
biome_leaf_texture = _build_block(terrain_images[52], terrain_images[52], 18)
|
biome_leaf_texture = _build_block(terrain_images[52], terrain_images[52], 18)
|
||||||
|
biome_tall_grass_texture = _build_block(terrain_images[39], terrain_images[39], 31)
|
||||||
|
biome_tall_fern_texture = _build_block(terrain_images[56], terrain_images[56], 31)
|
||||||
|
|
||||||
# generate the special blocks
|
# generate the special blocks
|
||||||
global specialblockmap, special_blocks
|
global specialblockmap, special_blocks
|
||||||
|
|||||||
BIN
web_assets/control-bg-active.png
Normal file
BIN
web_assets/control-bg-active.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
BIN
web_assets/control-bg.png
Normal file
BIN
web_assets/control-bg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
@@ -7,6 +7,10 @@ body {
|
|||||||
margin: 0px;
|
margin: 0px;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
background-color: #000;
|
background-color: #000;
|
||||||
|
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 160%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#mcmap {
|
#mcmap {
|
||||||
@@ -29,30 +33,52 @@ body {
|
|||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
#customControl {
|
.customControl {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
height: 15px;
|
height: 15px;
|
||||||
|
color: black;
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
#customControl > div#top {
|
.customControl > div.top {
|
||||||
background-color: #fff;
|
|
||||||
border: 2px solid #000;
|
|
||||||
text-align: center;
|
|
||||||
width: 70px;
|
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
width: 70px;
|
line-height: 160%;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0px 6px;
|
||||||
|
|
||||||
|
background-image: url('control-bg.png');
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
|
||||||
|
border: 1px solid #A9BBDF;
|
||||||
|
border-radius: 2px 2px;
|
||||||
|
box-shadow: rgba(0, 0, 0, 0.347656) 2px 2px 3px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
#customControl > div#dropDown {
|
.customControl > div.top:hover {
|
||||||
border: 1px solid #000;
|
border: 1px solid #678AC7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customControl > div.top-active {
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 0px 5px;
|
||||||
|
border: 1px solid #678AC7;
|
||||||
|
background-image: url('control-bg-active.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
.customControl > div.dropDown {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
background-color: #fff;
|
background-color: white;
|
||||||
|
|
||||||
|
border: 1px solid #A9BBDF;
|
||||||
|
border-radius: 2px 2px;
|
||||||
|
box-shadow: rgba(0, 0, 0, 0.347656) 2px 2px 3px;
|
||||||
|
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#customControl > div#button {
|
.customControl > div.button {
|
||||||
border: 1px solid #000;
|
border: 1px solid #000;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
@@ -60,7 +86,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#link {
|
#link, #coordsDiv {
|
||||||
background-color: #fff; /* fallback */
|
background-color: #fff; /* fallback */
|
||||||
background-color: rgba(255,255,255,0.55);
|
background-color: rgba(255,255,255,0.55);
|
||||||
border: 1px solid rgb(0, 0, 0);
|
border: 1px solid rgb(0, 0, 0);
|
||||||
|
|||||||
@@ -560,8 +560,8 @@ var overviewer = {
|
|||||||
|
|
||||||
// Adjust for the fact that we we can't figure out what Y is given
|
// Adjust for the fact that we we can't figure out what Y is given
|
||||||
// only latitude and longitude, so assume Y=64.
|
// only latitude and longitude, so assume Y=64.
|
||||||
point.x += 64 + 1;
|
point.x += 64;
|
||||||
point.z -= 64 + 2;
|
point.z -= 64;
|
||||||
|
|
||||||
return point;
|
return point;
|
||||||
},
|
},
|
||||||
@@ -585,12 +585,23 @@ var overviewer = {
|
|||||||
// Spawn button
|
// Spawn button
|
||||||
var homeControlDiv = document.createElement('DIV');
|
var homeControlDiv = document.createElement('DIV');
|
||||||
var homeControl = new overviewer.classes.HomeControl(homeControlDiv);
|
var homeControl = new overviewer.classes.HomeControl(homeControlDiv);
|
||||||
homeControlDiv.id = 'customControl';
|
$(homeControlDiv).addClass('customControl');
|
||||||
homeControlDiv.index = 1;
|
homeControlDiv.index = 1;
|
||||||
if (overviewerConfig.map.controls.spawn) {
|
if (overviewerConfig.map.controls.spawn) {
|
||||||
overviewer.map.controls[google.maps.ControlPosition.TOP_RIGHT].push(homeControlDiv);
|
overviewer.map.controls[google.maps.ControlPosition.TOP_RIGHT].push(homeControlDiv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Coords box
|
||||||
|
var coordsDiv = document.createElement('DIV');
|
||||||
|
coordsDiv.id = 'coordsDiv';
|
||||||
|
coordsDiv.innerHTML = '';
|
||||||
|
overviewer.map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(coordsDiv);
|
||||||
|
// Update coords on mousemove
|
||||||
|
google.maps.event.addListener(overviewer.map, 'mousemove', function (event) {
|
||||||
|
var worldcoords = overviewer.util.fromLatLngToWorld(event.latLng.lat(), event.latLng.lng());
|
||||||
|
coordsDiv.innerHTML = "Coords: X " + Math.round(worldcoords.x) + ", Z " + Math.round(worldcoords.z);
|
||||||
|
});
|
||||||
|
|
||||||
// only need to create the control if there are items in the list.
|
// only need to create the control if there are items in the list.
|
||||||
// as defined in config.js
|
// as defined in config.js
|
||||||
if (overviewerConfig.objectGroups.signs.length > 0) {
|
if (overviewerConfig.objectGroups.signs.length > 0) {
|
||||||
@@ -598,6 +609,11 @@ var overviewer = {
|
|||||||
var items = [];
|
var items = [];
|
||||||
for (i in overviewerConfig.objectGroups.signs) {
|
for (i in overviewerConfig.objectGroups.signs) {
|
||||||
var signGroup = overviewerConfig.objectGroups.signs[i];
|
var signGroup = overviewerConfig.objectGroups.signs[i];
|
||||||
|
// don't create an option for this group if empty
|
||||||
|
if (overviewer.collections.markers[signGroup.label].length == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
var iconURL = signGroup.icon;
|
var iconURL = signGroup.icon;
|
||||||
if(!iconURL) {
|
if(!iconURL) {
|
||||||
iconURL = overviewerConfig.CONST.image.defaultMarker;
|
iconURL = overviewerConfig.CONST.image.defaultMarker;
|
||||||
@@ -616,7 +632,11 @@ var overviewer = {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
overviewer.util.createDropDown('Signposts', items);
|
|
||||||
|
// only create drop down if there's used options
|
||||||
|
if (items.length > 0) {
|
||||||
|
overviewer.util.createDropDown('Signposts', items);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there are any regions data, lets show the option to hide/show them.
|
// if there are any regions data, lets show the option to hide/show them.
|
||||||
@@ -680,23 +700,24 @@ var overviewer = {
|
|||||||
'createDropDown': function(title, items) {
|
'createDropDown': function(title, items) {
|
||||||
var control = document.createElement('DIV');
|
var control = document.createElement('DIV');
|
||||||
// let's let a style sheet do most of the styling here
|
// let's let a style sheet do most of the styling here
|
||||||
control.id = 'customControl';
|
$(control).addClass('customControl');
|
||||||
|
|
||||||
var controlText = document.createElement('DIV');
|
var controlText = document.createElement('DIV');
|
||||||
controlText.innerHTML = title;
|
controlText.innerHTML = title;
|
||||||
|
|
||||||
var controlBorder = document.createElement('DIV');
|
var controlBorder = document.createElement('DIV');
|
||||||
controlBorder.id='top';
|
$(controlBorder).addClass('top');
|
||||||
control.appendChild(controlBorder);
|
control.appendChild(controlBorder);
|
||||||
controlBorder.appendChild(controlText);
|
controlBorder.appendChild(controlText);
|
||||||
|
|
||||||
var dropdownDiv = document.createElement('DIV');
|
var dropdownDiv = document.createElement('DIV');
|
||||||
dropdownDiv.id='dropDown';
|
$(dropdownDiv).addClass('dropDown');
|
||||||
control.appendChild(dropdownDiv);
|
control.appendChild(dropdownDiv);
|
||||||
dropdownDiv.innerHTML='';
|
dropdownDiv.innerHTML='';
|
||||||
|
|
||||||
// add the functionality to toggle visibility of the items
|
// add the functionality to toggle visibility of the items
|
||||||
$(controlText).click(function() {
|
$(controlText).click(function() {
|
||||||
|
$(controlBorder).toggleClass('top-active');
|
||||||
$(dropdownDiv).toggle();
|
$(dropdownDiv).toggle();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -868,14 +889,14 @@ var overviewer = {
|
|||||||
controlDiv.style.padding = '5px';
|
controlDiv.style.padding = '5px';
|
||||||
// Set CSS for the control border
|
// Set CSS for the control border
|
||||||
var control = document.createElement('DIV');
|
var control = document.createElement('DIV');
|
||||||
control.id='top';
|
$(control).addClass('top');
|
||||||
control.title = 'Click to center the map on the Spawn';
|
control.title = 'Click to center the map on the Spawn';
|
||||||
controlDiv.appendChild(control);
|
controlDiv.appendChild(control);
|
||||||
|
|
||||||
// Set CSS for the control interior
|
// Set CSS for the control interior
|
||||||
var controlText = document.createElement('DIV');
|
var controlText = document.createElement('DIV');
|
||||||
controlText.innerHTML = 'Spawn';
|
controlText.innerHTML = 'Spawn';
|
||||||
controlText.id='button';
|
$(controlText).addClass('button');
|
||||||
control.appendChild(controlText);
|
control.appendChild(controlText);
|
||||||
|
|
||||||
// Setup the click event listeners: simply set the map to map center
|
// Setup the click event listeners: simply set the map to map center
|
||||||
|
|||||||
40
world.py
40
world.py
@@ -78,7 +78,10 @@ class World(object):
|
|||||||
logging.info("Scanning regions")
|
logging.info("Scanning regions")
|
||||||
regionfiles = {}
|
regionfiles = {}
|
||||||
self.regions = {}
|
self.regions = {}
|
||||||
self.regionlist = regionlist # a list of paths
|
if regionlist:
|
||||||
|
self.regionlist = map(os.path.abspath, regionlist) # a list of paths
|
||||||
|
else:
|
||||||
|
self.regionlist = None
|
||||||
for x, y, regionfile in self._iterate_regionfiles():
|
for x, y, regionfile in self._iterate_regionfiles():
|
||||||
mcr = self.reload_region(regionfile)
|
mcr = self.reload_region(regionfile)
|
||||||
mcr.get_chunk_info()
|
mcr.get_chunk_info()
|
||||||
@@ -100,9 +103,6 @@ class World(object):
|
|||||||
logging.error("Sorry, This version of Minecraft-Overviewer only works with the new McRegion chunk format")
|
logging.error("Sorry, This version of Minecraft-Overviewer only works with the new McRegion chunk format")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if self.useBiomeData:
|
|
||||||
textures.prepareBiomeData(worlddir)
|
|
||||||
|
|
||||||
# stores Points Of Interest to be mapped with markers
|
# stores Points Of Interest to be mapped with markers
|
||||||
# a list of dictionaries, see below for an example
|
# a list of dictionaries, see below for an example
|
||||||
self.POI = []
|
self.POI = []
|
||||||
@@ -211,23 +211,25 @@ class World(object):
|
|||||||
|
|
||||||
## The filename of this chunk
|
## The filename of this chunk
|
||||||
chunkFile = self.get_region_path(chunkX, chunkY)
|
chunkFile = self.get_region_path(chunkX, chunkY)
|
||||||
|
|
||||||
data=nbt.load_from_region(chunkFile, chunkX, chunkY)[1]
|
if chunkFile is not None:
|
||||||
level = data['Level']
|
data = nbt.load_from_region(chunkFile, chunkX, chunkY)[1]
|
||||||
blockArray = numpy.frombuffer(level['Blocks'], dtype=numpy.uint8).reshape((16,16,128))
|
if data is not None:
|
||||||
|
level = data['Level']
|
||||||
## The block for spawn *within* the chunk
|
blockArray = numpy.frombuffer(level['Blocks'], dtype=numpy.uint8).reshape((16,16,128))
|
||||||
inChunkX = spawnX - (chunkX*16)
|
|
||||||
inChunkZ = spawnZ - (chunkY*16)
|
## The block for spawn *within* the chunk
|
||||||
|
inChunkX = spawnX - (chunkX*16)
|
||||||
## find the first air block
|
inChunkZ = spawnZ - (chunkY*16)
|
||||||
while (blockArray[inChunkX, inChunkZ, spawnY] != 0):
|
|
||||||
spawnY += 1
|
## find the first air block
|
||||||
if spawnY == 128:
|
while (blockArray[inChunkX, inChunkZ, spawnY] != 0):
|
||||||
break
|
spawnY += 1
|
||||||
|
if spawnY == 128:
|
||||||
|
break
|
||||||
|
|
||||||
self.POI.append( dict(x=spawnX, y=spawnY, z=spawnZ,
|
self.POI.append( dict(x=spawnX, y=spawnY, z=spawnZ,
|
||||||
msg="Spawn", type="spawn", chunk=(inChunkX,inChunkZ)))
|
msg="Spawn", type="spawn", chunk=(chunkX, chunkY)))
|
||||||
self.spawn = (spawnX, spawnY, spawnZ)
|
self.spawn = (spawnX, spawnY, spawnZ)
|
||||||
|
|
||||||
def go(self, procs):
|
def go(self, procs):
|
||||||
|
|||||||
Reference in New Issue
Block a user