0

Merge branch 'dtt-c-render' into lighting

This commit is contained in:
Aaron Griffith
2011-03-21 05:32:10 -04:00
10 changed files with 178 additions and 108 deletions

3
.gitignore vendored
View File

@@ -3,6 +3,9 @@ build
terrain.png terrain.png
cachedir* cachedir*
# user-provided settings file
settings.py
# header files that may be copied over, if missing # header files that may be copied over, if missing
ImPlatform.h ImPlatform.h
Imaging.h Imaging.h

View File

@@ -121,9 +121,9 @@ the same directory as "_composite.c".
Running Running
------- -------
To generate a set of Google Map tiles, use the gmap.py script like this:: To generate a set of Google Map tiles, use the overviewer.py script like this::
python gmap.py [OPTIONS] <World # / Name / Path to World> <Output Directory> python overviewer.py [OPTIONS] <World # / Name / Path to World> <Output Directory>
The output directory will be created if it doesn't exist. This will generate a The output directory will be created if it doesn't exist. This will generate a
set of image tiles for your world in the directory you choose. When it's done, set of image tiles for your world in the directory you choose. When it's done,
@@ -153,7 +153,7 @@ Options
Example:: Example::
python gmap.py --cachedir=<chunk cache dir> <world> <output dir> python overviewer.py --cachedir=<chunk cache dir> <world> <output dir>
--imgformat=FORMAT --imgformat=FORMAT
Set the output image format used for the tiles. The default is 'png', Set the output image format used for the tiles. The default is 'png',
@@ -168,7 +168,7 @@ Options
Example to run 5 worker processes in parallel:: Example to run 5 worker processes in parallel::
python gmap.py -p 5 <Path to World> <Output Directory> python overviewer.py -p 5 <Path to World> <Output Directory>
-z ZOOM, --zoom=ZOOM -z ZOOM, --zoom=ZOOM
The Overviewer by default will detect how many zoom levels are required The Overviewer by default will detect how many zoom levels are required
@@ -191,7 +191,7 @@ Options
This will render your map with 7 zoom levels:: This will render your map with 7 zoom levels::
python gmap.py -z 7 <Path to World> <Output Directory> python overviewer.py -z 7 <Path to World> <Output Directory>
Remember that each additional zoom level adds 4 times as many tiles as Remember that each additional zoom level adds 4 times as many tiles as
the last. This can add up fast, zoom level 10 has over a million tiles. the last. This can add up fast, zoom level 10 has over a million tiles.
@@ -210,13 +210,13 @@ Options
By default, the chunk images are saved in your world directory. This By default, the chunk images are saved in your world directory. This
example will remove them:: example will remove them::
python gmap.py -d <World # / Path to World / Path to cache dir> python overviewer.py -d <World # / Path to World / Path to cache dir>
You can also delete the tile cache as well. This will force a full You can also delete the tile cache as well. This will force a full
re-render, useful if you've changed texture packs and want your world re-render, useful if you've changed texture packs and want your world
to look uniform. Here's an example:: to look uniform. Here's an example::
python gmap.py -d <# / path> <Tile Directory> python overviewer.py -d <# / path> <Tile Directory>
Be warned, this will cause the next rendering of your map to take Be warned, this will cause the next rendering of your map to take
significantly longer, since it is having to re-generate the files you just significantly longer, since it is having to re-generate the files you just

View File

