Merge remote-tracking branch 'origin/rewrite-rendermodes' into rewrite
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -22,8 +22,9 @@ overviewer_core/c_overviewer.pyd
|
||||
overviewer_core/c_overviewer_d.pyd
|
||||
overviewer_core/c_overviewer.dylib
|
||||
|
||||
# generated version file
|
||||
# generated files
|
||||
overviewer_core/overviewer_version.py
|
||||
overviewer_core/src/primitives.h
|
||||
|
||||
# Mac OS X noise
|
||||
.DS_Store
|
||||
|
||||
331
overviewer.py
331
overviewer.py
@@ -18,25 +18,13 @@
|
||||
import platform
|
||||
import sys
|
||||
|
||||
# quick version check
|
||||
if not (sys.version_info[0] == 2 and sys.version_info[1] >= 6):
|
||||
print "Sorry, the Overviewer requires at least Python 2.6 to run"
|
||||
if sys.version_info[0] >= 3:
|
||||
print "and will not run on Python 3.0 or later"
|
||||
sys.exit(1)
|
||||
|
||||
isBareConsole = False
|
||||
|
||||
if platform.system() == 'Windows':
|
||||
try:
|
||||
import ctypes
|
||||
GetConsoleProcessList = ctypes.windll.kernel32.GetConsoleProcessList
|
||||
num = GetConsoleProcessList(ctypes.byref(ctypes.c_int(0)), ctypes.c_int(1))
|
||||
if (num == 1):
|
||||
isBareConsole = True
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import re
|
||||
@@ -44,110 +32,13 @@ import subprocess
|
||||
import multiprocessing
|
||||
import time
|
||||
import logging
|
||||
from overviewer_core import util
|
||||
|
||||
def doExit(msg=None, code=1, wait=None, consoleMsg=True):
|
||||
'''Exits Overviewer. If `wait` is None, the default
|
||||
will be true is 'isBareConsole' is true'''
|
||||
global isBareConsole
|
||||
if msg:
|
||||
print msg
|
||||
|
||||
if wait == None:
|
||||
if isBareConsole:
|
||||
if consoleMsg:
|
||||
print "\n"
|
||||
print "The Overviewer is a console program. Please open a Windows command prompt"
|
||||
print "first and run Overviewer from there. Further documentation is available at"
|
||||
print "http://docs.overviewer.org/\n"
|
||||
print "Press [Enter] to close this window."
|
||||
raw_input()
|
||||
else:
|
||||
if wait:
|
||||
if consoleMsg:
|
||||
print "\n"
|
||||
print "The Overviewer is a console program. Please open a Windows command prompt"
|
||||
print "first and run Overviewer from there. Further documentation is available at"
|
||||
print "http://docs.overviewer.org/\n"
|
||||
print "Press [Enter] to close this window."
|
||||
raw_input()
|
||||
|
||||
sys.exit(code)
|
||||
|
||||
|
||||
this_dir = util.get_program_path()
|
||||
|
||||
# make sure the c_overviewer extension is available
|
||||
try:
|
||||
from overviewer_core import c_overviewer
|
||||
except ImportError:
|
||||
## if this is a frozen windows package, the following error messages about
|
||||
## building the c_overviewer extension are not appropriate
|
||||
if hasattr(sys, "frozen"):
|
||||
print "Something has gone wrong importing the c_overviewer extension. Please"
|
||||
print "make sure the 2008 and 2010 redistributable packages from Microsoft"
|
||||
print "are installed."
|
||||
doExit()
|
||||
|
||||
|
||||
## try to find the build extension
|
||||
ext = os.path.join(this_dir, "overviewer_core", "c_overviewer.%s" % ("pyd" if platform.system() == "Windows" else "so"))
|
||||
if os.path.exists(ext):
|
||||
print "Something has gone wrong importing the c_overviewer extension. Please"
|
||||
print "make sure it is up-to-date (clean and rebuild)"
|
||||
doExit()
|
||||
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
print ""
|
||||
print "You need to compile the c_overviewer module to run Minecraft Overviewer."
|
||||
print "Run `python setup.py build`, or see the README for details."
|
||||
doExit()
|
||||
|
||||
from overviewer_core import textures
|
||||
|
||||
if hasattr(sys, "frozen"):
|
||||
pass # we don't bother with a compat test since it should always be in sync
|
||||
elif "extension_version" in dir(c_overviewer):
|
||||
# check to make sure the binary matches the headers
|
||||
if os.path.exists(os.path.join(this_dir, "overviewer_core", "src", "overviewer.h")):
|
||||
with open(os.path.join(this_dir, "overviewer_core", "src", "overviewer.h")) as f:
|
||||
lines = f.readlines()
|
||||
lines = filter(lambda x: x.startswith("#define OVERVIEWER_EXTENSION_VERSION"), lines)
|
||||
if lines:
|
||||
l = lines[0]
|
||||
if int(l.split()[2].strip()) != c_overviewer.extension_version():
|
||||
print "Please rebuild your c_overviewer module. It is out of date!"
|
||||
doExit(code=1, consoleMsg=True)
|
||||
else:
|
||||
print "Please rebuild your c_overviewer module. It is out of date!"
|
||||
doExit()
|
||||
|
||||
from optparse import OptionParser
|
||||
|
||||
from overviewer_core import util
|
||||
from overviewer_core import textures
|
||||
from overviewer_core import optimizeimages, world
|
||||
from overviewer_core import googlemap
|
||||
from overviewer_core import configParser, tileset, assetmanager, dispatcher
|
||||
|
||||
# definitions of built-in custom modes
|
||||
# usually because what used to be a mode became an option
|
||||
# for example, night mode
|
||||
builtin_custom_rendermodes = {}
|
||||
# 'night' : {
|
||||
# 'parent' : 'lighting',
|
||||
# 'label' : 'Night',
|
||||
# 'description' : 'like "lighting", except at night',
|
||||
# 'options' : {'night' : True}
|
||||
# },
|
||||
|
||||
# 'smooth-night' : {
|
||||
# 'parent' : 'smooth-lighting',
|
||||
# 'label' : 'Smooth Night',
|
||||
# 'description' : 'like "lighting", except smooth and at night',
|
||||
# 'options' : {'night' : True}
|
||||
# },
|
||||
# }
|
||||
|
||||
helptext = """
|
||||
%prog [OPTIONS] <World # / Name / Path to World> <tiles dest dir>"""
|
||||
|
||||
@@ -195,7 +86,6 @@ def configure_logger(loglevel=logging.INFO, verbose=False):
|
||||
logger.setLevel(loglevel)
|
||||
|
||||
def main():
|
||||
|
||||
# bootstrap the logger with defaults
|
||||
configure_logger()
|
||||
|
||||
@@ -204,7 +94,7 @@ def main():
|
||||
except NotImplementedError:
|
||||
cpus = 1
|
||||
|
||||
avail_rendermodes = c_overviewer.get_render_modes()
|
||||
#avail_rendermodes = c_overviewer.get_render_modes()
|
||||
avail_north_dirs = ['lower-left', 'upper-left', 'upper-right', 'lower-right', 'auto']
|
||||
|
||||
# revert to a vanilla OptionParser for right now
|
||||
@@ -216,7 +106,6 @@ def main():
|
||||
#parser.add_option("--forcerender", dest="forcerender", help="Force re-rendering the entire map (or the given regionlist). Useful for re-rendering without deleting it.", action="store_true")
|
||||
#parser.add_option("--stochastic-render", dest="stochastic_render", help="Rerender a non-updated tile randomly, with the given probability (between 0 and 1). Useful for incrementally updating a map with a new mode.", type="float", advanced=True, default=0.0, metavar="PROBABILITY")
|
||||
#parser.add_option("--rendermodes", dest="rendermode", help="Specifies the render types, separated by ',', ':', or '/'. Use --list-rendermodes to list them all.", type="choice", 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.")
|
||||
#parser.add_option("--rendermode-options", dest="rendermode_options", default={}, advanced=True, help="Used to specify options for different rendermodes. Only useful in a settings.py file")
|
||||
#parser.add_option("--custom-rendermodes", dest="custom_rendermodes", default={}, advanced=True, help="Used to define custom rendermodes. Only useful in a settings.py file")
|
||||
#parser.add_option("--imgformat", dest="imgformat", help="The image output format to use. Currently supported: png(default), jpg.", advanced=True )
|
||||
@@ -253,59 +142,54 @@ def main():
|
||||
print "Build machine: %s %s" % (overviewer_version.BUILD_PLATFORM, overviewer_version.BUILD_OS)
|
||||
except ImportError:
|
||||
print "(build info not found)"
|
||||
pass
|
||||
doExit(code=0, consoleMsg=False)
|
||||
|
||||
# setup c_overviewer rendermode customs / options
|
||||
for mode in builtin_custom_rendermodes:
|
||||
c_overviewer.add_custom_render_mode(mode, builtin_custom_rendermodes[mode])
|
||||
# TODO allow custom rendermodes to be specified in a settings.py file
|
||||
#for mode in options.custom_rendermodes:
|
||||
# c_overviewer.add_custom_render_mode(mode, options.custom_rendermodes[mode])
|
||||
#for mode in options.rendermode_options:
|
||||
# c_overviewer.set_render_mode_options(mode, options.rendermode_options[mode])
|
||||
|
||||
|
||||
|
||||
if options.list_rendermodes:
|
||||
list_rendermodes()
|
||||
doExit(code=0, consoleMsg=False)
|
||||
return 0
|
||||
|
||||
if options.check_terrain:
|
||||
import hashlib
|
||||
from overviewer_core.textures import _find_file
|
||||
if options.textures_path:
|
||||
textures._find_file_local_path = options.textures_path
|
||||
from overviewer_core.textures import Textures
|
||||
# TODO custom textures path?
|
||||
tex = Textures()
|
||||
|
||||
try:
|
||||
f = _find_file("terrain.png", verbose=True)
|
||||
f = tex.find_file("terrain.png", verbose=True)
|
||||
except IOError:
|
||||
logging.error("Could not find the file terrain.png")
|
||||
doExit(code=1, consoleMsg=False)
|
||||
return 1
|
||||
|
||||
h = hashlib.sha1()
|
||||
h.update(f.read())
|
||||
logging.info("Hash of terrain.png file is: `%s`", h.hexdigest())
|
||||
doExit(code=0, consoleMsg=False)
|
||||
return 0
|
||||
|
||||
if options.display_config:
|
||||
# just display the config file and exit
|
||||
parser.display_config()
|
||||
return 0
|
||||
|
||||
# TODO remove advanced help? needs discussion
|
||||
#if options.advanced_help:
|
||||
# parser.advanced_help()
|
||||
# doExit(code=0, consoleMsg=False)
|
||||
|
||||
# TODO right now, we will not let users specify worlds to render on the command line.
|
||||
# TODO in the future, we need to also let worlds be specified on the command line
|
||||
|
||||
# if no arguments are provided, print out a helpful message
|
||||
if len(args) == 0:
|
||||
# first provide an appropriate error for bare-console users
|
||||
# that don't provide any options
|
||||
if util.is_bare_console():
|
||||
print "\n"
|
||||
print "The Overviewer is a console program. Please open a Windows command prompt"
|
||||
print "first and run Overviewer from there. Further documentation is available at"
|
||||
print "http://docs.overviewer.org/\n"
|
||||
else:
|
||||
# more helpful message for users who know what they're doing
|
||||
logging.error("You need to give me your world number or directory")
|
||||
parser.print_help()
|
||||
list_worlds()
|
||||
return 1
|
||||
|
||||
# for multiworld, we must specify the *outputdir* on the command line
|
||||
if len(args) == 1:
|
||||
elif len(args) == 1:
|
||||
logging.debug("Using %r as the output_directory", args[0])
|
||||
destdir = os.path.expanduser(args[0])
|
||||
|
||||
elif len(args) < 1:
|
||||
logging.error("You need to give me your world number or directory")
|
||||
parser.print_help()
|
||||
list_worlds()
|
||||
doExit(code=1, consoleMsg=True)
|
||||
elif len(args) == 2: # TODO support this usecase
|
||||
worlddir = os.path.expanduser(args[0])
|
||||
destdir = os.path.expanduser(args[1])
|
||||
@@ -319,14 +203,7 @@ def main():
|
||||
if os.path.exists(" ".join(args[start:end])):
|
||||
logging.warning("It looks like you meant to specify \"%s\" as your world dir or your output\n\
|
||||
dir but you forgot to put quotes around the directory, since it contains spaces." % " ".join(args[start:end]))
|
||||
doExit(code=1, consoleMsg=False)
|
||||
|
||||
|
||||
if options.display_config:
|
||||
# just display the config file and exit
|
||||
parser.display_config()
|
||||
doExit(code=0, consoleMsg=False)
|
||||
|
||||
return 1
|
||||
|
||||
# TODO regionlists are per-world
|
||||
#if options.regionlist:
|
||||
@@ -363,11 +240,11 @@ dir but you forgot to put quotes around the directory, since it contains spaces.
|
||||
# except IOError as e:
|
||||
# logging.error("Unable to open file %s to use for changelist." % options.changelist)
|
||||
# logging.error("I/O Error: %s" % e.strerror)
|
||||
# doExit(code=1, consoleMsg=False)
|
||||
# return 1
|
||||
|
||||
#if options.changelist_format != "auto" and not options.changelist:
|
||||
# logging.error("changelist_format specified without changelist.")
|
||||
# doExit(code=1, consoleMsg=False)
|
||||
# return 1
|
||||
#if options.changelist_format == "auto":
|
||||
# options.changelist_format = "relative"
|
||||
|
||||
@@ -382,7 +259,7 @@ dir but you forgot to put quotes around the directory, since it contains spaces.
|
||||
tex.generate()
|
||||
except IOError, e:
|
||||
logging.error(str(e))
|
||||
doExit(code=1, consoleMsg=False)
|
||||
return 1
|
||||
|
||||
# look at our settings.py file
|
||||
mw_parser = configParser.MultiWorldParser("settings.py")
|
||||
@@ -429,127 +306,7 @@ dir but you forgot to put quotes around the directory, since it contains spaces.
|
||||
dispatch.close()
|
||||
|
||||
assetMrg.finalize(tilesets)
|
||||
|
||||
sys.exit("early abort")
|
||||
|
||||
# First do world-level preprocessing. This scans the world hierarchy, reads
|
||||
# in the region files and caches chunk modified times, and determines the
|
||||
# chunk bounds (max and min in both dimensions)
|
||||
w = world.World(worlddir)
|
||||
rset = w.get_regionsets()[0] # use the default
|
||||
if north_direction == 'auto':
|
||||
# TODO get this from the asset manager # north_direction = w.persistentData['north_direction']
|
||||
options.north_direction = north_direction
|
||||
|
||||
# TODO deal with changed north direction
|
||||
|
||||
# A couple other things we need to figure out about the world:
|
||||
w.get_regionsets()[0].determine_bounds()
|
||||
# w.find_true_spawn()
|
||||
|
||||
logging.info("Rendering the following tilesets: %s", ",".join(options.rendermode))
|
||||
|
||||
bgcolor = (int(options.bg_color[1:3],16),
|
||||
int(options.bg_color[3:5],16),
|
||||
int(options.bg_color[5:7],16),
|
||||
0)
|
||||
|
||||
# Create the quadtrees. There is one quadtree per rendermode requested, and
|
||||
# therefore, per output directory hierarchy of tiles. Each quadtree
|
||||
# individually computes its depth and size. The constructor computes the
|
||||
# depth of the tree, while the go() method re-arranges tiles if the current
|
||||
# depth differs from the computed depth.
|
||||
q = []
|
||||
qtree_args = {'depth' : options.zoom,
|
||||
'imgformat' : imgformat,
|
||||
'imgquality' : options.imgquality,
|
||||
'optimizeimg' : optimizeimg,
|
||||
'bgcolor' : bgcolor,
|
||||
'forcerender' : options.forcerender,
|
||||
'rerender_prob' : options.stochastic_render
|
||||
}
|
||||
for rendermode in options.rendermode:
|
||||
if rendermode == 'normal':
|
||||
qtree = quadtree.QuadtreeGen(rset, destdir, rendermode=rendermode, tiledir='tiles', **qtree_args)
|
||||
else:
|
||||
qtree = quadtree.QuadtreeGen(rset, destdir, rendermode=rendermode, **qtree_args)
|
||||
q.append(qtree)
|
||||
|
||||
# Make sure the quadtrees are the correct depth
|
||||
for qtree in q:
|
||||
qtree.check_depth()
|
||||
|
||||
# create the distributed render
|
||||
r = rendernode.RenderNode(q, options)
|
||||
# for the pool_initializer
|
||||
r.builtin_custom_rendermodes = builtin_custom_rendermodes
|
||||
|
||||
# write out the map and web assets
|
||||
m = googlemap.MapGen(q, configInfo=options)
|
||||
m.go(options.procs)
|
||||
|
||||
# render the tiles!
|
||||
r.go(options.procs)
|
||||
|
||||
# finish up the map
|
||||
m.finalize()
|
||||
|
||||
if options.changelist:
|
||||
changed=[]
|
||||
for tile in r.rendered_tiles:
|
||||
if options.changelist_format=="absolute":
|
||||
tile=os.path.abspath(tile)
|
||||
changed.append(tile)
|
||||
for zl in range(q[0].p - 1):
|
||||
tile=os.path.dirname(tile)
|
||||
changed.append("%s.%s" % (tile, imgformat))
|
||||
#Quick and nasty way to remove duplicate entries
|
||||
changed=list(set(changed))
|
||||
changed.sort()
|
||||
for path in changed:
|
||||
changefile.write("%s\n" % path)
|
||||
changefile.close()
|
||||
|
||||
def list_rendermodes():
|
||||
"Prints out a pretty list of supported rendermodes"
|
||||
|
||||
def print_mode_tree(line_max, mode, prefix='', last=False):
|
||||
"Prints out a mode tree for the given mode, with an indent."
|
||||
|
||||
try:
|
||||
info = c_overviewer.get_render_mode_info(mode)
|
||||
except ValueError:
|
||||
info = {}
|
||||
|
||||
print prefix + '+-', mode,
|
||||
|
||||
if 'description' in info:
|
||||
print " " * (line_max - len(prefix) - len(mode) - 2),
|
||||
print info['description']
|
||||
else:
|
||||
print
|
||||
|
||||
children = c_overviewer.get_render_mode_children(mode)
|
||||
for child in children:
|
||||
child_last = (child == children[-1])
|
||||
if last:
|
||||
child_prefix = ' '
|
||||
else:
|
||||
child_prefix = '| '
|
||||
print_mode_tree(line_max, child, prefix=prefix + child_prefix, last=child_last)
|
||||
|
||||
avail_rendermodes = c_overviewer.get_render_modes()
|
||||
line_lengths = {}
|
||||
parent_modes = []
|
||||
for mode in avail_rendermodes:
|
||||
inherit = c_overviewer.get_render_mode_inheritance(mode)
|
||||
if not inherit[0] in parent_modes:
|
||||
parent_modes.append(inherit[0])
|
||||
line_lengths[mode] = 2 * len(inherit) + 1 + len(mode)
|
||||
|
||||
line_length = max(line_lengths.values())
|
||||
for mode in parent_modes:
|
||||
print_mode_tree(line_length, mode, last=(mode == parent_modes[-1]))
|
||||
return 0
|
||||
|
||||
def list_worlds():
|
||||
"Prints out a brief summary of saves found in the default directory"
|
||||
@@ -582,18 +339,14 @@ def list_worlds():
|
||||
size = "%.2fMB" % (info['SizeOnDisk'] / 1024. / 1024.)
|
||||
print formatString % (name, size, playstamp, timestamp)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
multiprocessing.freeze_support()
|
||||
try:
|
||||
main()
|
||||
ret = main()
|
||||
util.exit(ret)
|
||||
except Exception, e:
|
||||
print e
|
||||
if e.args[0] == "Exiting":
|
||||
logging.info("Exiting...")
|
||||
doExit(code=0, wait=False)
|
||||
logging.exception("""An error has occurred. This may be a bug. Please let us know!
|
||||
See http://docs.overviewer.org/en/latest/index.html#help
|
||||
|
||||
This is the error that occurred:""")
|
||||
doExit(code=1, consoleMsg=False)
|
||||
util.exit(1)
|
||||
|
||||
@@ -1,7 +1,71 @@
|
||||
# c_overviewer must be imported first, because it imports other
|
||||
# modules; leaving this out can lead to bad dependency loops
|
||||
#
|
||||
# Code to check to make sure c_overviewer is built and working
|
||||
#
|
||||
|
||||
try:
|
||||
import c_overviewer
|
||||
except ImportError:
|
||||
pass
|
||||
import os.path
|
||||
import platform
|
||||
import traceback
|
||||
import sys
|
||||
|
||||
import util
|
||||
|
||||
def check_c_overviewer():
|
||||
"""Check to make sure c_overviewer works and is up-to-date. Prints
|
||||
out a helpful error and returns 1 if something's wrong, returns 0
|
||||
otherwise.
|
||||
"""
|
||||
root_dir = util.get_program_path()
|
||||
# make sure the c_overviewer extension is available
|
||||
try:
|
||||
import c_overviewer
|
||||
except ImportError:
|
||||
## if this is a frozen windows package, the following error messages about
|
||||
## building the c_overviewer extension are not appropriate
|
||||
if hasattr(sys, "frozen") and platform.system() == 'Windows':
|
||||
print "Something has gone wrong importing the c_overviewer extension. Please"
|
||||
print "make sure the 2008 and 2010 redistributable packages from Microsoft"
|
||||
print "are installed."
|
||||
return 1
|
||||
|
||||
## try to find the build extension
|
||||
ext = os.path.join(root_dir, "overviewer_core", "c_overviewer.%s" % ("pyd" if platform.system() == "Windows" else "so"))
|
||||
if os.path.exists(ext):
|
||||
traceback.print_exc()
|
||||
print ""
|
||||
print "Something has gone wrong importing the c_overviewer extension. Please"
|
||||
print "make sure it is up-to-date (clean and rebuild)"
|
||||
return 1
|
||||
|
||||
print "You need to compile the c_overviewer module to run Minecraft Overviewer."
|
||||
print "Run `python setup.py build`, or see the README for details."
|
||||
return 1
|
||||
|
||||
#
|
||||
# make sure it's up-to-date
|
||||
#
|
||||
|
||||
if hasattr(sys, "frozen"):
|
||||
pass # we don't bother with a compat test since it should always be in sync
|
||||
elif "extension_version" in dir(c_overviewer):
|
||||
# check to make sure the binary matches the headers
|
||||
if os.path.exists(os.path.join(root_dir, "overviewer_core", "src", "overviewer.h")):
|
||||
with open(os.path.join(root_dir, "overviewer_core", "src", "overviewer.h")) as f:
|
||||
lines = f.readlines()
|
||||
lines = filter(lambda x: x.startswith("#define OVERVIEWER_EXTENSION_VERSION"), lines)
|
||||
if lines:
|
||||
l = lines[0]
|
||||
if int(l.split()[2].strip()) != c_overviewer.extension_version():
|
||||
print "Please rebuild your c_overviewer module. It is out of date!"
|
||||
return 1
|
||||
else:
|
||||
print "Please rebuild your c_overviewer module. It is out of date!"
|
||||
return 1
|
||||
|
||||
# all good!
|
||||
return 0
|
||||
|
||||
# only check the module if we're not setup.py
|
||||
if not sys.argv[0].endswith("setup.py"):
|
||||
ret = check_c_overviewer()
|
||||
if ret > 0:
|
||||
util.exit(ret)
|
||||
|
||||
@@ -16,59 +16,125 @@
|
||||
from PIL import Image
|
||||
import textures
|
||||
|
||||
# Render 3 blending masks for lighting
|
||||
# first is top (+Z), second is left (-X), third is right (+Y)
|
||||
def generate_facemasks():
|
||||
white = Image.new("L", (24,24), 255)
|
||||
|
||||
top = Image.new("L", (24,24), 0)
|
||||
left = Image.new("L", (24,24), 0)
|
||||
whole = Image.new("L", (24,24), 0)
|
||||
|
||||
toppart = textures.Textures.transform_image_top(white)
|
||||
leftpart = textures.Textures.transform_image_side(white)
|
||||
|
||||
# using the real PIL paste here (not alpha_over) because there is
|
||||
# no alpha channel (and it's mode "L")
|
||||
top.paste(toppart, (0,0))
|
||||
left.paste(leftpart, (0,6))
|
||||
right = left.transpose(Image.FLIP_LEFT_RIGHT)
|
||||
|
||||
# Manually touch up 6 pixels that leave a gap, like in
|
||||
# textures._build_block()
|
||||
for x,y in [(13,23), (17,21), (21,19)]:
|
||||
right.putpixel((x,y), 255)
|
||||
for x,y in [(3,4), (7,2), (11,0)]:
|
||||
top.putpixel((x,y), 255)
|
||||
|
||||
# special fix for chunk boundary stipple
|
||||
for x,y in [(13,11), (17,9), (21,7)]:
|
||||
right.putpixel((x,y), 0)
|
||||
|
||||
return (top, left, right)
|
||||
facemasks = generate_facemasks()
|
||||
black_color = Image.new("RGB", (24,24), (0,0,0))
|
||||
white_color = Image.new("RGB", (24,24), (255,255,255))
|
||||
|
||||
# Render 128 different color images for color coded depth blending in cave mode
|
||||
def generate_depthcolors():
|
||||
depth_colors = []
|
||||
r = 255
|
||||
g = 0
|
||||
b = 0
|
||||
for z in range(128):
|
||||
depth_colors.append(r)
|
||||
depth_colors.append(g)
|
||||
depth_colors.append(b)
|
||||
class RenderPrimitive(object):
|
||||
options = {}
|
||||
name = None
|
||||
def __init__(self, **kwargs):
|
||||
if self.name is None:
|
||||
raise RuntimeError("RenderPrimitive cannot be used directly")
|
||||
|
||||
if z < 32:
|
||||
g += 7
|
||||
elif z < 64:
|
||||
r -= 7
|
||||
elif z < 96:
|
||||
b += 7
|
||||
else:
|
||||
g -= 7
|
||||
self.option_values = {}
|
||||
for key, val in kwargs.iteritems():
|
||||
if not key in self.options:
|
||||
raise ValueError("primitive `{0}' has no option `{1}'".format(self.name, key))
|
||||
self.option_values[key] = val
|
||||
|
||||
# set up defaults
|
||||
for name, (description, default) in self.options.iteritems():
|
||||
if not name in self.option_values:
|
||||
self.option_values[name] = default
|
||||
|
||||
return depth_colors
|
||||
depth_colors = generate_depthcolors()
|
||||
class Base(RenderPrimitive):
|
||||
name = "base"
|
||||
|
||||
class Nether(RenderPrimitive):
|
||||
name = "nether"
|
||||
|
||||
class HeightFading(RenderPrimitive):
|
||||
name = "height-fading"
|
||||
|
||||
black_color = Image.new("RGB", (24,24), (0,0,0))
|
||||
white_color = Image.new("RGB", (24,24), (255,255,255))
|
||||
|
||||
class Depth(RenderPrimitive):
|
||||
name = "depth"
|
||||
options = {
|
||||
"min": ("lowest level of blocks to render", 0),
|
||||
"max": ("highest level of blocks to render", 127),
|
||||
}
|
||||
|
||||
class EdgeLines(RenderPrimitive):
|
||||
name = "edge-lines"
|
||||
options = {
|
||||
"opacity": ("darkness of the edge lines, from 0.0 to 1.0", 0.15),
|
||||
}
|
||||
|
||||
class Cave(RenderPrimitive):
|
||||
name = "cave"
|
||||
options = {
|
||||
"only_lit": ("only render lit caves", False),
|
||||
}
|
||||
|
||||
class DepthTinting(RenderPrimitive):
|
||||
name = "depth-tinting"
|
||||
|
||||
@property
|
||||
def depth_colors(self):
|
||||
depth_colors = getattr(self, "_depth_colors", [])
|
||||
if depth_colors:
|
||||
return depth_colors
|
||||
r = 255
|
||||
g = 0
|
||||
b = 0
|
||||
for z in range(128):
|
||||
depth_colors.append(r)
|
||||
depth_colors.append(g)
|
||||
depth_colors.append(b)
|
||||
|
||||
if z < 32:
|
||||
g += 7
|
||||
elif z < 64:
|
||||
r -= 7
|
||||
elif z < 96:
|
||||
b += 7
|
||||
else:
|
||||
g -= 7
|
||||
|
||||
self._depth_colors = depth_colors
|
||||
return depth_colors
|
||||
|
||||
class Lighting(RenderPrimitive):
|
||||
name = "lighting"
|
||||
options = {
|
||||
"strength": ("how dark to make the shadows, from 0.0 to 1.0", 1.0),
|
||||
"night": ("whether to use nighttime skylight settings", False),
|
||||
"color": ("whether to use colored light", False),
|
||||
}
|
||||
|
||||
@property
|
||||
def facemasks(self):
|
||||
facemasks = getattr(self, "_facemasks", None)
|
||||
if facemasks:
|
||||
return facemasks
|
||||
|
||||
white = Image.new("L", (24,24), 255)
|
||||
|
||||
top = Image.new("L", (24,24), 0)
|
||||
left = Image.new("L", (24,24), 0)
|
||||
whole = Image.new("L", (24,24), 0)
|
||||
|
||||
toppart = textures.Textures.transform_image_top(white)
|
||||
leftpart = textures.Textures.transform_image_side(white)
|
||||
|
||||
# using the real PIL paste here (not alpha_over) because there is
|
||||
# no alpha channel (and it's mode "L")
|
||||
top.paste(toppart, (0,0))
|
||||
left.paste(leftpart, (0,6))
|
||||
right = left.transpose(Image.FLIP_LEFT_RIGHT)
|
||||
|
||||
# Manually touch up 6 pixels that leave a gap, like in
|
||||
# textures._build_block()
|
||||
for x,y in [(13,23), (17,21), (21,19)]:
|
||||
right.putpixel((x,y), 255)
|
||||
for x,y in [(3,4), (7,2), (11,0)]:
|
||||
top.putpixel((x,y), 255)
|
||||
|
||||
# special fix for chunk boundary stipple
|
||||
for x,y in [(13,11), (17,9), (21,7)]:
|
||||
right.putpixel((x,y), 0)
|
||||
|
||||
self._facemasks = (top, left, right)
|
||||
return self._facemasks
|
||||
|
||||
class SmoothLighting(Lighting):
|
||||
name = "smooth-lighting"
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "overviewer.h"
|
||||
|
||||
static PyObject *textures = NULL;
|
||||
static PyObject *support = NULL;
|
||||
|
||||
unsigned int max_blockid = 0;
|
||||
unsigned int max_data = 0;
|
||||
@@ -47,11 +46,6 @@ PyObject *init_chunk_render(void) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
support = PyImport_ImportModule("overviewer_core.rendermodes");
|
||||
if (!support) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tmp = PyObject_GetAttrString(textures, "max_blockid");
|
||||
if (!tmp)
|
||||
return NULL;
|
||||
@@ -388,7 +382,7 @@ chunk_render(PyObject *self, PyObject *args) {
|
||||
RenderState state;
|
||||
PyObject *regionset;
|
||||
int chunkx, chunkz;
|
||||
const char* rendermode_name = NULL;
|
||||
PyObject *modeobj;
|
||||
PyObject *blockmap;
|
||||
|
||||
int xoff, yoff;
|
||||
@@ -406,14 +400,11 @@ chunk_render(PyObject *self, PyObject *args) {
|
||||
|
||||
PyObject *t = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "OiiOiisO", &state.regionset, &state.chunkx, &state.chunkz, &state.img, &xoff, &yoff, &rendermode_name, &state.textures))
|
||||
if (!PyArg_ParseTuple(args, "OiiOiiOO", &state.regionset, &state.chunkx, &state.chunkz, &state.img, &xoff, &yoff, &modeobj, &state.textures))
|
||||
return NULL;
|
||||
|
||||
/* rendermode support */
|
||||
state.support = support;
|
||||
|
||||
/* set up the render mode */
|
||||
state.rendermode = rendermode = render_mode_create(rendermode_name, &state);
|
||||
state.rendermode = rendermode = render_mode_create(modeobj, &state);
|
||||
if (rendermode == NULL) {
|
||||
return NULL; // note that render_mode_create will
|
||||
// set PyErr. No need to set it here
|
||||
|
||||
@@ -17,10 +17,6 @@
|
||||
|
||||
#include "overviewer.h"
|
||||
|
||||
/* global variables from rendermodes.c -- both are dictionaries */
|
||||
extern PyObject *render_mode_options;
|
||||
extern PyObject *custom_render_modes;
|
||||
|
||||
PyObject *get_extension_version(PyObject *self, PyObject *args) {
|
||||
|
||||
return Py_BuildValue("i", OVERVIEWER_EXTENSION_VERSION);
|
||||
@@ -33,20 +29,6 @@ static PyMethodDef COverviewerMethods[] = {
|
||||
{"render_loop", chunk_render, METH_VARARGS,
|
||||
"Renders stuffs"},
|
||||
|
||||
{"get_render_modes", get_render_modes, METH_VARARGS,
|
||||
"returns available render modes"},
|
||||
{"get_render_mode_info", get_render_mode_info, METH_VARARGS,
|
||||
"returns info for a particular render mode"},
|
||||
{"get_render_mode_inheritance", get_render_mode_inheritance, METH_VARARGS,
|
||||
"returns inheritance chain for a particular render mode"},
|
||||
{"get_render_mode_children", get_render_mode_children, METH_VARARGS,
|
||||
"returns (direct) children for a particular render mode"},
|
||||
|
||||
{"set_render_mode_options", set_render_mode_options, METH_VARARGS,
|
||||
"sets the default options for a given render mode"},
|
||||
{"add_custom_render_mode", add_custom_render_mode, METH_VARARGS,
|
||||
"add a new rendermode derived from an existing mode"},
|
||||
|
||||
{"extension_version", get_extension_version, METH_VARARGS,
|
||||
"Returns the extension version"},
|
||||
|
||||
@@ -69,17 +51,5 @@ initc_overviewer(void)
|
||||
return;
|
||||
}
|
||||
|
||||
/* create the render mode data structures, and attatch them to the module
|
||||
* so that the Python garbage collector doesn't freak out
|
||||
*/
|
||||
|
||||
render_mode_options = PyDict_New();
|
||||
PyObject_SetAttrString(mod, "_render_mode_options", render_mode_options);
|
||||
Py_DECREF(render_mode_options);
|
||||
|
||||
custom_render_modes = PyDict_New();
|
||||
PyObject_SetAttrString(mod, "_custom_render_modes", custom_render_modes);
|
||||
Py_DECREF(custom_render_modes);
|
||||
|
||||
init_endian();
|
||||
}
|
||||
|
||||
@@ -79,9 +79,6 @@ typedef struct {
|
||||
/* the Texture object */
|
||||
PyObject *textures;
|
||||
|
||||
/* the rendermode support module (rendermodes.py) */
|
||||
PyObject *support;
|
||||
|
||||
/* the block position and type, and the block array */
|
||||
int x, y, z;
|
||||
unsigned char block;
|
||||
|
||||
@@ -15,39 +15,22 @@
|
||||
* with the Overviewer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "overviewer.h"
|
||||
#include "../overviewer.h"
|
||||
|
||||
typedef struct {
|
||||
/* coordinates of the chunk, inside its region file */
|
||||
int chunk_x, chunk_y;
|
||||
/* biome data for the region */
|
||||
PyObject *biome_data;
|
||||
/* grasscolor and foliagecolor lookup tables */
|
||||
PyObject *grasscolor, *foliagecolor, *watercolor;
|
||||
/* biome-compatible grass/leaf textures */
|
||||
PyObject *grass_texture;
|
||||
} PrimitiveBase;
|
||||
|
||||
static int
|
||||
rendermode_normal_start(void *data, RenderState *state, PyObject *options) {
|
||||
RenderModeNormal *self = (RenderModeNormal *)data;
|
||||
|
||||
/* load up the given options, first */
|
||||
|
||||
self->edge_opacity = 0.15;
|
||||
if (!render_mode_parse_option(options, "edge_opacity", "f", &(self->edge_opacity)))
|
||||
return 1;
|
||||
|
||||
self->min_depth = 0;
|
||||
if (!render_mode_parse_option(options, "min_depth", "I", &(self->min_depth)))
|
||||
return 1;
|
||||
|
||||
self->max_depth = 127;
|
||||
if (!render_mode_parse_option(options, "max_depth", "I", &(self->max_depth)))
|
||||
return 1;
|
||||
|
||||
self->height_fading = 0;
|
||||
/* XXX skip height fading */
|
||||
/*if (!render_mode_parse_option(options, "height_fading", "i", &(self->height_fading)))
|
||||
return 1;*/
|
||||
|
||||
self->nether = 0;
|
||||
if (!render_mode_parse_option(options, "nether", "i", &(self->nether)))
|
||||
return 1;
|
||||
|
||||
/*if (self->height_fading) {
|
||||
self->black_color = PyObject_GetAttrString(state->chunk, "black_color");
|
||||
self->white_color = PyObject_GetAttrString(state->chunk, "white_color");
|
||||
}*/
|
||||
base_start(void *data, RenderState *state, PyObject *support) {
|
||||
PrimitiveBase *self = (PrimitiveBase *)data;
|
||||
|
||||
/* biome-compliant grass mask (includes sides!) */
|
||||
self->grass_texture = PyObject_GetAttrString(state->textures, "biome_grass_texture");
|
||||
@@ -95,20 +78,18 @@ rendermode_normal_start(void *data, RenderState *state, PyObject *options) {
|
||||
}
|
||||
|
||||
static void
|
||||
rendermode_normal_finish(void *data, RenderState *state) {
|
||||
RenderModeNormal *self = (RenderModeNormal *)data;
|
||||
base_finish(void *data, RenderState *state) {
|
||||
PrimitiveBase *self = (PrimitiveBase *)data;
|
||||
|
||||
Py_XDECREF(self->biome_data);
|
||||
Py_XDECREF(self->foliagecolor);
|
||||
Py_XDECREF(self->grasscolor);
|
||||
Py_XDECREF(self->watercolor);
|
||||
Py_XDECREF(self->grass_texture);
|
||||
Py_XDECREF(self->black_color);
|
||||
Py_XDECREF(self->white_color);
|
||||
}
|
||||
|
||||
static int
|
||||
rendermode_normal_occluded(void *data, RenderState *state, int x, int y, int z) {
|
||||
base_occluded(void *data, RenderState *state, int x, int y, int z) {
|
||||
if ( (x != 0) && (y != 15) && (z != 127) &&
|
||||
!render_mode_hidden(state->rendermode, x-1, y, z) &&
|
||||
!render_mode_hidden(state->rendermode, x, y, z+1) &&
|
||||
@@ -123,39 +104,15 @@ rendermode_normal_occluded(void *data, RenderState *state, int x, int y, int z)
|
||||
}
|
||||
|
||||
static int
|
||||
rendermode_normal_hidden(void *data, RenderState *state, int x, int y, int z) {
|
||||
RenderModeNormal *self = (RenderModeNormal *)data;
|
||||
base_hidden(void *data, RenderState *state, int x, int y, int z) {
|
||||
PrimitiveBase *self = (PrimitiveBase *)data;
|
||||
|
||||
if (z > self->max_depth || z < self->min_depth) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (self->nether)
|
||||
{
|
||||
|
||||
/* hide all blocks above all air blocks */
|
||||
int below_air = 0;
|
||||
|
||||
while (z < 128)
|
||||
{
|
||||
if (getArrayByte3D(state->blocks, x, y, z) == 0)
|
||||
{
|
||||
below_air = 1;
|
||||
break;
|
||||
}
|
||||
z++;
|
||||
}
|
||||
|
||||
if (!below_air)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
|
||||
RenderModeNormal *self = (RenderModeNormal *)data;
|
||||
base_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
|
||||
PrimitiveBase *self = (PrimitiveBase *)data;
|
||||
|
||||
/* draw the block! */
|
||||
alpha_over(state->img, src, mask, state->imgx, state->imgy, 0, 0);
|
||||
@@ -299,85 +256,13 @@ rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject *
|
||||
if (facemask)
|
||||
tint_with_mask(state->img, r, g, b, 255, facemask, state->imgx, state->imgy, 0, 0);
|
||||
}
|
||||
|
||||
if (self->height_fading) {
|
||||
/* do some height fading */
|
||||
PyObject *height_color = self->white_color;
|
||||
/* negative alpha => darkness, positive => light */
|
||||
float alpha = (1.0 / (1 + expf((70 - state->z) / 11.0))) * 0.6 - 0.55;
|
||||
|
||||
if (alpha < 0.0) {
|
||||
alpha *= -1;
|
||||
height_color = self->black_color;
|
||||
}
|
||||
|
||||
alpha_over_full(state->img, height_color, mask_light, alpha, state->imgx, state->imgy, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
/* Draw some edge lines! */
|
||||
// draw.line(((imgx+12,imgy+increment), (imgx+22,imgy+5+increment)), fill=(0,0,0), width=1)
|
||||
if (state->block == 44 || state->block == 78 || !is_transparent(state->block)) {
|
||||
Imaging img_i = imaging_python_to_c(state->img);
|
||||
unsigned char ink[] = {0, 0, 0, 255 * self->edge_opacity};
|
||||
|
||||
int increment=0;
|
||||
if (state->block == 44) // half-step
|
||||
increment=6;
|
||||
else if ((state->block == 78) || (state->block == 93) || (state->block == 94)) // snow, redstone repeaters (on and off)
|
||||
increment=9;
|
||||
|
||||
if ((state->x == 15) && (state->up_right_blocks != Py_None)) {
|
||||
unsigned char side_block = getArrayByte3D(state->up_right_blocks, 0, state->y, state->z);
|
||||
if (side_block != state->block && is_transparent(side_block)) {
|
||||
ImagingDrawLine(img_i, state->imgx+12, state->imgy+1+increment, state->imgx+22+1, state->imgy+5+1+increment, &ink, 1);
|
||||
ImagingDrawLine(img_i, state->imgx+12, state->imgy+increment, state->imgx+22+1, state->imgy+5+increment, &ink, 1);
|
||||
}
|
||||
} else if (state->x != 15) {
|
||||
unsigned char side_block = getArrayByte3D(state->blocks, state->x+1, state->y, state->z);
|
||||
if (side_block != state->block && is_transparent(side_block)) {
|
||||
ImagingDrawLine(img_i, state->imgx+12, state->imgy+1+increment, state->imgx+22+1, state->imgy+5+1+increment, &ink, 1);
|
||||
ImagingDrawLine(img_i, state->imgx+12, state->imgy+increment, state->imgx+22+1, state->imgy+5+increment, &ink, 1);
|
||||
}
|
||||
}
|
||||
// if y != 0 and blocks[x,y-1,z] == 0
|
||||
|
||||
// chunk boundries are annoying
|
||||
if ((state->y == 0) && (state->up_left_blocks != Py_None)) {
|
||||
unsigned char side_block = getArrayByte3D(state->up_left_blocks, state->x, 15, state->z);
|
||||
if (side_block != state->block && is_transparent(side_block)) {
|
||||
ImagingDrawLine(img_i, state->imgx, state->imgy+6+1+increment, state->imgx+12+1, state->imgy+1+increment, &ink, 1);
|
||||
ImagingDrawLine(img_i, state->imgx, state->imgy+6+increment, state->imgx+12+1, state->imgy+increment, &ink, 1);
|
||||
}
|
||||
} else if (state->y != 0) {
|
||||
unsigned char side_block = getArrayByte3D(state->blocks, state->x, state->y-1, state->z);
|
||||
if (side_block != state->block && is_transparent(side_block)) {
|
||||
// draw.line(((imgx,imgy+6+increment), (imgx+12,imgy+increment)), fill=(0,0,0), width=1)
|
||||
ImagingDrawLine(img_i, state->imgx, state->imgy+6+1+increment, state->imgx+12+1, state->imgy+1+increment, &ink, 1);
|
||||
ImagingDrawLine(img_i, state->imgx, state->imgy+6+increment, state->imgx+12+1, state->imgy+increment, &ink, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const RenderModeOption rendermode_normal_options[] = {
|
||||
{"edge_opacity", "darkness of the edge lines, from 0.0 to 1.0 (default: 0.15)"},
|
||||
{"min_depth", "lowest level of blocks to render (default: 0)"},
|
||||
{"max_depth", "highest level of blocks to render (default: 127)"},
|
||||
{"height_fading", "darken or lighten blocks based on height (default: False)"},
|
||||
{"nether", "if True, remove the roof of the map. Useful on nether maps. (default: False)"},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
RenderModeInterface rendermode_normal = {
|
||||
"normal", "Normal",
|
||||
"nothing special, just render the blocks",
|
||||
rendermode_normal_options,
|
||||
NULL,
|
||||
sizeof(RenderModeNormal),
|
||||
rendermode_normal_start,
|
||||
rendermode_normal_finish,
|
||||
rendermode_normal_occluded,
|
||||
rendermode_normal_hidden,
|
||||
rendermode_normal_draw,
|
||||
RenderPrimitiveInterface primitive_base = {
|
||||
"base", sizeof(PrimitiveBase),
|
||||
base_start,
|
||||
base_finish,
|
||||
base_occluded,
|
||||
base_hidden,
|
||||
base_draw,
|
||||
};
|
||||
@@ -15,15 +15,32 @@
|
||||
* with the Overviewer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "overviewer.h"
|
||||
#include "../overviewer.h"
|
||||
#include <math.h>
|
||||
|
||||
typedef struct {
|
||||
/* data used to know where the surface is */
|
||||
PyObject *skylight;
|
||||
PyObject *left_skylight;
|
||||
PyObject *right_skylight;
|
||||
PyObject *up_left_skylight;
|
||||
PyObject *up_right_skylight;
|
||||
|
||||
/* data used to know where the lit caves are */
|
||||
PyObject *blocklight;
|
||||
PyObject *left_blocklight;
|
||||
PyObject *right_blocklight;
|
||||
PyObject *up_left_blocklight;
|
||||
PyObject *up_right_blocklight;
|
||||
|
||||
int only_lit;
|
||||
} RenderPrimitiveCave;
|
||||
|
||||
static inline int
|
||||
touches_light(unsigned int x, unsigned int y, unsigned int z,
|
||||
PyObject *light, PyObject *left_light, PyObject *right_light,
|
||||
PyObject *up_left_light, PyObject *up_right_light) {
|
||||
|
||||
|
||||
if (getArrayByte3D(light, x, y, z+1) != 0) {
|
||||
return 1;
|
||||
}
|
||||
@@ -79,10 +96,11 @@ touches_light(unsigned int x, unsigned int y, unsigned int z,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
rendermode_cave_adjacent_occluded(void *data, RenderState *state, int x, int y, int z) {
|
||||
/* check for occlusion of edge blocks, using adjacent block data */
|
||||
|
||||
static int
|
||||
cave_occluded(void *data, RenderState *state, int x, int y, int z) {
|
||||
/* check for normal occlusion */
|
||||
/* use ajacent chunks, if not you get blocks spreaded in chunk edges */
|
||||
|
||||
if (z != 127) {
|
||||
if ( (x == 0) && (y != 15) ) {
|
||||
if (state->left_blocks != Py_None) {
|
||||
@@ -133,26 +151,11 @@ rendermode_cave_adjacent_occluded(void *data, RenderState *state, int x, int y,
|
||||
}
|
||||
|
||||
static int
|
||||
rendermode_cave_occluded(void *data, RenderState *state, int x, int y, int z) {
|
||||
/* first, check to see if it's "normally" occluded */
|
||||
if (rendermode_lighting.occluded(data, state, x, y, z))
|
||||
return 1;
|
||||
|
||||
/* check for normal occlusion */
|
||||
/* use ajacent chunks, if not you get blocks spreaded in chunk edges */
|
||||
return rendermode_cave_adjacent_occluded(data, state, x, y, z);
|
||||
}
|
||||
|
||||
static int
|
||||
rendermode_cave_hidden(void *data, RenderState *state, int x, int y, int z) {
|
||||
RenderModeCave* self;
|
||||
cave_hidden(void *data, RenderState *state, int x, int y, int z) {
|
||||
RenderPrimitiveCave* self;
|
||||
int dz = 0;
|
||||
self = (RenderModeCave *)data;
|
||||
self = (RenderPrimitiveCave *)data;
|
||||
|
||||
/* first, check to see if it's "normally" hidden */
|
||||
if (rendermode_lighting.hidden(data, state, x, y, z))
|
||||
return 1;
|
||||
|
||||
/* check if the block is touching skylight */
|
||||
if (z != 127) {
|
||||
|
||||
@@ -190,51 +193,25 @@ rendermode_cave_hidden(void *data, RenderState *state, int x, int y, int z) {
|
||||
/* unfortunate side-effect of lit cave mode: we need to count occluded
|
||||
* blocks as hidden for the lighting to look right, since technically our
|
||||
* hiding depends on occlusion as well
|
||||
*
|
||||
* We leave out this check otherwise because it's fairly expensive.
|
||||
*/
|
||||
if (self->lighting) {
|
||||
if ( (x != 0) && (y != 15) && (z != 127) &&
|
||||
!is_transparent(getArrayByte3D(state->blocks, x-1, y, z)) &&
|
||||
!is_transparent(getArrayByte3D(state->blocks, x, y, z+1)) &&
|
||||
!is_transparent(getArrayByte3D(state->blocks, x, y+1, z))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return rendermode_cave_adjacent_occluded(data, state, x, y, z);
|
||||
if ( (x != 0) && (y != 15) && (z != 127) &&
|
||||
!is_transparent(getArrayByte3D(state->blocks, x-1, y, z)) &&
|
||||
!is_transparent(getArrayByte3D(state->blocks, x, y, z+1)) &&
|
||||
!is_transparent(getArrayByte3D(state->blocks, x, y+1, z))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return cave_occluded(data, state, x, y, z);
|
||||
}
|
||||
|
||||
static int
|
||||
rendermode_cave_start(void *data, RenderState *state, PyObject *options) {
|
||||
RenderModeCave* self;
|
||||
cave_start(void *data, RenderState *state, PyObject *support) {
|
||||
RenderPrimitiveCave* self;
|
||||
int ret;
|
||||
self = (RenderModeCave *)data;
|
||||
self = (RenderPrimitiveCave *)data;
|
||||
|
||||
/* first, chain up */
|
||||
ret = rendermode_lighting.start(data, state, options);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
self->depth_tinting = 1;
|
||||
if (!render_mode_parse_option(options, "depth_tinting", "i", &(self->depth_tinting)))
|
||||
if (!render_mode_parse_option(support, "only_lit", "i", &(self->only_lit)))
|
||||
return 1;
|
||||
|
||||
self->only_lit = 0;
|
||||
if (!render_mode_parse_option(options, "only_lit", "i", &(self->only_lit)))
|
||||
return 1;
|
||||
|
||||
self->lighting = 0;
|
||||
if (!render_mode_parse_option(options, "lighting", "i", &(self->lighting)))
|
||||
return 1;
|
||||
|
||||
if (self->lighting)
|
||||
{
|
||||
/* we can't skip lighting the sides in cave mode, it looks too weird */
|
||||
self->parent.skip_sides = 0;
|
||||
}
|
||||
|
||||
/* if there's skylight we are in the surface! */
|
||||
self->skylight = get_chunk_data(state, CURRENT, SKYLIGHT);
|
||||
@@ -251,16 +228,13 @@ rendermode_cave_start(void *data, RenderState *state, PyObject *options) {
|
||||
self->up_right_blocklight = get_chunk_data(state, UP_RIGHT, BLOCKLIGHT);
|
||||
}
|
||||
|
||||
/* colors for tinting */
|
||||
self->depth_colors = PyObject_GetAttrString(state->support, "depth_colors");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
rendermode_cave_finish(void *data, RenderState *state) {
|
||||
RenderModeCave* self;
|
||||
self = (RenderModeCave *)data;
|
||||
cave_finish(void *data, RenderState *state) {
|
||||
RenderPrimitiveCave* self;
|
||||
self = (RenderPrimitiveCave *)data;
|
||||
|
||||
Py_DECREF(self->skylight);
|
||||
Py_DECREF(self->left_skylight);
|
||||
@@ -275,55 +249,13 @@ rendermode_cave_finish(void *data, RenderState *state) {
|
||||
Py_DECREF(self->up_left_blocklight);
|
||||
Py_DECREF(self->up_right_blocklight);
|
||||
}
|
||||
|
||||
Py_DECREF(self->depth_colors);
|
||||
|
||||
rendermode_lighting.finish(data, state);
|
||||
}
|
||||
|
||||
static void
|
||||
rendermode_cave_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
|
||||
RenderModeCave* self;
|
||||
int z, r, g, b;
|
||||
self = (RenderModeCave *)data;
|
||||
|
||||
z = state->z;
|
||||
r = 0, g = 0, b = 0;
|
||||
|
||||
/* draw the normal block */
|
||||
if (self->lighting) {
|
||||
rendermode_lighting.draw(data, state, src, mask, mask_light);
|
||||
} else {
|
||||
rendermode_normal.draw(data, state, src, mask, mask_light);
|
||||
}
|
||||
|
||||
if (self->depth_tinting) {
|
||||
/* get the colors and tint and tint */
|
||||
r = PyInt_AsLong(PyList_GetItem(self->depth_colors, 0 + z*3));
|
||||
g = PyInt_AsLong(PyList_GetItem(self->depth_colors, 1 + z*3));
|
||||
b = PyInt_AsLong(PyList_GetItem(self->depth_colors, 2 + z*3));
|
||||
|
||||
tint_with_mask(state->img, r, g, b, 255, mask, state->imgx, state->imgy, 0, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const RenderModeOption rendermode_cave_options[] = {
|
||||
{"depth_tinting", "tint caves based on how deep they are (default: True)"},
|
||||
{"only_lit", "only render lit caves (default: False)"},
|
||||
{"lighting", "render caves with lighting enabled (default: False)"},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
RenderModeInterface rendermode_cave = {
|
||||
"cave", "Cave",
|
||||
"render only caves",
|
||||
rendermode_cave_options,
|
||||
&rendermode_lighting,
|
||||
sizeof(RenderModeCave),
|
||||
rendermode_cave_start,
|
||||
rendermode_cave_finish,
|
||||
rendermode_cave_occluded,
|
||||
rendermode_cave_hidden,
|
||||
rendermode_cave_draw,
|
||||
RenderPrimitiveInterface primitive_cave = {
|
||||
"cave", sizeof(RenderPrimitiveCave),
|
||||
cave_start,
|
||||
cave_finish,
|
||||
cave_occluded,
|
||||
cave_hidden,
|
||||
NULL,
|
||||
};
|
||||
70
overviewer_core/src/primitives/depth-tinting.c
Normal file
70
overviewer_core/src/primitives/depth-tinting.c
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* This file is part of the Minecraft Overviewer.
|
||||
*
|
||||
* Minecraft Overviewer is free software: you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Minecraft Overviewer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with the Overviewer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../overviewer.h"
|
||||
#include <math.h>
|
||||
|
||||
typedef struct {
|
||||
/* list of colors used for tinting */
|
||||
PyObject *depth_colors;
|
||||
} RenderPrimitiveDepthTinting;
|
||||
|
||||
static int
|
||||
depth_tinting_start(void *data, RenderState *state, PyObject *support) {
|
||||
RenderPrimitiveDepthTinting* self;
|
||||
self = (RenderPrimitiveDepthTinting *)data;
|
||||
|
||||
self->depth_colors = PyObject_GetAttrString(support, "depth_colors");
|
||||
if (self->depth_colors == NULL)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
depth_tinting_finish(void *data, RenderState *state) {
|
||||
RenderPrimitiveDepthTinting* self;
|
||||
self = (RenderPrimitiveDepthTinting *)data;
|
||||
|
||||
Py_DECREF(self->depth_colors);
|
||||
}
|
||||
|
||||
static void
|
||||
depth_tinting_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
|
||||
RenderPrimitiveDepthTinting* self;
|
||||
int z, r, g, b;
|
||||
self = (RenderPrimitiveDepthTinting *)data;
|
||||
|
||||
z = state->z;
|
||||
r = 0, g = 0, b = 0;
|
||||
|
||||
/* get the colors and tint and tint */
|
||||
r = PyInt_AsLong(PyList_GetItem(self->depth_colors, 0 + z*3));
|
||||
g = PyInt_AsLong(PyList_GetItem(self->depth_colors, 1 + z*3));
|
||||
b = PyInt_AsLong(PyList_GetItem(self->depth_colors, 2 + z*3));
|
||||
|
||||
tint_with_mask(state->img, r, g, b, 255, mask, state->imgx, state->imgy, 0, 0);
|
||||
}
|
||||
|
||||
RenderPrimitiveInterface primitive_depth_tinting = {
|
||||
"depth-tinting", sizeof(RenderPrimitiveDepthTinting),
|
||||
depth_tinting_start,
|
||||
depth_tinting_finish,
|
||||
NULL,
|
||||
NULL,
|
||||
depth_tinting_draw,
|
||||
};
|
||||
53
overviewer_core/src/primitives/depth.c
Normal file
53
overviewer_core/src/primitives/depth.c
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of the Minecraft Overviewer.
|
||||
*
|
||||
* Minecraft Overviewer is free software: you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Minecraft Overviewer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with the Overviewer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../overviewer.h"
|
||||
|
||||
typedef struct {
|
||||
unsigned int min;
|
||||
unsigned int max;
|
||||
} PrimitiveDepth;
|
||||
|
||||
static int
|
||||
depth_start(void *data, RenderState *state, PyObject *support) {
|
||||
PrimitiveDepth *self = (PrimitiveDepth *)data;
|
||||
|
||||
if (!render_mode_parse_option(support, "min", "I", &(self->min)))
|
||||
return 1;
|
||||
if (!render_mode_parse_option(support, "max", "I", &(self->max)))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
depth_hidden(void *data, RenderState *state, int x, int y, int z) {
|
||||
PrimitiveDepth *self = (PrimitiveDepth *)data;
|
||||
if (z > self->max || z < self->min) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
RenderPrimitiveInterface primitive_depth = {
|
||||
"depth", sizeof(PrimitiveDepth),
|
||||
depth_start,
|
||||
NULL,
|
||||
NULL,
|
||||
depth_hidden,
|
||||
NULL,
|
||||
};
|
||||
88
overviewer_core/src/primitives/edge-lines.c
Normal file
88
overviewer_core/src/primitives/edge-lines.c
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* This file is part of the Minecraft Overviewer.
|
||||
*
|
||||
* Minecraft Overviewer is free software: you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Minecraft Overviewer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with the Overviewer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../overviewer.h"
|
||||
|
||||
typedef struct {
|
||||
float opacity;
|
||||
} PrimitiveEdgeLines;
|
||||
|
||||
static int
|
||||
edge_lines_start(void *data, RenderState *state, PyObject *support) {
|
||||
PrimitiveEdgeLines *self = (PrimitiveEdgeLines *)data;
|
||||
if (!render_mode_parse_option(support, "opacity", "f", &(self->opacity)))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
edge_lines_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
|
||||
PrimitiveEdgeLines *self = (PrimitiveEdgeLines *)data;
|
||||
|
||||
/* Draw some edge lines! */
|
||||
// draw.line(((imgx+12,imgy+increment), (imgx+22,imgy+5+increment)), fill=(0,0,0), width=1)
|
||||
if (state->block == 44 || state->block == 78 || !is_transparent(state->block)) {
|
||||
Imaging img_i = imaging_python_to_c(state->img);
|
||||
unsigned char ink[] = {0, 0, 0, 255 * self->opacity};
|
||||
|
||||
int increment=0;
|
||||
if (state->block == 44) // half-step
|
||||
increment=6;
|
||||
else if ((state->block == 78) || (state->block == 93) || (state->block == 94)) // snow, redstone repeaters (on and off)
|
||||
increment=9;
|
||||
|
||||
if ((state->x == 15) && (state->up_right_blocks != Py_None)) {
|
||||
unsigned char side_block = getArrayByte3D(state->up_right_blocks, 0, state->y, state->z);
|
||||
if (side_block != state->block && is_transparent(side_block)) {
|
||||
ImagingDrawLine(img_i, state->imgx+12, state->imgy+1+increment, state->imgx+22+1, state->imgy+5+1+increment, &ink, 1);
|
||||
ImagingDrawLine(img_i, state->imgx+12, state->imgy+increment, state->imgx+22+1, state->imgy+5+increment, &ink, 1);
|
||||
}
|
||||
} else if (state->x != 15) {
|
||||
unsigned char side_block = getArrayByte3D(state->blocks, state->x+1, state->y, state->z);
|
||||
if (side_block != state->block && is_transparent(side_block)) {
|
||||
ImagingDrawLine(img_i, state->imgx+12, state->imgy+1+increment, state->imgx+22+1, state->imgy+5+1+increment, &ink, 1);
|
||||
ImagingDrawLine(img_i, state->imgx+12, state->imgy+increment, state->imgx+22+1, state->imgy+5+increment, &ink, 1);
|
||||
}
|
||||
}
|
||||
// if y != 0 and blocks[x,y-1,z] == 0
|
||||
|
||||
// chunk boundries are annoying
|
||||
if ((state->y == 0) && (state->up_left_blocks != Py_None)) {
|
||||
unsigned char side_block = getArrayByte3D(state->up_left_blocks, state->x, 15, state->z);
|
||||
if (side_block != state->block && is_transparent(side_block)) {
|
||||
ImagingDrawLine(img_i, state->imgx, state->imgy+6+1+increment, state->imgx+12+1, state->imgy+1+increment, &ink, 1);
|
||||
ImagingDrawLine(img_i, state->imgx, state->imgy+6+increment, state->imgx+12+1, state->imgy+increment, &ink, 1);
|
||||
}
|
||||
} else if (state->y != 0) {
|
||||
unsigned char side_block = getArrayByte3D(state->blocks, state->x, state->y-1, state->z);
|
||||
if (side_block != state->block && is_transparent(side_block)) {
|
||||
// draw.line(((imgx,imgy+6+increment), (imgx+12,imgy+increment)), fill=(0,0,0), width=1)
|
||||
ImagingDrawLine(img_i, state->imgx, state->imgy+6+1+increment, state->imgx+12+1, state->imgy+1+increment, &ink, 1);
|
||||
ImagingDrawLine(img_i, state->imgx, state->imgy+6+increment, state->imgx+12+1, state->imgy+increment, &ink, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RenderPrimitiveInterface primitive_edge_lines = {
|
||||
"edge-lines", sizeof(PrimitiveEdgeLines),
|
||||
edge_lines_start,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
edge_lines_draw,
|
||||
};
|
||||
68
overviewer_core/src/primitives/height-fading.c
Normal file
68
overviewer_core/src/primitives/height-fading.c
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* This file is part of the Minecraft Overviewer.
|
||||
*
|
||||
* Minecraft Overviewer is free software: you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Minecraft Overviewer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with the Overviewer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../overviewer.h"
|
||||
|
||||
typedef struct {
|
||||
PyObject *black_color;
|
||||
PyObject *white_color;
|
||||
} PrimitiveHeightFading;
|
||||
|
||||
static int
|
||||
height_fading_start(void *data, RenderState *state, PyObject *support) {
|
||||
PrimitiveHeightFading *self = (PrimitiveHeightFading *)data;
|
||||
|
||||
self->black_color = PyObject_GetAttrString(support, "black_color");
|
||||
self->white_color = PyObject_GetAttrString(support, "white_color");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
height_fading_finish(void *data, RenderState *state) {
|
||||
PrimitiveHeightFading *self = (PrimitiveHeightFading *)data;
|
||||
|
||||
Py_DECREF(self->black_color);
|
||||
Py_DECREF(self->white_color);
|
||||
}
|
||||
|
||||
static void
|
||||
height_fading_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
|
||||
PrimitiveHeightFading *self = (PrimitiveHeightFading *)data;
|
||||
|
||||
/* do some height fading */
|
||||
PyObject *height_color = self->white_color;
|
||||
|
||||
/* negative alpha => darkness, positive => light */
|
||||
float alpha = (1.0 / (1 + expf((70 - state->z) / 11.0))) * 0.6 - 0.55;
|
||||
|
||||
if (alpha < 0.0) {
|
||||
alpha *= -1;
|
||||
height_color = self->black_color;
|
||||
}
|
||||
|
||||
alpha_over_full(state->img, height_color, mask_light, alpha, state->imgx, state->imgy, 0, 0);
|
||||
}
|
||||
|
||||
RenderPrimitiveInterface primitive_height_fading = {
|
||||
"height-fading", sizeof(PrimitiveHeightFading),
|
||||
height_fading_start,
|
||||
height_fading_finish,
|
||||
NULL,
|
||||
NULL,
|
||||
height_fading_draw,
|
||||
};
|
||||
@@ -15,7 +15,8 @@
|
||||
* with the Overviewer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "overviewer.h"
|
||||
#include "../overviewer.h"
|
||||
#include "lighting.h"
|
||||
#include <math.h>
|
||||
|
||||
/* figures out the color from a given skylight and blocklight,
|
||||
@@ -35,7 +36,7 @@ static void
|
||||
calculate_light_color_fancy(void *data,
|
||||
unsigned char skylight, unsigned char blocklight,
|
||||
unsigned char *r, unsigned char *g, unsigned char *b) {
|
||||
RenderModeLighting *mode = (RenderModeLighting *)(data);
|
||||
RenderPrimitiveLighting *mode = (RenderPrimitiveLighting *)(data);
|
||||
unsigned int index;
|
||||
PyObject *color;
|
||||
|
||||
@@ -70,7 +71,7 @@ static void
|
||||
calculate_light_color_fancy_night(void *data,
|
||||
unsigned char skylight, unsigned char blocklight,
|
||||
unsigned char *r, unsigned char *g, unsigned char *b) {
|
||||
RenderModeLighting *mode = (RenderModeLighting *)(data);
|
||||
RenderPrimitiveLighting *mode = (RenderPrimitiveLighting *)(data);
|
||||
unsigned int index;
|
||||
PyObject *color;
|
||||
|
||||
@@ -95,7 +96,7 @@ calculate_light_color_fancy_night(void *data,
|
||||
*/
|
||||
|
||||
inline unsigned char
|
||||
estimate_blocklevel(RenderModeLighting *self, RenderState *state,
|
||||
estimate_blocklevel(RenderPrimitiveLighting *self, RenderState *state,
|
||||
int x, int y, int z, int *authoratative) {
|
||||
|
||||
/* placeholders for later data arrays, coordinates */
|
||||
@@ -185,7 +186,7 @@ estimate_blocklevel(RenderModeLighting *self, RenderState *state,
|
||||
}
|
||||
|
||||
inline void
|
||||
get_lighting_color(RenderModeLighting *self, RenderState *state,
|
||||
get_lighting_color(RenderPrimitiveLighting *self, RenderState *state,
|
||||
int x, int y, int z,
|
||||
unsigned char *r, unsigned char *g, unsigned char *b) {
|
||||
|
||||
@@ -273,7 +274,10 @@ get_lighting_color(RenderModeLighting *self, RenderState *state,
|
||||
|
||||
if (block == 10 || block == 11) {
|
||||
/* lava blocks should always be lit! */
|
||||
return 0.0f;
|
||||
*r = 255;
|
||||
*g = 255;
|
||||
*b = 255;
|
||||
return;
|
||||
}
|
||||
|
||||
self->calculate_light_color(self, MIN(skylevel, 15), MIN(blocklevel, 15), r, g, b);
|
||||
@@ -281,7 +285,7 @@ get_lighting_color(RenderModeLighting *self, RenderState *state,
|
||||
|
||||
/* does per-face occlusion checking for do_shading_with_mask */
|
||||
inline int
|
||||
rendermode_lighting_is_face_occluded(RenderState *state, int skip_sides, int x, int y, int z) {
|
||||
lighting_is_face_occluded(RenderState *state, int skip_sides, int x, int y, int z) {
|
||||
/* first, check for occlusion if the block is in the local chunk */
|
||||
if (x >= 0 && x < 16 && y >= 0 && y < 16 && z >= 0 && z < 128) {
|
||||
unsigned char block = getArrayByte3D(state->blocks, x, y, z);
|
||||
@@ -315,52 +319,41 @@ rendermode_lighting_is_face_occluded(RenderState *state, int skip_sides, int x,
|
||||
/* shades the drawn block with the given facemask, based on the
|
||||
lighting results from (x, y, z) */
|
||||
static inline void
|
||||
do_shading_with_mask(RenderModeLighting *self, RenderState *state,
|
||||
do_shading_with_mask(RenderPrimitiveLighting *self, RenderState *state,
|
||||
int x, int y, int z, PyObject *mask) {
|
||||
unsigned char r, g, b;
|
||||
float comp_shade_strength;
|
||||
float comp_strength;
|
||||
|
||||
/* check occlusion */
|
||||
if (rendermode_lighting_is_face_occluded(state, self->skip_sides, x, y, z))
|
||||
if (lighting_is_face_occluded(state, self->skip_sides, x, y, z))
|
||||
return;
|
||||
|
||||
get_lighting_color(self, state, x, y, z, &r, &g, &b);
|
||||
comp_shade_strength = 1.0 - self->shade_strength;
|
||||
comp_strength = 1.0 - self->strength;
|
||||
|
||||
r += (255 - r) * comp_shade_strength;
|
||||
g += (255 - g) * comp_shade_strength;
|
||||
b += (255 - b) * comp_shade_strength;
|
||||
r += (255 - r) * comp_strength;
|
||||
g += (255 - g) * comp_strength;
|
||||
b += (255 - b) * comp_strength;
|
||||
|
||||
tint_with_mask(state->img, r, g, b, 255, mask, state->imgx, state->imgy, 0, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
rendermode_lighting_start(void *data, RenderState *state, PyObject *options) {
|
||||
RenderModeLighting* self;
|
||||
|
||||
/* first, chain up */
|
||||
int ret = rendermode_normal.start(data, state, options);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
lighting_start(void *data, RenderState *state, PyObject *support) {
|
||||
RenderPrimitiveLighting* self;
|
||||
self = (RenderPrimitiveLighting *)data;
|
||||
|
||||
self = (RenderModeLighting *)data;
|
||||
|
||||
/* skip sides by default */
|
||||
self->skip_sides = 1;
|
||||
/* don't skip sides by default */
|
||||
self->skip_sides = 0;
|
||||
|
||||
self->shade_strength = 1.0;
|
||||
if (!render_mode_parse_option(options, "shade_strength", "f", &(self->shade_strength)))
|
||||
if (!render_mode_parse_option(support, "strength", "f", &(self->strength)))
|
||||
return 1;
|
||||
|
||||
self->night = 0;
|
||||
if (!render_mode_parse_option(options, "night", "i", &(self->night)))
|
||||
if (!render_mode_parse_option(support, "night", "i", &(self->night)))
|
||||
return 1;
|
||||
|
||||
self->color_light = 0;
|
||||
if (!render_mode_parse_option(options, "color_light", "i", &(self->color_light)))
|
||||
if (!render_mode_parse_option(support, "color", "i", &(self->color)))
|
||||
return 1;
|
||||
|
||||
self->facemasks_py = PyObject_GetAttrString(state->support, "facemasks");
|
||||
self->facemasks_py = PyObject_GetAttrString(support, "facemasks");
|
||||
// borrowed references, don't need to be decref'd
|
||||
self->facemasks[0] = PyTuple_GetItem(self->facemasks_py, 0);
|
||||
self->facemasks[1] = PyTuple_GetItem(self->facemasks_py, 1);
|
||||
@@ -383,12 +376,12 @@ rendermode_lighting_start(void *data, RenderState *state, PyObject *options) {
|
||||
self->calculate_light_color = calculate_light_color;
|
||||
}
|
||||
|
||||
if (self->color_light) {
|
||||
self->lightcolor = PyObject_CallMethod(state->textures, "loadLightColor", "");
|
||||
if (self->color) {
|
||||
self->lightcolor = PyObject_CallMethod(state->textures, "load_light_color", "");
|
||||
if (self->lightcolor == Py_None) {
|
||||
Py_DECREF(self->lightcolor);
|
||||
self->lightcolor = NULL;
|
||||
self->color_light = 0;
|
||||
self->color = 0;
|
||||
} else {
|
||||
if (self->night) {
|
||||
self->calculate_light_color = calculate_light_color_fancy_night;
|
||||
@@ -404,8 +397,8 @@ rendermode_lighting_start(void *data, RenderState *state, PyObject *options) {
|
||||
}
|
||||
|
||||
static void
|
||||
rendermode_lighting_finish(void *data, RenderState *state) {
|
||||
RenderModeLighting *self = (RenderModeLighting *)data;
|
||||
lighting_finish(void *data, RenderState *state) {
|
||||
RenderPrimitiveLighting *self = (RenderPrimitiveLighting *)data;
|
||||
|
||||
Py_DECREF(self->facemasks_py);
|
||||
|
||||
@@ -419,32 +412,14 @@ rendermode_lighting_finish(void *data, RenderState *state) {
|
||||
Py_DECREF(self->up_left_blocklight);
|
||||
Py_DECREF(self->up_right_skylight);
|
||||
Py_DECREF(self->up_right_blocklight);
|
||||
|
||||
/* now chain up */
|
||||
rendermode_normal.finish(data, state);
|
||||
}
|
||||
|
||||
static int
|
||||
rendermode_lighting_occluded(void *data, RenderState *state, int x, int y, int z) {
|
||||
/* no special occlusion here */
|
||||
return rendermode_normal.occluded(data, state, x, y, z);
|
||||
}
|
||||
|
||||
static int
|
||||
rendermode_lighting_hidden(void *data, RenderState *state, int x, int y, int z) {
|
||||
/* no special hiding here */
|
||||
return rendermode_normal.hidden(data, state, x, y, z);
|
||||
}
|
||||
|
||||
static void
|
||||
rendermode_lighting_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
|
||||
RenderModeLighting* self;
|
||||
lighting_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
|
||||
RenderPrimitiveLighting* self;
|
||||
int x, y, z;
|
||||
|
||||
/* first, chain up */
|
||||
rendermode_normal.draw(data, state, src, mask, mask_light);
|
||||
|
||||
self = (RenderModeLighting *)data;
|
||||
self = (RenderPrimitiveLighting *)data;
|
||||
x = state->x, y = state->y, z = state->z;
|
||||
|
||||
if ((state->block == 9) || (state->block == 79)) { /* special case for water and ice */
|
||||
@@ -473,22 +448,11 @@ rendermode_lighting_draw(void *data, RenderState *state, PyObject *src, PyObject
|
||||
}
|
||||
}
|
||||
|
||||
const RenderModeOption rendermode_lighting_options[] = {
|
||||
{"shade_strength", "how dark to make the shadows, from 0.0 to 1.0 (default: 1.0)"},
|
||||
{"night", "whether to use nighttime skylight settings (default: False)"},
|
||||
{"color_light", "whether to use colored light (default: False)"},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
RenderModeInterface rendermode_lighting = {
|
||||
"lighting", "Lighting",
|
||||
"draw shadows from the lighting data",
|
||||
rendermode_lighting_options,
|
||||
&rendermode_normal,
|
||||
sizeof(RenderModeLighting),
|
||||
rendermode_lighting_start,
|
||||
rendermode_lighting_finish,
|
||||
rendermode_lighting_occluded,
|
||||
rendermode_lighting_hidden,
|
||||
rendermode_lighting_draw,
|
||||
RenderPrimitiveInterface primitive_lighting = {
|
||||
"lighting", sizeof(RenderPrimitiveLighting),
|
||||
lighting_start,
|
||||
lighting_finish,
|
||||
NULL,
|
||||
NULL,
|
||||
lighting_draw,
|
||||
};
|
||||
53
overviewer_core/src/primitives/lighting.h
Normal file
53
overviewer_core/src/primitives/lighting.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of the Minecraft Overviewer.
|
||||
*
|
||||
* Minecraft Overviewer is free software: you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Minecraft Overviewer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with the Overviewer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../overviewer.h"
|
||||
|
||||
typedef struct {
|
||||
PyObject *facemasks_py;
|
||||
PyObject *facemasks[3];
|
||||
|
||||
/* extra data, loaded off the chunk class */
|
||||
PyObject *skylight, *blocklight;
|
||||
PyObject *left_skylight, *left_blocklight;
|
||||
PyObject *right_skylight, *right_blocklight;
|
||||
PyObject *up_left_skylight, *up_left_blocklight;
|
||||
PyObject *up_right_skylight, *up_right_blocklight;
|
||||
|
||||
/* light color image, loaded if color_light is True */
|
||||
PyObject *lightcolor;
|
||||
|
||||
/* can be overridden in derived rendermodes to control lighting
|
||||
arguments are data, skylight, blocklight, return RGB */
|
||||
void (*calculate_light_color)(void *, unsigned char, unsigned char, unsigned char *, unsigned char *, unsigned char *);
|
||||
|
||||
/* can be set to 0 in derived modes to indicate that lighting the chunk
|
||||
* sides is actually important. Right now, this is used in cave mode
|
||||
*/
|
||||
int skip_sides;
|
||||
|
||||
float strength;
|
||||
int color;
|
||||
int night;
|
||||
} RenderPrimitiveLighting;
|
||||
|
||||
/* exposed so that smooth-lighting can use them */
|
||||
extern RenderPrimitiveInterface primitive_lighting;
|
||||
int lighting_is_face_occluded(RenderState *state, int skip_sides, int x, int y, int z);
|
||||
void get_lighting_color(RenderPrimitiveLighting *self, RenderState *state,
|
||||
int x, int y, int z,
|
||||
unsigned char *r, unsigned char *g, unsigned char *b);
|
||||
42
overviewer_core/src/primitives/nether.c
Normal file
42
overviewer_core/src/primitives/nether.c
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of the Minecraft Overviewer.
|
||||
*
|
||||
* Minecraft Overviewer is free software: you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Minecraft Overviewer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with the Overviewer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../overviewer.h"
|
||||
|
||||
static int
|
||||
nether_hidden(void *data, RenderState *state, int x, int y, int z) {
|
||||
/* hide all blocks above all air blocks */
|
||||
while (z < 128)
|
||||
{
|
||||
if (getArrayByte3D(state->blocks, x, y, z) == 0)
|
||||
{
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
z++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
RenderPrimitiveInterface primitive_nether = {
|
||||
"nether", 0,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
nether_hidden,
|
||||
NULL,
|
||||
};
|
||||
@@ -15,9 +15,15 @@
|
||||
* with the Overviewer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "overviewer.h"
|
||||
#include "../overviewer.h"
|
||||
#include "lighting.h"
|
||||
#include <math.h>
|
||||
|
||||
typedef struct {
|
||||
/* inherits from lighting */
|
||||
RenderPrimitiveLighting parent;
|
||||
} RenderPrimitiveSmoothLighting;
|
||||
|
||||
/* structure representing one corner of a face (see below) */
|
||||
struct SmoothLightingCorner {
|
||||
/* where this corner shows up on each block texture */
|
||||
@@ -123,12 +129,12 @@ enum
|
||||
};
|
||||
|
||||
static void
|
||||
do_shading_with_rule(RenderModeSmoothLighting *self, RenderState *state, struct SmoothLightingFace face) {
|
||||
do_shading_with_rule(RenderPrimitiveSmoothLighting *self, RenderState *state, struct SmoothLightingFace face) {
|
||||
int i;
|
||||
RenderModeLighting *lighting = (RenderModeLighting *)self;
|
||||
RenderPrimitiveLighting *lighting = (RenderPrimitiveLighting *)self;
|
||||
int x = state->imgx, y = state->imgy;
|
||||
struct SmoothLightingCorner *pts = face.corners;
|
||||
float comp_shade_strength = 1.0 - lighting->shade_strength;
|
||||
float comp_shade_strength = 1.0 - lighting->strength;
|
||||
unsigned char pts_r[4] = {0, 0, 0, 0};
|
||||
unsigned char pts_g[4] = {0, 0, 0, 0};
|
||||
unsigned char pts_b[4] = {0, 0, 0, 0};
|
||||
@@ -137,7 +143,7 @@ do_shading_with_rule(RenderModeSmoothLighting *self, RenderState *state, struct
|
||||
int cz = state->z + face.dz;
|
||||
|
||||
/* first, check for occlusion if the block is in the local chunk */
|
||||
if (rendermode_lighting_is_face_occluded(state, 0, cx, cy, cz))
|
||||
if (lighting_is_face_occluded(state, 0, cx, cy, cz))
|
||||
return;
|
||||
|
||||
/* calculate the lighting colors for each point */
|
||||
@@ -189,55 +195,38 @@ do_shading_with_rule(RenderModeSmoothLighting *self, RenderState *state, struct
|
||||
}
|
||||
|
||||
static int
|
||||
rendermode_smooth_lighting_start(void *data, RenderState *state, PyObject *options) {
|
||||
smooth_lighting_start(void *data, RenderState *state, PyObject *support) {
|
||||
/* first, chain up */
|
||||
int ret = rendermode_lighting.start(data, state, options);
|
||||
int ret = primitive_lighting.start(data, state, support);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
rendermode_smooth_lighting_finish(void *data, RenderState *state) {
|
||||
smooth_lighting_finish(void *data, RenderState *state) {
|
||||
/* nothing special to do */
|
||||
rendermode_lighting.finish(data, state);
|
||||
}
|
||||
|
||||
static int
|
||||
rendermode_smooth_lighting_occluded(void *data, RenderState *state, int x, int y, int z) {
|
||||
/* no special occlusion here */
|
||||
return rendermode_lighting.occluded(data, state, x, y, z);
|
||||
}
|
||||
|
||||
static int
|
||||
rendermode_smooth_lighting_hidden(void *data, RenderState *state, int x, int y, int z) {
|
||||
/* no special hiding here */
|
||||
return rendermode_lighting.hidden(data, state, x, y, z);
|
||||
primitive_lighting.finish(data, state);
|
||||
}
|
||||
|
||||
static void
|
||||
rendermode_smooth_lighting_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
|
||||
smooth_lighting_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
|
||||
int light_top = 1;
|
||||
int light_left = 1;
|
||||
int light_right = 1;
|
||||
RenderModeSmoothLighting *self = (RenderModeSmoothLighting *)data;
|
||||
RenderPrimitiveSmoothLighting *self = (RenderPrimitiveSmoothLighting *)data;
|
||||
|
||||
/* special case for leaves, water 8, water 9
|
||||
-- these are also smooth-lit! */
|
||||
if (state->block != 18 && state->block != 8 && state->block != 9 && is_transparent(state->block))
|
||||
{
|
||||
/* transparent blocks are rendered as usual, with flat lighting */
|
||||
rendermode_lighting.draw(data, state, src, mask, mask_light);
|
||||
primitive_lighting.draw(data, state, src, mask, mask_light);
|
||||
return;
|
||||
}
|
||||
|
||||
/* non-transparent blocks get the special smooth treatment */
|
||||
|
||||
/* nothing special to do, but we do want to avoid vanilla
|
||||
* lighting mode draws */
|
||||
rendermode_normal.draw(data, state, src, mask, mask_light);
|
||||
|
||||
/* special code for water */
|
||||
if (state->block == 9)
|
||||
{
|
||||
@@ -257,15 +246,11 @@ rendermode_smooth_lighting_draw(void *data, RenderState *state, PyObject *src, P
|
||||
do_shading_with_rule(self, state, lighting_rules[FACE_RIGHT]);
|
||||
}
|
||||
|
||||
RenderModeInterface rendermode_smooth_lighting = {
|
||||
"smooth-lighting", "Smooth Lighting",
|
||||
"like \"lighting\", except smooth",
|
||||
RenderPrimitiveInterface primitive_smooth_lighting = {
|
||||
"smooth-lighting", sizeof(RenderPrimitiveSmoothLighting),
|
||||
smooth_lighting_start,
|
||||
smooth_lighting_finish,
|
||||
NULL,
|
||||
&rendermode_lighting,
|
||||
sizeof(RenderModeSmoothLighting),
|
||||
rendermode_smooth_lighting_start,
|
||||
rendermode_smooth_lighting_finish,
|
||||
rendermode_smooth_lighting_occluded,
|
||||
rendermode_smooth_lighting_hidden,
|
||||
rendermode_smooth_lighting_draw,
|
||||
NULL,
|
||||
smooth_lighting_draw,
|
||||
};
|
||||
@@ -19,175 +19,174 @@
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/* list of all render modes, ending in NULL
|
||||
all of these will be available to the user, so DON'T include modes
|
||||
that are only useful as a base for other modes. */
|
||||
static RenderModeInterface *render_modes[] = {
|
||||
&rendermode_normal,
|
||||
&rendermode_lighting,
|
||||
&rendermode_smooth_lighting,
|
||||
&rendermode_cave,
|
||||
|
||||
&rendermode_spawn,
|
||||
&rendermode_mineral,
|
||||
NULL
|
||||
};
|
||||
|
||||
PyObject *render_mode_options = NULL;
|
||||
PyObject *custom_render_modes = NULL;
|
||||
/* this file defines render_primitives,
|
||||
a list of all render primitives, ending in NULL
|
||||
all of these will be available to the user, so DON'T include primitives
|
||||
that are only useful as a base for other primitives.
|
||||
|
||||
this file is auto-generated by setup.py */
|
||||
#include "primitives.h"
|
||||
|
||||
/* rendermode encapsulation */
|
||||
|
||||
/* helper to recursively find options for a given mode */
|
||||
static inline PyObject *
|
||||
render_mode_create_options(const char *mode) {
|
||||
const char *parent = NULL;
|
||||
PyObject *base_options, *ret, *parent_options;
|
||||
unsigned int i, found_concrete;
|
||||
/* helper to create a single primitive */
|
||||
RenderPrimitive *render_primitive_create(PyObject *prim, RenderState *state) {
|
||||
RenderPrimitive *ret = NULL;
|
||||
RenderPrimitiveInterface *iface = NULL;
|
||||
unsigned int i;
|
||||
PyObject *pyname;
|
||||
const char* name;
|
||||
|
||||
pyname = PyObject_GetAttrString(prim, "name");
|
||||
if (!pyname)
|
||||
return NULL;
|
||||
name = PyString_AsString(pyname);
|
||||
|
||||
base_options = PyDict_GetItemString(render_mode_options, mode);
|
||||
if (base_options) {
|
||||
ret = PyDict_Copy(base_options);
|
||||
} else {
|
||||
ret = PyDict_New();
|
||||
}
|
||||
|
||||
/* figure out the parent mode name */
|
||||
found_concrete = 0;
|
||||
for (i = 0; render_modes[i] != NULL; i++) {
|
||||
if (strcmp(render_modes[i]->name, mode) == 0) {
|
||||
found_concrete = 1;
|
||||
if (render_modes[i]->parent) {
|
||||
parent = render_modes[i]->parent->name;
|
||||
}
|
||||
for (i = 0; render_primitives[i] != NULL; i++) {
|
||||
if (strcmp(render_primitives[i]->name, name) == 0) {
|
||||
iface = render_primitives[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
Py_DECREF(pyname);
|
||||
|
||||
if (iface == NULL)
|
||||
return (RenderPrimitive *)PyErr_Format(PyExc_RuntimeError, "invalid primitive name: %s", name);
|
||||
|
||||
/* check custom mode info if needed */
|
||||
if (found_concrete == 0) {
|
||||
PyObject *custom = PyDict_GetItemString(custom_render_modes, mode);
|
||||
if (custom) {
|
||||
custom = PyDict_GetItemString(custom, "parent");
|
||||
if (custom) {
|
||||
parent = PyString_AsString(custom);
|
||||
}
|
||||
ret = calloc(1, sizeof(RenderPrimitive));
|
||||
if (ret == NULL) {
|
||||
return (RenderPrimitive *)PyErr_Format(PyExc_RuntimeError, "Failed to alloc a render primitive");
|
||||
}
|
||||
|
||||
if (iface->data_size > 0) {
|
||||
ret->primitive = calloc(1, iface->data_size);
|
||||
if (ret->primitive == NULL) {
|
||||
free(ret);
|
||||
return (RenderPrimitive *)PyErr_Format(PyExc_RuntimeError, "Failed to alloc render primitive data");
|
||||
}
|
||||
}
|
||||
|
||||
/* merge parent options, if the parent was found */
|
||||
if (parent) {
|
||||
parent_options = render_mode_create_options(parent);
|
||||
if (parent_options) {
|
||||
if (PyDict_Merge(ret, parent_options, 0) == -1) {
|
||||
Py_DECREF(ret);
|
||||
Py_DECREF(parent_options);
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(parent_options);
|
||||
ret->iface = iface;
|
||||
|
||||
if (iface->start) {
|
||||
if (iface->start(ret->primitive, state, prim)) {
|
||||
free(ret->primitive);
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* helper to find the first concrete, C interface for a given mode */
|
||||
inline static RenderModeInterface *
|
||||
render_mode_find_interface(const char *mode) {
|
||||
PyObject *custom;
|
||||
const char *custom_parent;
|
||||
RenderMode *render_mode_create(PyObject *mode, RenderState *state) {
|
||||
RenderMode *ret = NULL;
|
||||
PyObject *mode_fast = NULL;
|
||||
unsigned int i;
|
||||
|
||||
/* if it is *itself* concrete, we're done */
|
||||
for (i = 0; render_modes[i] != NULL; i++) {
|
||||
if (strcmp(render_modes[i]->name, mode) == 0)
|
||||
return render_modes[i];
|
||||
}
|
||||
|
||||
/* check for custom modes */
|
||||
custom = PyDict_GetItemString(custom_render_modes, mode);
|
||||
if (custom == NULL)
|
||||
return PyErr_Format(PyExc_RuntimeError, "Failed to find rendermode interface (custom not found)");
|
||||
custom = PyDict_GetItemString(custom, "parent");
|
||||
if (custom == NULL)
|
||||
return PyErr_Format(PyExc_RuntimeError, "Failed to find rendermode interface (parent not found)");
|
||||
custom_parent = PyString_AsString(custom);
|
||||
if (custom_parent == NULL)
|
||||
return NULL; // PyString_AsString sets an exception
|
||||
|
||||
return render_mode_find_interface(custom_parent);
|
||||
}
|
||||
mode_fast = PySequence_Fast(mode, "Mode is not a sequence type");
|
||||
if (!mode_fast)
|
||||
return NULL;
|
||||
|
||||
RenderMode *render_mode_create(const char *mode, RenderState *state) {
|
||||
PyObject *options;
|
||||
RenderMode *ret = NULL;
|
||||
RenderModeInterface *iface = NULL;
|
||||
|
||||
iface = render_mode_find_interface(mode);
|
||||
if (iface == NULL)
|
||||
return NULL;
|
||||
|
||||
options = render_mode_create_options(mode);
|
||||
if (options == NULL)
|
||||
return NULL;
|
||||
|
||||
ret = calloc(1, sizeof(RenderMode));
|
||||
if (ret == NULL) {
|
||||
Py_DECREF(options);
|
||||
return PyErr_Format(PyExc_RuntimeError, "Failed to alloc a rendermode");
|
||||
}
|
||||
|
||||
ret->mode = calloc(1, iface->data_size);
|
||||
if (ret->mode == NULL) {
|
||||
Py_DECREF(options);
|
||||
free(ret);
|
||||
return PyErr_Format(PyExc_RuntimeError, "Failed to alloc rendermode data");
|
||||
}
|
||||
|
||||
ret->iface = iface;
|
||||
ret->state = state;
|
||||
|
||||
if (iface->start(ret->mode, state, options)) {
|
||||
Py_DECREF(options);
|
||||
free(ret->mode);
|
||||
free(ret);
|
||||
return NULL;
|
||||
ret->num_primitives = PySequence_Length(mode);
|
||||
ret->primitives = calloc(ret->num_primitives, sizeof(RenderPrimitive*));
|
||||
for (i = 0; i < ret->num_primitives; i++) {
|
||||
PyObject *pyprim = PySequence_Fast_GET_ITEM(mode_fast, i);
|
||||
RenderPrimitive *prim = render_primitive_create(pyprim, state);
|
||||
|
||||
if (!prim) {
|
||||
render_mode_destroy(ret);
|
||||
Py_DECREF(mode_fast);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->primitives[i] = prim;
|
||||
}
|
||||
|
||||
Py_DECREF(options);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void render_mode_destroy(RenderMode *self) {
|
||||
self->iface->finish(self->mode, self->state);
|
||||
free(self->mode);
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < self->num_primitives; i++) {
|
||||
RenderPrimitive *prim = self->primitives[i];
|
||||
/* we may be destroying a half-constructed mode, so we need this
|
||||
check */
|
||||
if (prim) {
|
||||
if (prim->iface->finish) {
|
||||
prim->iface->finish(prim->primitive, self->state);
|
||||
}
|
||||
if (prim->primitive) {
|
||||
free(prim->primitive);
|
||||
}
|
||||
free(prim);
|
||||
}
|
||||
}
|
||||
free(self->primitives);
|
||||
free(self);
|
||||
}
|
||||
|
||||
int render_mode_occluded(RenderMode *self, int x, int y, int z) {
|
||||
return self->iface->occluded(self->mode, self->state, x, y, z);
|
||||
unsigned int i;
|
||||
int occluded = 0;
|
||||
for (i = 0; i < self->num_primitives; i++) {
|
||||
RenderPrimitive *prim = self->primitives[i];
|
||||
if (prim->iface->occluded) {
|
||||
occluded |= prim->iface->occluded(prim->primitive, self->state, x, y, z);
|
||||
}
|
||||
|
||||
if (occluded)
|
||||
return occluded;
|
||||
}
|
||||
return occluded;
|
||||
}
|
||||
|
||||
int render_mode_hidden(RenderMode *self, int x, int y, int z) {
|
||||
return self->iface->hidden(self->mode, self->state, x, y, z);
|
||||
unsigned int i;
|
||||
int hidden = 0;
|
||||
for (i = 0; i < self->num_primitives; i++) {
|
||||
RenderPrimitive *prim = self->primitives[i];
|
||||
if (prim->iface->hidden) {
|
||||
hidden |= prim->iface->hidden(prim->primitive, self->state, x, y, z);
|
||||
}
|
||||
|
||||
if (hidden)
|
||||
return hidden;
|
||||
}
|
||||
return hidden;
|
||||
}
|
||||
|
||||
void render_mode_draw(RenderMode *self, PyObject *img, PyObject *mask, PyObject *mask_light) {
|
||||
self->iface->draw(self->mode, self->state, img, mask, mask_light);
|
||||
unsigned int i;
|
||||
for (i = 0; i < self->num_primitives; i++) {
|
||||
RenderPrimitive *prim = self->primitives[i];
|
||||
if (prim->iface->draw) {
|
||||
prim->iface->draw(prim->primitive, self->state, img, mask, mask_light);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* options parse helper */
|
||||
int render_mode_parse_option(PyObject *dict, const char *name, const char *format, ...) {
|
||||
int render_mode_parse_option(PyObject *support, const char *name, const char *format, ...) {
|
||||
va_list ap;
|
||||
PyObject *item;
|
||||
PyObject *item, *dict;
|
||||
int ret;
|
||||
|
||||
if (dict == NULL || name == NULL)
|
||||
return 1;
|
||||
if (support == NULL || name == NULL)
|
||||
return 0;
|
||||
|
||||
dict = PyObject_GetAttrString(support, "option_values");
|
||||
if (!dict)
|
||||
return 0;
|
||||
|
||||
item = PyDict_GetItemString(dict, name);
|
||||
if (item == NULL)
|
||||
return 1;
|
||||
if (item == NULL) {
|
||||
Py_DECREF(dict);
|
||||
return 0;
|
||||
};
|
||||
|
||||
/* make sure the item we're parsing is a tuple
|
||||
for VaParse to work correctly */
|
||||
@@ -202,6 +201,7 @@ int render_mode_parse_option(PyObject *dict, const char *name, const char *forma
|
||||
va_end(ap);
|
||||
|
||||
Py_DECREF(item);
|
||||
Py_DECREF(dict);
|
||||
|
||||
if (!ret) {
|
||||
PyObject *errtype, *errvalue, *errtraceback;
|
||||
@@ -219,330 +219,3 @@ int render_mode_parse_option(PyObject *dict, const char *name, const char *forma
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* bindings for python -- get all the rendermode names */
|
||||
PyObject *get_render_modes(PyObject *self, PyObject *args) {
|
||||
PyObject *modes;
|
||||
unsigned int i;
|
||||
PyObject *key, *value;
|
||||
Py_ssize_t pos = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
return NULL;
|
||||
|
||||
modes = PyList_New(0);
|
||||
if (modes == NULL)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; render_modes[i] != NULL; i++) {
|
||||
PyObject *name = PyString_FromString(render_modes[i]->name);
|
||||
PyList_Append(modes, name);
|
||||
Py_DECREF(name);
|
||||
}
|
||||
|
||||
|
||||
while (PyDict_Next(custom_render_modes, &pos, &key, &value)) {
|
||||
PyList_Append(modes, key);
|
||||
}
|
||||
|
||||
return modes;
|
||||
}
|
||||
|
||||
/* helper, get the list of options for a render mode */
|
||||
static inline PyObject *
|
||||
get_render_mode_options(const char *rendermode)
|
||||
{
|
||||
PyObject *options;
|
||||
unsigned int i, j;
|
||||
|
||||
options = PyList_New(0);
|
||||
if (!options)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; render_modes[i] != NULL; i++) {
|
||||
if (strcmp(render_modes[i]->name, rendermode) == 0) {
|
||||
if (render_modes[i]->options == NULL)
|
||||
break;
|
||||
|
||||
for (j = 0; render_modes[i]->options[j].name != NULL; j++) {
|
||||
RenderModeOption opt = render_modes[i]->options[j];
|
||||
PyObject *name = PyString_FromString(opt.name);
|
||||
PyObject *description = PyString_FromString(opt.description);
|
||||
PyObject *option = PyDict_New();
|
||||
if (!name || !description || !option) {
|
||||
Py_XDECREF(name);
|
||||
Py_XDECREF(description);
|
||||
Py_XDECREF(option);
|
||||
Py_DECREF(options);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyDict_SetItemString(option, "name", name);
|
||||
PyDict_SetItemString(option, "description", description);
|
||||
PyList_Append(options, option);
|
||||
Py_DECREF(name);
|
||||
Py_DECREF(description);
|
||||
Py_DECREF(option);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/* more bindings -- return info for a given rendermode name */
|
||||
PyObject *get_render_mode_info(PyObject *self, PyObject *args) {
|
||||
const char* rendermode;
|
||||
PyObject *info;
|
||||
unsigned int i;
|
||||
PyObject *custom;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &rendermode))
|
||||
return NULL;
|
||||
|
||||
info = PyDict_New();
|
||||
if (info == NULL)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; render_modes[i] != NULL; i++) {
|
||||
if (strcmp(render_modes[i]->name, rendermode) == 0) {
|
||||
PyObject *tmp;
|
||||
|
||||
tmp = PyString_FromString(render_modes[i]->name);
|
||||
PyDict_SetItemString(info, "name", tmp);
|
||||
Py_DECREF(tmp);
|
||||
|
||||
tmp = PyString_FromString(render_modes[i]->label);
|
||||
PyDict_SetItemString(info, "label", tmp);
|
||||
Py_DECREF(tmp);
|
||||
|
||||
tmp = PyString_FromString(render_modes[i]->description);
|
||||
PyDict_SetItemString(info, "description", tmp);
|
||||
Py_DECREF(tmp);
|
||||
|
||||
tmp = get_render_mode_options(rendermode);
|
||||
PyDict_SetItemString(info, "options", tmp);
|
||||
Py_DECREF(tmp);
|
||||
|
||||
if (render_modes[i]->parent != NULL) {
|
||||
tmp = PyString_FromString(render_modes[i]->parent->name);
|
||||
PyDict_SetItemString(info, "parent", tmp);
|
||||
Py_DECREF(tmp);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
custom = PyDict_GetItemString(custom_render_modes, rendermode);
|
||||
if (custom) {
|
||||
PyObject *tmp, *copy = PyDict_Copy(custom);
|
||||
Py_DECREF(info);
|
||||
|
||||
tmp = PyString_FromString(rendermode);
|
||||
PyDict_SetItemString(copy, "name", tmp);
|
||||
Py_DECREF(tmp);
|
||||
|
||||
tmp = PyList_New(0);
|
||||
PyDict_SetItemString(copy, "options", tmp);
|
||||
Py_DECREF(tmp);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
Py_DECREF(info);
|
||||
return PyErr_Format(PyExc_ValueError, "invalid rendermode: \"%s\"", rendermode);
|
||||
}
|
||||
|
||||
/* bindings -- get list of inherited parents */
|
||||
PyObject *get_render_mode_inheritance(PyObject *self, PyObject *args) {
|
||||
const char *rendermode;
|
||||
PyObject *parents;
|
||||
unsigned int i;
|
||||
RenderModeInterface *iface = NULL;
|
||||
PyObject *custom;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &rendermode))
|
||||
return NULL;
|
||||
|
||||
parents = PyList_New(0);
|
||||
if (!parents)
|
||||
return NULL;
|
||||
|
||||
/* take care of the chain of custom modes, if there are any */
|
||||
custom = PyDict_GetItemString(custom_render_modes, rendermode);
|
||||
while (custom != NULL) {
|
||||
PyObject *name = PyString_FromString(rendermode);
|
||||
PyList_Append(parents, name);
|
||||
Py_DECREF(name);
|
||||
|
||||
custom = PyDict_GetItemString(custom, "parent");
|
||||
rendermode = PyString_AsString(custom);
|
||||
custom = PyDict_GetItem(custom_render_modes, custom);
|
||||
}
|
||||
|
||||
/* now handle concrete modes */
|
||||
for (i = 0; render_modes[i] != NULL; i++) {
|
||||
if (strcmp(render_modes[i]->name, rendermode) == 0) {
|
||||
iface = render_modes[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!iface) {
|
||||
Py_DECREF(parents);
|
||||
return PyErr_Format(PyExc_ValueError, "invalid rendermode: \"%s\"", rendermode);
|
||||
}
|
||||
|
||||
while (iface) {
|
||||
PyObject *name = PyString_FromString(iface->name);
|
||||
PyList_Append(parents, name);
|
||||
Py_DECREF(name);
|
||||
|
||||
iface = iface->parent;
|
||||
}
|
||||
|
||||
PyList_Reverse(parents);
|
||||
return parents;
|
||||
}
|
||||
|
||||
/* bindings -- get list of (direct) children */
|
||||
PyObject *get_render_mode_children(PyObject *self, PyObject *args) {
|
||||
const char *rendermode;
|
||||
PyObject *children;
|
||||
unsigned int i;
|
||||
PyObject *key, *value;
|
||||
Py_ssize_t pos = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &rendermode))
|
||||
return NULL;
|
||||
|
||||
children = PyList_New(0);
|
||||
if (!children)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; render_modes[i] != NULL; i++) {
|
||||
if (render_modes[i]->parent && strcmp(render_modes[i]->parent->name, rendermode) == 0) {
|
||||
PyObject *child_name = PyString_FromString(render_modes[i]->name);
|
||||
PyList_Append(children, child_name);
|
||||
Py_DECREF(child_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
while (PyDict_Next(custom_render_modes, &pos, &key, &value)) {
|
||||
PyObject *pyparent = PyDict_GetItemString(value, "parent");
|
||||
const char *parent = PyString_AsString(pyparent);
|
||||
|
||||
if (strcmp(parent, rendermode) == 0) {
|
||||
PyList_Append(children, key);
|
||||
}
|
||||
}
|
||||
|
||||
return children;
|
||||
}
|
||||
|
||||
/* helper to decide if a rendermode supports a given option */
|
||||
static inline int
|
||||
render_mode_supports_option(RenderModeInterface *iface, const char *name) {
|
||||
unsigned int i;
|
||||
|
||||
if (iface->options != NULL) {
|
||||
for (i = 0; iface->options[i].name != NULL; i++) {
|
||||
if (strcmp(iface->options[i].name, name) == 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (iface->parent != NULL)
|
||||
return render_mode_supports_option(iface->parent, name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* python rendermode options bindings */
|
||||
PyObject *set_render_mode_options(PyObject *self, PyObject *args) {
|
||||
const char *rendermode;
|
||||
PyObject *opts, *key, *value;
|
||||
Py_ssize_t pos = 0;
|
||||
RenderModeInterface *iface = NULL;
|
||||
if (!PyArg_ParseTuple(args, "sO!", &rendermode, &PyDict_Type, &opts))
|
||||
return NULL;
|
||||
|
||||
iface = render_mode_find_interface(rendermode);
|
||||
|
||||
if (iface == NULL) {
|
||||
return PyErr_Format(PyExc_ValueError, "'%s' is not a valid rendermode name", rendermode);
|
||||
}
|
||||
|
||||
/* check options to make sure they're available */
|
||||
while (PyDict_Next(opts, &pos, &key, &value)) {
|
||||
const char *name = PyString_AsString(key);
|
||||
if (name == NULL)
|
||||
return NULL;
|
||||
|
||||
if (!render_mode_supports_option(iface, name)) {
|
||||
return PyErr_Format(PyExc_ValueError, "'%s' is not a valid option for rendermode '%s'", name, rendermode);
|
||||
}
|
||||
}
|
||||
|
||||
PyDict_SetItemString(render_mode_options, rendermode, opts);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyObject *add_custom_render_mode(PyObject *self, PyObject *args) {
|
||||
const char *rendermode, *parentmode;
|
||||
PyObject *opts, *options, *pyparent;
|
||||
if (!PyArg_ParseTuple(args, "sO!", &rendermode, &PyDict_Type, &opts))
|
||||
return NULL;
|
||||
|
||||
/* first, make sure the parent is set correctly */
|
||||
pyparent = PyDict_GetItemString(opts, "parent");
|
||||
if (pyparent == NULL)
|
||||
return PyErr_Format(PyExc_ValueError, "'%s' does not have a parent mode", rendermode);
|
||||
parentmode = PyString_AsString(pyparent);
|
||||
if (parentmode == NULL)
|
||||
return PyErr_Format(PyExc_ValueError, "'%s' does not have a valid parent", rendermode);
|
||||
|
||||
/* check that parentmode exists */
|
||||
if (PyDict_GetItemString(custom_render_modes, parentmode) == NULL) {
|
||||
unsigned int parent_valid = 0, i;
|
||||
for (i = 0; render_modes[i] != NULL; i++) {
|
||||
if (strcmp(render_modes[i]->name, parentmode) == 0) {
|
||||
parent_valid = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent_valid == 0)
|
||||
return PyErr_Format(PyExc_ValueError, "'%s' parent '%s' is not valid", rendermode, parentmode);
|
||||
}
|
||||
|
||||
/* remove and handle options seperately, if needed */
|
||||
options = PyDict_GetItemString(opts, "options");
|
||||
if (options != NULL) {
|
||||
PyObject *opts_copy, *set_opts_args;
|
||||
|
||||
opts_copy = PyDict_Copy(opts);
|
||||
if (opts_copy == NULL)
|
||||
return NULL;
|
||||
|
||||
PyDict_DelItemString(opts_copy, "options");
|
||||
PyDict_SetItemString(custom_render_modes, rendermode, opts_copy);
|
||||
Py_DECREF(opts_copy);
|
||||
|
||||
/* call set_render_mode_options */
|
||||
set_opts_args = Py_BuildValue("sO", rendermode, options);
|
||||
if (set_opts_args == NULL)
|
||||
return NULL;
|
||||
if (set_render_mode_options(NULL, set_opts_args) == NULL) {
|
||||
Py_DECREF(set_opts_args);
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(set_opts_args);
|
||||
} else {
|
||||
PyDict_SetItemString(custom_render_modes, rendermode, opts);
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
@@ -15,21 +15,27 @@
|
||||
* with the Overviewer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* To make a new render mode (the C part, at least):
|
||||
/* To make a new render primitive:
|
||||
*
|
||||
* * add a data struct and extern'd interface declaration below
|
||||
* * add a new class to rendermodes.py
|
||||
* there are a ton of examples there, the syntax is pretty simple. If
|
||||
* you need any extra objects that are easy to create in python, this
|
||||
* is where you put them.
|
||||
*
|
||||
* * fill in this interface struct in rendermode-(yourmode).c
|
||||
* (see rendermodes-normal.c for an example: the "normal" mode)
|
||||
* * create a file in src/primitives with the same name
|
||||
* so, Nether (named "nether") goes in `nether.c`.
|
||||
*
|
||||
* * if you want to derive from (say) the "normal" mode, put
|
||||
* a RenderModeNormal entry at the top of your data struct, and
|
||||
* be sure to call your parent's functions in your own!
|
||||
* (see rendermode-night.c for a simple example derived from
|
||||
* the "lighting" mode)
|
||||
* * declare a RenderPrimitiveInterface with the name primitive_name
|
||||
* if you have an underscore in the name, replace it with a
|
||||
* hyphen. height-fading uses primitive_height_fading.
|
||||
*
|
||||
* * add your mode to the list in rendermodes.c
|
||||
* * fill in the entries of this struct
|
||||
* the name should match, and you should declare an 'instance' struct
|
||||
* to use as the self argument to each function. See nether.c and
|
||||
* height-fading.c for simple examples.
|
||||
*
|
||||
* setup.py will pick up your primitive, add it to the global list, and build
|
||||
* it for you if you follow these conventions.
|
||||
*/
|
||||
|
||||
#ifndef __RENDERMODES_H_INCLUDED__
|
||||
@@ -38,30 +44,14 @@
|
||||
#include <Python.h>
|
||||
#include "overviewer.h"
|
||||
|
||||
/* render primitive interface */
|
||||
typedef struct {
|
||||
const char *name;
|
||||
const char *description;
|
||||
} RenderModeOption;
|
||||
|
||||
/* rendermode interface */
|
||||
typedef struct _RenderModeInterface RenderModeInterface;
|
||||
struct _RenderModeInterface {
|
||||
/* the name of this mode */
|
||||
const char *name;
|
||||
/* the label to use in the map */
|
||||
const char *label;
|
||||
/* the short description of this render mode */
|
||||
const char *description;
|
||||
|
||||
/* a NULL-terminated list of render mode options, or NULL */
|
||||
RenderModeOption *options;
|
||||
|
||||
/* the rendermode this is derived from, or NULL */
|
||||
RenderModeInterface *parent;
|
||||
const char *name;
|
||||
/* the size of the local storage for this rendermode */
|
||||
unsigned int data_size;
|
||||
|
||||
/* may return non-zero on error, last arg is options */
|
||||
/* may return non-zero on error, last arg is the python support object */
|
||||
int (*start)(void *, RenderState *, PyObject *);
|
||||
void (*finish)(void *, RenderState *);
|
||||
/* returns non-zero to skip rendering this block because it's not visible */
|
||||
@@ -71,7 +61,7 @@ struct _RenderModeInterface {
|
||||
int (*hidden)(void *, RenderState *, int, int, int);
|
||||
/* last two arguments are img and mask, from texture lookup */
|
||||
void (*draw)(void *, RenderState *, PyObject *, PyObject *, PyObject *);
|
||||
};
|
||||
} RenderPrimitiveInterface;
|
||||
|
||||
/* A quick note about the difference between occluded and hidden:
|
||||
*
|
||||
@@ -88,57 +78,32 @@ struct _RenderModeInterface {
|
||||
* example, in lighting mode it is called at most 4 times per block.
|
||||
*/
|
||||
|
||||
/* convenience wrapper for a single primitive + interface */
|
||||
typedef struct {
|
||||
void *primitive;
|
||||
RenderPrimitiveInterface *iface;
|
||||
} RenderPrimitive;
|
||||
|
||||
/* wrapper for passing around rendermodes */
|
||||
struct _RenderMode {
|
||||
void *mode;
|
||||
RenderModeInterface *iface;
|
||||
unsigned int num_primitives;
|
||||
RenderPrimitive **primitives;
|
||||
RenderState *state;
|
||||
};
|
||||
|
||||
/* functions for creating / using rendermodes */
|
||||
RenderMode *render_mode_create(const char *mode, RenderState *state);
|
||||
RenderMode *render_mode_create(PyObject *mode, RenderState *state);
|
||||
void render_mode_destroy(RenderMode *self);
|
||||
int render_mode_occluded(RenderMode *self, int x, int y, int z);
|
||||
int render_mode_hidden(RenderMode *self, int x, int y, int z);
|
||||
void render_mode_draw(RenderMode *self, PyObject *img, PyObject *mask, PyObject *mask_light);
|
||||
|
||||
/* helper function for reading in rendermode options
|
||||
works like PyArg_ParseTuple on a dictionary item */
|
||||
int render_mode_parse_option(PyObject *dict, const char *name, const char *format, ...);
|
||||
works like PyArg_ParseTuple on a support object */
|
||||
int render_mode_parse_option(PyObject *support, const char *name, const char *format, ...);
|
||||
|
||||
/* python metadata bindings */
|
||||
PyObject *get_render_modes(PyObject *self, PyObject *args);
|
||||
PyObject *get_render_mode_info(PyObject *self, PyObject *args);
|
||||
PyObject *get_render_mode_inheritance(PyObject *self, PyObject *args);
|
||||
PyObject *get_render_mode_children(PyObject *self, PyObject *args);
|
||||
|
||||
/* python rendermode options bindings */
|
||||
PyObject *set_render_mode_options(PyObject *self, PyObject *args);
|
||||
PyObject *add_custom_render_mode(PyObject *self, PyObject *args);
|
||||
|
||||
/* individual rendermode interface declarations follow */
|
||||
|
||||
/* NORMAL */
|
||||
typedef struct {
|
||||
/* coordinates of the chunk, inside its region file */
|
||||
int chunk_x, chunk_y;
|
||||
/* biome data for the region */
|
||||
PyObject *biome_data;
|
||||
/* grasscolor and foliagecolor lookup tables */
|
||||
PyObject *grasscolor, *foliagecolor, *watercolor;
|
||||
/* biome-compatible grass/leaf textures */
|
||||
PyObject *grass_texture;
|
||||
|
||||
/* black and white colors for height fading */
|
||||
PyObject *black_color, *white_color;
|
||||
|
||||
float edge_opacity;
|
||||
unsigned int min_depth;
|
||||
unsigned int max_depth;
|
||||
int height_fading;
|
||||
int nether;
|
||||
} RenderModeNormal;
|
||||
extern RenderModeInterface rendermode_normal;
|
||||
/* XXX individual rendermode interface declarations follow */
|
||||
#ifdef OLD_MODES
|
||||
|
||||
/* OVERLAY */
|
||||
typedef struct {
|
||||
@@ -152,54 +117,6 @@ typedef struct {
|
||||
} RenderModeOverlay;
|
||||
extern RenderModeInterface rendermode_overlay;
|
||||
|
||||
/* LIGHTING */
|
||||
typedef struct {
|
||||
/* inherits from normal render mode */
|
||||
RenderModeNormal parent;
|
||||
|
||||
PyObject *facemasks_py;
|
||||
PyObject *facemasks[3];
|
||||
|
||||
/* extra data, loaded off the chunk class */
|
||||
PyObject *skylight, *blocklight;
|
||||
PyObject *left_skylight, *left_blocklight;
|
||||
PyObject *right_skylight, *right_blocklight;
|
||||
PyObject *up_left_skylight, *up_left_blocklight;
|
||||
PyObject *up_right_skylight, *up_right_blocklight;
|
||||
|
||||
/* light color image, loaded if color_light is True */
|
||||
PyObject *lightcolor;
|
||||
|
||||
/* can be overridden in derived rendermodes to control lighting
|
||||
arguments are data, skylight, blocklight, return RGB */
|
||||
void (*calculate_light_color)(void *, unsigned char, unsigned char, unsigned char *, unsigned char *, unsigned char *);
|
||||
|
||||
/* can be set to 0 in derived modes to indicate that lighting the chunk
|
||||
* sides is actually important. Right now, this is used in cave mode
|
||||
*/
|
||||
int skip_sides;
|
||||
|
||||
float shade_strength;
|
||||
int color_light;
|
||||
int night;
|
||||
} RenderModeLighting;
|
||||
extern RenderModeInterface rendermode_lighting;
|
||||
|
||||
/* exposed so it can be used in other per-face occlusion checks */
|
||||
int rendermode_lighting_is_face_occluded(RenderState *state, int skip_sides, int x, int y, int z);
|
||||
|
||||
/* exposed so sub-modes can look at colors directly */
|
||||
void get_lighting_color(RenderModeLighting *self, RenderState *state,
|
||||
int x, int y, int z,
|
||||
unsigned char *r, unsigned char *g, unsigned char *b);
|
||||
|
||||
/* SMOOTH LIGHTING */
|
||||
typedef struct {
|
||||
/* inherits from lighting */
|
||||
RenderModeLighting parent;
|
||||
} RenderModeSmoothLighting;
|
||||
extern RenderModeInterface rendermode_smooth_lighting;
|
||||
|
||||
/* SPAWN */
|
||||
typedef struct {
|
||||
/* inherits from overlay */
|
||||
@@ -209,34 +126,6 @@ typedef struct {
|
||||
} RenderModeSpawn;
|
||||
extern RenderModeInterface rendermode_spawn;
|
||||
|
||||
/* CAVE */
|
||||
typedef struct {
|
||||
/* render blocks with lighting mode */
|
||||
RenderModeLighting parent;
|
||||
|
||||
/* data used to know where the surface is */
|
||||
PyObject *skylight;
|
||||
PyObject *left_skylight;
|
||||
PyObject *right_skylight;
|
||||
PyObject *up_left_skylight;
|
||||
PyObject *up_right_skylight;
|
||||
|
||||
/* data used to know where the surface is */
|
||||
PyObject *blocklight;
|
||||
PyObject *left_blocklight;
|
||||
PyObject *right_blocklight;
|
||||
PyObject *up_left_blocklight;
|
||||
PyObject *up_right_blocklight;
|
||||
|
||||
/* colors used for tinting */
|
||||
PyObject *depth_colors;
|
||||
|
||||
int depth_tinting;
|
||||
int only_lit;
|
||||
int lighting;
|
||||
} RenderModeCave;
|
||||
extern RenderModeInterface rendermode_cave;
|
||||
|
||||
/* MINERAL */
|
||||
typedef struct {
|
||||
/* inherits from overlay */
|
||||
@@ -245,5 +134,6 @@ typedef struct {
|
||||
void *minerals;
|
||||
} RenderModeMineral;
|
||||
extern RenderModeInterface rendermode_mineral;
|
||||
#endif /* OLD_MODES */
|
||||
|
||||
#endif /* __RENDERMODES_H_INCLUDED__ */
|
||||
|
||||
@@ -56,8 +56,11 @@ class Textures(object):
|
||||
def __getstate__(self):
|
||||
# we must get rid of the huge image lists, and other images
|
||||
attributes = self.__dict__.copy()
|
||||
for attr in ['terrain_images', 'blockmap', 'biome_grass_texture', 'watertexture', 'lavatexture']:
|
||||
del attributes[attr]
|
||||
for attr in ['terrain_images', 'blockmap', 'biome_grass_texture', 'watertexture', 'lavatexture', 'lightcolor']:
|
||||
try:
|
||||
del attributes[attr]
|
||||
except KeyError:
|
||||
pass
|
||||
return attributes
|
||||
def __setstate__(self, attrs):
|
||||
# regenerate textures, if needed
|
||||
@@ -245,6 +248,18 @@ class Textures(object):
|
||||
lavatexture = self.load_image("lava.png")
|
||||
self.lavatexture = lavatexture
|
||||
return lavatexture
|
||||
|
||||
def load_light_color(self):
|
||||
"""Helper function to load the light color texture."""
|
||||
if hasattr(self, "lightcolor"):
|
||||
return self.lightcolor
|
||||
try:
|
||||
lightcolor = list(_load_image("light_normal.png").getdata())
|
||||
except Exception:
|
||||
logging.warning("Light color image could not be found.")
|
||||
lightcolor = None
|
||||
self.lightcolor = lightcolor
|
||||
return lightcolor
|
||||
|
||||
def _split_terrain(self, terrain):
|
||||
"""Builds and returns a length 256 array of each 16x16 chunk
|
||||
@@ -650,24 +665,6 @@ def getBiomeData(worlddir, chunkX, chunkY):
|
||||
currentBiomeData = data
|
||||
return data
|
||||
|
||||
##
|
||||
## Color Light
|
||||
##
|
||||
|
||||
lightcolor = None
|
||||
lightcolor_checked = False
|
||||
def loadLightColor():
|
||||
global lightcolor, lightcolor_checked
|
||||
|
||||
if not lightcolor_checked:
|
||||
lightcolor_checked = True
|
||||
try:
|
||||
lightcolor = list(_load_image("light_normal.png").getdata())
|
||||
except Exception:
|
||||
logging.warning("Light color image could not be found.")
|
||||
lightcolor = None
|
||||
return lightcolor
|
||||
|
||||
##
|
||||
## The other big one: @material and associated framework
|
||||
##
|
||||
|
||||
@@ -21,6 +21,7 @@ import imp
|
||||
import os
|
||||
import os.path
|
||||
import sys
|
||||
import platform
|
||||
from subprocess import Popen, PIPE
|
||||
import logging
|
||||
from cStringIO import StringIO
|
||||
@@ -88,6 +89,33 @@ def findGitVersion():
|
||||
except Exception:
|
||||
return "unknown"
|
||||
|
||||
def is_bare_console():
|
||||
"""Returns true if Overviewer is running in a bare console in
|
||||
Windows, that is, if overviewer wasn't started in a cmd.exe
|
||||
session.
|
||||
"""
|
||||
if platform.system() == 'Windows':
|
||||
try:
|
||||
import ctypes
|
||||
GetConsoleProcessList = ctypes.windll.kernel32.GetConsoleProcessList
|
||||
num = GetConsoleProcessList(ctypes.byref(ctypes.c_int(0)), ctypes.c_int(1))
|
||||
if (num == 1):
|
||||
return True
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
return False
|
||||
|
||||
def exit(ret=0):
|
||||
"""Drop-in replacement for sys.exit that will automatically detect
|
||||
bare consoles and wait for user input before closing.
|
||||
"""
|
||||
if ret and is_bare_console():
|
||||
print
|
||||
print "Press [Enter] to close this window."
|
||||
raw_input()
|
||||
sys.exit(ret)
|
||||
|
||||
# http://docs.python.org/library/itertools.html
|
||||
def roundrobin(iterables):
|
||||
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"
|
||||
|
||||
74
setup.py
74
setup.py
@@ -15,6 +15,7 @@ import glob
|
||||
import platform
|
||||
import time
|
||||
import overviewer_core.util as util
|
||||
import numpy
|
||||
|
||||
try:
|
||||
import py2exe
|
||||
@@ -133,7 +134,6 @@ if py2exe is None:
|
||||
#
|
||||
|
||||
# Third-party modules - we depend on numpy for everything
|
||||
import numpy
|
||||
# Obtain the numpy include directory. This logic works across numpy versions.
|
||||
try:
|
||||
numpy_include = numpy.get_include()
|
||||
@@ -149,11 +149,16 @@ except Exception:
|
||||
|
||||
|
||||
# used to figure out what files to compile
|
||||
render_modes = ['normal', 'lighting', 'smooth-lighting', 'cave']
|
||||
render_modes += ['overlay', 'spawn', 'mineral']
|
||||
# auto-created from files in primitives/, but we need the raw names so
|
||||
# we can use them later.
|
||||
primitives = []
|
||||
for name in glob.glob("overviewer_core/src/primitives/*.c"):
|
||||
name = os.path.split(name)[-1]
|
||||
name = os.path.splitext(name)[0]
|
||||
primitives.append(name)
|
||||
|
||||
c_overviewer_files = ['main.c', 'composite.c', 'iterate.c', 'endian.c', 'rendermodes.c']
|
||||
c_overviewer_files += map(lambda mode: 'rendermode-%s.c' % (mode,), render_modes)
|
||||
c_overviewer_files += map(lambda mode: 'primitives/%s.c' % (mode,), primitives)
|
||||
c_overviewer_files += ['Draw.c']
|
||||
c_overviewer_includes = ['overviewer.h', 'rendermodes.h']
|
||||
|
||||
@@ -168,7 +173,7 @@ setup_kwargs['ext_modules'].append(Extension('overviewer_core.c_overviewer', c_o
|
||||
setup_kwargs['options']['build_ext'] = {'inplace' : 1}
|
||||
|
||||
# custom clean command to remove in-place extension
|
||||
# and the version file
|
||||
# and the version file, primitives header
|
||||
class CustomClean(clean):
|
||||
def run(self):
|
||||
# do the normal cleanup
|
||||
@@ -177,31 +182,24 @@ class CustomClean(clean):
|
||||
# try to remove '_composite.{so,pyd,...}' extension,
|
||||
# regardless of the current system's extension name convention
|
||||
build_ext = self.get_finalized_command('build_ext')
|
||||
pretty_fname = build_ext.get_ext_filename('overviewer_core.c_overviewer')
|
||||
fname = pretty_fname
|
||||
if os.path.exists(fname):
|
||||
try:
|
||||
if not self.dry_run:
|
||||
os.remove(fname)
|
||||
log.info("removing '%s'", pretty_fname)
|
||||
except OSError:
|
||||
log.warn("'%s' could not be cleaned -- permission denied",
|
||||
pretty_fname)
|
||||
else:
|
||||
log.debug("'%s' does not exist -- can't clean it",
|
||||
pretty_fname)
|
||||
|
||||
ext_fname = build_ext.get_ext_filename('overviewer_core.c_overviewer')
|
||||
versionpath = os.path.join("overviewer_core", "overviewer_version.py")
|
||||
if os.path.exists(versionpath):
|
||||
try:
|
||||
if not self.dry_run:
|
||||
os.remove(versionpath)
|
||||
log.info("removing '%s'", versionpath)
|
||||
except OSError:
|
||||
log.warn("'%s' could not be cleaned -- permission denied", versionpath)
|
||||
else:
|
||||
log.debug("'%s' does not exist -- can't clean it", versionpath)
|
||||
|
||||
primspath = os.path.join("overviewer_core", "src", "primitives.h")
|
||||
|
||||
for fname in [ext_fname, versionpath, primspath]:
|
||||
if os.path.exists(fname):
|
||||
try:
|
||||
log.info("removing '%s'", fname)
|
||||
if not self.dry_run:
|
||||
os.remove(fname)
|
||||
|
||||
except OSError:
|
||||
log.warn("'%s' could not be cleaned -- permission denied",
|
||||
fname)
|
||||
else:
|
||||
log.debug("'%s' does not exist -- can't clean it",
|
||||
fname)
|
||||
|
||||
# now try to purge all *.pyc files
|
||||
for root, dirs, files in os.walk(os.path.join(os.path.dirname(__file__), ".")):
|
||||
for f in files:
|
||||
@@ -225,16 +223,34 @@ def generate_version_py():
|
||||
except Exception:
|
||||
print "WARNING: failed to build overviewer_version file"
|
||||
|
||||
def generate_primitives_h():
|
||||
global primitives
|
||||
prims = [p.lower().replace('-', '_') for p in primitives]
|
||||
|
||||
outstr = "/* this file is auto-generated by setup.py */\n"
|
||||
for p in prims:
|
||||
outstr += "extern RenderPrimitiveInterface primitive_{0};\n".format(p)
|
||||
outstr += "static RenderPrimitiveInterface *render_primitives[] = {\n"
|
||||
for p in prims:
|
||||
outstr += " &primitive_{0},\n".format(p)
|
||||
outstr += " NULL\n"
|
||||
outstr += "};\n"
|
||||
|
||||
with open("overviewer_core/src/primitives.h", "w") as f:
|
||||
f.write(outstr)
|
||||
|
||||
class CustomSDist(sdist):
|
||||
def run(self):
|
||||
# generate the version file
|
||||
generate_version_py()
|
||||
generate_primitives_h()
|
||||
sdist.run(self)
|
||||
|
||||
class CustomBuild(build):
|
||||
def run(self):
|
||||
# generate the version file
|
||||
generate_version_py()
|
||||
generate_primitives_h()
|
||||
build.run(self)
|
||||
print "\nBuild Complete"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user