0

Merge remote-tracking branch 'origin/rewrite-rendermodes' into rewrite

This commit is contained in:
Andrew Brown
2012-01-16 00:50:57 -05:00
22 changed files with 1001 additions and 1415 deletions

3
.gitignore vendored
View File

@@ -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

View File

@@ -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
# for multiworld, we must specify the *outputdir* on the command line
if len(args) == 1:
logging.debug("Using %r as the output_directory", args[0])
destdir = os.path.expanduser(args[0])
elif len(args) < 1:
# 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()
doExit(code=1, consoleMsg=True)
return 1
# for multiworld, we must specify the *outputdir* on the command line
elif len(args) == 1:
logging.debug("Using %r as the output_directory", args[0])
destdir = os.path.expanduser(args[0])
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)

View File

@@ -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 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:
pass
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)

View File

@@ -16,9 +16,97 @@
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():
class RenderPrimitive(object):
options = {}
name = None
def __init__(self, **kwargs):
if self.name is None:
raise RuntimeError("RenderPrimitive cannot be used directly")
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
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)
@@ -45,30 +133,8 @@ def generate_facemasks():
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))
self._facemasks = (top, left, right)
return self._facemasks
# 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)
if z < 32:
g += 7
elif z < 64:
r -= 7
elif z < 96:
b += 7
else:
g -= 7
return depth_colors
depth_colors = generate_depthcolors()
class SmoothLighting(Lighting):
name = "smooth-lighting"

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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;
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;
}
base_hidden(void *data, RenderState *state, int x, int y, int z) {
PrimitiveBase *self = (PrimitiveBase *)data;
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,
};

View File

@@ -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,9 +96,10 @@ 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) ) {
@@ -133,25 +151,10 @@ 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;
/* first, check to see if it's "normally" hidden */
if (rendermode_lighting.hidden(data, state, x, y, z))
return 1;
self = (RenderPrimitiveCave *)data;
/* check if the block is touching skylight */
if (z != 127) {
@@ -190,10 +193,7 @@ 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)) &&
@@ -201,41 +201,18 @@ rendermode_cave_hidden(void *data, RenderState *state, int x, int y, int z) {
return 1;
}
return rendermode_cave_adjacent_occluded(data, state, x, y, z);
}
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);
self->left_skylight = get_chunk_data(state, DOWN_LEFT, 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,
};

View 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,
};

View 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,
};

View 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,
};

View 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,
};

View File

@@ -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;
lighting_start(void *data, RenderState *state, PyObject *support) {
RenderPrimitiveLighting* self;
self = (RenderPrimitiveLighting *)data;
/* first, chain up */
int ret = rendermode_normal.start(data, state, options);
if (ret != 0)
return ret;
/* don't skip sides by default */
self->skip_sides = 0;
self = (RenderModeLighting *)data;
/* skip sides by default */
self->skip_sides = 1;
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;
if (!render_mode_parse_option(support, "night", "i", &(self->night)))
return 1;
if (!render_mode_parse_option(support, "color", "i", &(self->color)))
return 1;
self->night = 0;
if (!render_mode_parse_option(options, "night", "i", &(self->night)))
return 1;
self->color_light = 0;
if (!render_mode_parse_option(options, "color_light", "i", &(self->color_light)))
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,
};

View 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);

View 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,
};

View File

@@ -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 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,
};

View File

@@ -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,
/* 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.
&rendermode_spawn,
&rendermode_mineral,
NULL
};
PyObject *render_mode_options = NULL;
PyObject *custom_render_modes = NULL;
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;
base_options = PyDict_GetItemString(render_mode_options, mode);
if (base_options) {
ret = PyDict_Copy(base_options);
} else {
ret = PyDict_New();
}
pyname = PyObject_GetAttrString(prim, "name");
if (!pyname)
return NULL;
name = PyString_AsString(pyname);
/* 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);
/* 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);
if (iface == NULL)
return (RenderPrimitive *)PyErr_Format(PyExc_RuntimeError, "invalid primitive name: %s", name);
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);
ret->iface = iface;
if (iface->start) {
if (iface->start(ret->primitive, state, prim)) {
free(ret->primitive);
free(ret);
return NULL;
}
Py_DECREF(parent_options);
}
}
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);
}
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)
mode_fast = PySequence_Fast(mode, "Mode is not a sequence type");
if (!mode_fast)
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;
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 (iface->start(ret->mode, state, options)) {
Py_DECREF(options);
free(ret->mode);
free(ret);
if (!prim) {
render_mode_destroy(ret);
Py_DECREF(mode_fast);
return NULL;
}
Py_DECREF(options);
ret->primitives[i] = prim;
}
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;
}

View File

@@ -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;
/* 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__ */

View File

@@ -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']:
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
@@ -246,6 +249,18 @@ class Textures(object):
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
of texture.
@@ -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
##

View File

@@ -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"

View File

@@ -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,30 +182,23 @@ 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
ext_fname = build_ext.get_ext_filename('overviewer_core.c_overviewer')
versionpath = os.path.join("overviewer_core", "overviewer_version.py")
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)
log.info("removing '%s'", pretty_fname)
except OSError:
log.warn("'%s' could not be cleaned -- permission denied",
pretty_fname)
fname)
else:
log.debug("'%s' does not exist -- can't clean it",
pretty_fname)
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)
fname)
# now try to purge all *.pyc files
for root, dirs, files in os.walk(os.path.join(os.path.dirname(__file__), ".")):
@@ -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"