@@ -39,13 +39,16 @@ var signGroups = [
* path : string. Location of the rendered tiles. * path : string. Location of the rendered tiles.
* Optional: * Optional:
* base : string. Base of the url path for tile locations, useful for serving tiles from a different server than the js/html server. * base : string. Base of the url path for tile locations, useful for serving tiles from a different server than the js/html server.
*/
var mapTypeData=[ var mapTypeData=[
{'label': 'Unlit', 'path': 'tiles'}, {'label': 'Unlit', 'path': 'tiles'},
// {'label': 'Day', 'path': 'lighting/tiles'}, // {'label': 'Day', 'path': 'lighting/tiles'},
// {'label': 'Night', 'path': 'night/tiles'}, // {'label': 'Night', 'path': 'night/tiles'},
// {'label': 'Spawn', 'path': 'spawn/tiles', 'base': 'http://example.cdn.amazon.com/'} // {'label': 'Spawn', 'path': 'spawn/tiles', 'base': 'http://example.cdn.amazon.com/'}
]; ];
*/
var mapTypeData = {maptypedata};
// Please leave the following variables here: // Please leave the following variables here:
var markerCollection = {}; // holds groups of markers var markerCollection = {}; // holds groups of markers

View File

@@ -4,7 +4,7 @@ usage = "python contrib/%prog [OPTIONS] <World # / Name / Path to World>"
description = """ description = """
This script will delete files from the old chunk-based cache, a lot This script will delete files from the old chunk-based cache, a lot
like the old `gmap.py -d World/` command. You should only use this if like the old `overviewer.py -d World/` command. You should only use this if
you're updating from an older version of Overviewer, and you want to you're updating from an older version of Overviewer, and you want to
clean up your world folder. clean up your world folder.
""" """
@@ -19,7 +19,7 @@ overviewer_dir = os.path.split(os.path.split(os.path.abspath(__file__))[0])[0]
sys.path.insert(0, overviewer_dir) sys.path.insert(0, overviewer_dir)
import world import world
from gmap import list_worlds from overviewer import list_worlds
def main(): def main():
parser = OptionParser(usage=usage, description=description) parser = OptionParser(usage=usage, description=description)

View File

@@ -11,7 +11,7 @@ To run, simply give a path to your world directory, for example:
Once that is done, simply re-run the overviewer to generate markers.js: Once that is done, simply re-run the overviewer to generate markers.js:
python gmap.py ../world.test/ output_dir/ python overviewer.py ../world.test/ output_dir/
Note: if your cachedir is not the same as your world-dir, you'll need to manually Note: if your cachedir is not the same as your world-dir, you'll need to manually
move overviewer.dat into the correct location. move overviewer.dat into the correct location.

View File

@@ -3,12 +3,12 @@
''' '''
This is used to force the regeneration of any chunks that contain a certain This is used to force the regeneration of any chunks that contain a certain
blockID. The output is a chunklist file that is suitable to use with the blockID. The output is a chunklist file that is suitable to use with the
--chunklist option to gmap.py. --chunklist option to overviewer.py.
Example: Example:
python contrib/rerenderBlocks.py --ids=46,79,91 --world=world/> chunklist.txt python contrib/rerenderBlocks.py --ids=46,79,91 --world=world/> chunklist.txt
python gmap.py --chunklist=chunklist.txt world/ output_dir/ python overviewer.py --chunklist=chunklist.txt world/ output_dir/
This will rerender any chunks that contain either TNT (46), Ice (79), or This will rerender any chunks that contain either TNT (46), Ice (79), or
a Jack-O-Lantern (91) a Jack-O-Lantern (91)

147
googlemap.py Normal file
View File

@@ -0,0 +1,147 @@
# This file is part of the Minecraft Overviewer.
#
# Minecraft Overviewer is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as published
# by the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# Minecraft Overviewer is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with the Overviewer. If not, see <http://www.gnu.org/licenses/>.
import os
import os.path
import cPickle
import Image
import shutil
from time import strftime, gmtime
import json
import util
"""
This module has routines related to generating a Google Maps-based
interface out of a set of tiles.
"""
def mirror_dir(src, dst, entities=None):
'''copies all of the entities from src to dst'''
if not os.path.exists(dst):
os.mkdir(dst)
if entities and type(entities) != list: raise Exception("Expected a list, got a %r instead" % type(entities))
for entry in os.listdir(src):
if entities and entry not in entities: continue
if os.path.isdir(os.path.join(src,entry)):
mirror_dir(os.path.join(src, entry), os.path.join(dst, entry))
elif os.path.isfile(os.path.join(src,entry)):
try:
shutil.copy(os.path.join(src, entry), os.path.join(dst, entry))
except IOError:
# maybe permission problems?
os.chmod(os.path.join(src, entry), stat.S_IRUSR)
os.chmod(os.path.join(dst, entry), stat.S_IWUSR)
shutil.copy(os.path.join(src, entry), os.path.join(dst, entry))
# if this stills throws an error, let it propagate up
class MapGen(object):
def __init__(self, quadtrees, skipjs=False, web_assets_hook=None):
"""Generates a Google Maps interface for the given list of
quadtrees. All of the quadtrees must have the same destdir,
image format, and world."""
self.skipjs = skipjs
self.web_assets_hook = web_assets_hook
if not len(quadtrees) > 0:
raise ValueError("there must be at least one quadtree to work on")
self.destdir = quadtrees[0].destdir
self.imgformat = quadtrees[0].imgformat
self.world = quadtrees[0].world
self.p = quadtrees[0].p
for i in quadtrees:
if i.destdir != self.destdir or i.imgformat != self.imgformat or i.world != self.world:
raise ValueError("all the given quadtrees must have the same destdir")
self.quadtrees = quadtrees
def go(self, procs):
"""Writes out config.js, marker.js, and region.js
Copies web assets into the destdir"""
zoomlevel = self.p
imgformat = self.imgformat
configpath = os.path.join(util.get_program_path(), "config.js")
config = open(configpath, 'r').read()
config = config.replace(
"{maxzoom}", str(zoomlevel))
config = config.replace(
"{imgformat}", str(imgformat))
# create generated map type data, from given quadtrees
maptypedata = map(lambda q: {'label' : q.rendermode.capitalize(),
'path' : q.tiledir}, self.quadtrees)
config = config.replace("{maptypedata}", json.dumps(maptypedata))
with open(os.path.join(self.destdir, "config.js"), 'w') as output:
output.write(config)
# Write a blank image
for quadtree in self.quadtrees:
blank = Image.new("RGBA", (1,1))
tileDir = os.path.join(self.destdir, quadtree.tiledir)
if not os.path.exists(tileDir): os.mkdir(tileDir)
blank.save(os.path.join(tileDir, "blank."+self.imgformat))
# copy web assets into destdir:
mirror_dir(os.path.join(util.get_program_path(), "web_assets"), self.destdir)
# Add time in index.html
indexpath = os.path.join(self.destdir, "index.html")
index = open(indexpath, 'r').read()
index = index.replace(
"{time}", str(strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime())))
with open(os.path.join(self.destdir, "index.html"), 'w') as output:
output.write(index)
if self.skipjs:
if self.web_assets_hook:
self.web_assets_hook(self)
return
# since we will only discover PointsOfInterest in chunks that need to be
# [re]rendered, POIs like signs in unchanged chunks will not be listed
# in self.world.POI. To make sure we don't remove these from markers.js
# we need to merge self.world.POI with the persistant data in world.PersistentData
self.world.POI += filter(lambda x: x['type'] != 'spawn', self.world.persistentData['POI'])
# write out the default marker table
with open(os.path.join(self.destdir, "markers.js"), 'w') as output:
output.write("var markerData=%s" % json.dumps(self.world.POI))
# save persistent data
self.world.persistentData['POI'] = self.world.POI
with open(self.world.pickleFile,"wb") as f:
cPickle.dump(self.world.persistentData,f)
# write out the default (empty, but documented) region table
with open(os.path.join(self.destdir, "regions.js"), 'w') as output:
output.write('var regionData=[\n')
output.write(' // {"color": "#FFAA00", "opacity": 0.5, "closed": true, "path": [\n')
output.write(' // {"x": 0, "y": 0, "z": 0},\n')
output.write(' // {"x": 0, "y": 10, "z": 0},\n')
output.write(' // {"x": 0, "y": 0, "z": 10}\n')
output.write(' // ]},\n')
output.write('];')
if self.web_assets_hook:
self.web_assets_hook(self)

View File

@@ -43,6 +43,7 @@ import optimizeimages
import composite import composite
import world import world
import quadtree import quadtree
import googlemap
helptext = """ helptext = """
%prog [OPTIONS] <World # / Name / Path to World> <tiles dest dir> %prog [OPTIONS] <World # / Name / Path to World> <tiles dest dir>
@@ -159,10 +160,15 @@ def main():
w = world.World(worlddir, useBiomeData=useBiomeData, lighting=options.lighting) w = world.World(worlddir, useBiomeData=useBiomeData, lighting=options.lighting)
w.go(options.procs) w.go(options.procs)
# Now generate the tiles # create the quadtrees
# TODO chunklist # TODO chunklist
q = quadtree.QuadtreeGen(w, destdir, depth=options.zoom, imgformat=imgformat, optimizeimg=optimizeimg, rendermode=options.rendermode, web_assets_hook=options.web_assets_hook) q = quadtree.QuadtreeGen(w, destdir, depth=options.zoom, imgformat=imgformat, optimizeimg=optimizeimg, rendermode=options.rendermode)
q.write_html(options.skipjs)
# write out the map and web assets
m = googlemap.MapGen([q,], skipjs=options.skipjs, web_assets_hook=options.web_assets_hook)
m.go(options.procs)
# render the tiles!
q.go(options.procs) q.go(options.procs)
def delete_all(worlddir, tiledir): def delete_all(worlddir, tiledir):

View File

@@ -42,26 +42,6 @@ This module has routines related to generating a quadtree of tiles
""" """
def mirror_dir(src, dst, entities=None):
'''copies all of the entities from src to dst'''
if not os.path.exists(dst):
os.mkdir(dst)
if entities and type(entities) != list: raise Exception("Expected a list, got a %r instead" % type(entities))
for entry in os.listdir(src):
if entities and entry not in entities: continue
if os.path.isdir(os.path.join(src,entry)):
mirror_dir(os.path.join(src, entry), os.path.join(dst, entry))
elif os.path.isfile(os.path.join(src,entry)):
try:
shutil.copy(os.path.join(src, entry), os.path.join(dst, entry))
except IOError:
# maybe permission problems?
os.chmod(os.path.join(src, entry), stat.S_IRUSR)
os.chmod(os.path.join(dst, entry), stat.S_IWUSR)
shutil.copy(os.path.join(src, entry), os.path.join(dst, entry))
# if this stills throws an error, let it propagate up
def iterate_base4(d): def iterate_base4(d):
"""Iterates over a base 4 number with d digits""" """Iterates over a base 4 number with d digits"""
return itertools.product(xrange(4), repeat=d) return itertools.product(xrange(4), repeat=d)
@@ -90,7 +70,7 @@ def pool_initializer(quadtree):
child_quadtree = quadtree child_quadtree = quadtree
class QuadtreeGen(object): class QuadtreeGen(object):
def __init__(self, worldobj, destdir, depth=None, tiledir="tiles", imgformat=None, optimizeimg=None, rendermode="normal", web_assets_hook=None): def __init__(self, worldobj, destdir, depth=None, tiledir="tiles", imgformat=None, optimizeimg=None, rendermode="normal"):
"""Generates a quadtree from the world given into the """Generates a quadtree from the world given into the
given dest directory given dest directory
@@ -103,11 +83,11 @@ class QuadtreeGen(object):
assert(imgformat) assert(imgformat)
self.imgformat = imgformat self.imgformat = imgformat
self.optimizeimg = optimizeimg self.optimizeimg = optimizeimg
self.web_assets_hook = web_assets_hook
self.lighting = rendermode in ("lighting", "night", "spawn") self.lighting = rendermode in ("lighting", "night", "spawn")
self.night = rendermode in ("night", "spawn") self.night = rendermode in ("night", "spawn")
self.spawn = rendermode in ("spawn",) self.spawn = rendermode in ("spawn",)
self.rendermode = rendermode
# Make the destination dir # Make the destination dir
if not os.path.exists(destdir): if not os.path.exists(destdir):
@@ -161,75 +141,6 @@ class QuadtreeGen(object):
logging.info("{0}/{1} tiles complete on level {2}/{3}".format( logging.info("{0}/{1} tiles complete on level {2}/{3}".format(
complete, total, level, self.p)) complete, total, level, self.p))
def write_html(self, skipjs=False):
"""Writes out config.js, marker.js, and region.js
Copies web assets into the destdir"""
zoomlevel = self.p
imgformat = self.imgformat
configpath = os.path.join(util.get_program_path(), "config.js")
config = open(configpath, 'r').read()
config = config.replace(
"{maxzoom}", str(zoomlevel))
config = config.replace(
"{imgformat}", str(imgformat))
with open(os.path.join(self.destdir, "config.js"), 'w') as output:
output.write(config)
# Write a blank image
blank = Image.new("RGBA", (1,1))
tileDir = os.path.join(self.destdir, self.tiledir)
if not os.path.exists(tileDir): os.mkdir(tileDir)
blank.save(os.path.join(tileDir, "blank."+self.imgformat))
# copy web assets into destdir:
mirror_dir(os.path.join(util.get_program_path(), "web_assets"), self.destdir)
# Add time in index.html
indexpath = os.path.join(self.destdir, "index.html")
index = open(indexpath, 'r').read()
index = index.replace(
"{time}", str(strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime())))
with open(os.path.join(self.destdir, "index.html"), 'w') as output:
output.write(index)
if skipjs:
if self.web_assets_hook:
self.web_assets_hook(self)
return
# since we will only discover PointsOfInterest in chunks that need to be
# [re]rendered, POIs like signs in unchanged chunks will not be listed
# in self.world.POI. To make sure we don't remove these from markers.js
# we need to merge self.world.POI with the persistant data in world.PersistentData
self.world.POI += filter(lambda x: x['type'] != 'spawn', self.world.persistentData['POI'])
# write out the default marker table
with open(os.path.join(self.destdir, "markers.js"), 'w') as output:
output.write("var markerData=%s" % json.dumps(self.world.POI))
# save persistent data
self.world.persistentData['POI'] = self.world.POI
with open(self.world.pickleFile,"wb") as f:
cPickle.dump(self.world.persistentData,f)
# write out the default (empty, but documented) region table
with open(os.path.join(self.destdir, "regions.js"), 'w') as output:
output.write('var regionData=[\n')
output.write(' // {"color": "#FFAA00", "opacity": 0.5, "closed": true, "path": [\n')
output.write(' // {"x": 0, "y": 0, "z": 0},\n')
output.write(' // {"x": 0, "y": 10, "z": 0},\n')
output.write(' // {"x": 0, "y": 0, "z": 10}\n')
output.write(' // ]},\n')
output.write('];')
if self.web_assets_hook:
self.web_assets_hook(self)
def _get_cur_depth(self): def _get_cur_depth(self):
"""How deep is the quadtree currently in the destdir? This glances in """How deep is the quadtree currently in the destdir? This glances in
config.js to see what maxZoom is set to. config.js to see what maxZoom is set to.

View File

@@ -24,7 +24,7 @@ setup_kwargs['cmdclass'] = {}
# #
if py2exe is not None: if py2exe is not None:
setup_kwargs['console'] = ['gmap.py'] setup_kwargs['console'] = ['overviewer.py']
setup_kwargs['data_files'] = [('textures', ['textures/lava.png', 'textures/water.png', 'textures/fire.png']), setup_kwargs['data_files'] = [('textures', ['textures/lava.png', 'textures/water.png', 'textures/fire.png']),
('', ['config.js', 'COPYING.txt', 'README.rst']), ('', ['config.js', 'COPYING.txt', 'README.rst']),
('web_assets', glob.glob('web_assets/*'))] ('web_assets', glob.glob('web_assets/*'))]