0

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

This commit is contained in:
Aaron Griffith
2011-04-13 02:42:22 -04:00
8 changed files with 272 additions and 61 deletions

View File

@@ -4,6 +4,8 @@ import os, shutil, tempfile, time, sys, math, re
from subprocess import Popen, PIPE, STDOUT, CalledProcessError from subprocess import Popen, PIPE, STDOUT, CalledProcessError
from optparse import OptionParser from optparse import OptionParser
overviewer_scripts = ['./overviewer.py', './gmap.py']
def check_call(*args, **kwargs): def check_call(*args, **kwargs):
quiet = False quiet = False
if "quiet" in kwargs.keys(): if "quiet" in kwargs.keys():
@@ -35,12 +37,21 @@ def check_output(*args, **kwargs):
def clean_render(overviewerargs, quiet): def clean_render(overviewerargs, quiet):
tempdir = tempfile.mkdtemp('mc-overviewer-test') tempdir = tempfile.mkdtemp('mc-overviewer-test')
overviewer_script = None
for script in overviewer_scripts:
if os.path.exists(script):
overviewer_script = script
break
if overviewer_script is None:
sys.stderr.write("could not find main overviewer script\n")
sys.exit(1)
try: try:
# check_call raises CalledProcessError when overviewer.py exits badly # check_call raises CalledProcessError when overviewer.py exits badly
check_call(['python', 'setup.py', 'clean', 'build'], quiet=quiet) check_call(['python', 'setup.py', 'clean', 'build'], quiet=quiet)
check_call(['./overviewer.py', '-d'] + overviewerargs, quiet=quiet) check_call([overviewer_script, '-d'] + overviewerargs, quiet=quiet)
starttime = time.time() starttime = time.time()
check_call(['./overviewer.py',] + overviewerargs + [tempdir,], quiet=quiet) check_call([overviewer_script,] + overviewerargs + [tempdir,], quiet=quiet)
endtime = time.time() endtime = time.time()
return endtime - starttime return endtime - starttime

View File

@@ -129,38 +129,6 @@ fluid_blocks = set([8,9,10,11])
# (glass, half blocks) # (glass, half blocks)
nospawn_blocks = set([20,44]) nospawn_blocks = set([20,44])
# chunkcoords should be the coordinates of a possible chunk. it may not exist
def render_to_image(chunkcoords, img, imgcoords, quadtreeobj, cave=False, queue=None):
"""Used to render a chunk to a tile in quadtree.py.
chunkcoords is a tuple: (chunkX, chunkY)
imgcoords is as well: (imgX, imgY), which represents the "origin"
to use for drawing.
If the chunk doesn't exist, return False.
Else, returns True."""
a = ChunkRenderer(chunkcoords, quadtreeobj.world, quadtreeobj.rendermode, queue)
try:
a.chunk_render(img, imgcoords[0], imgcoords[1], cave)
return True
except ChunkCorrupt:
# This should be non-fatal, but should print a warning
pass
except Exception, e:
import traceback
traceback.print_exc()
raise
except KeyboardInterrupt:
print
print "You pressed Ctrl-C. Exiting..."
# Raise an exception that is an instance of Exception. Unlike
# KeyboardInterrupt, this will re-raise in the parent, killing the
# entire program, instead of this process dying and the parent waiting
# forever for it to finish.
raise Exception()
return False
class ChunkCorrupt(Exception): class ChunkCorrupt(Exception):
pass pass

View File

@@ -160,7 +160,12 @@ function initMarkers() {
if (markersInit) { return; } if (markersInit) { return; }
markersInit = true; markersInit = true;
// first, give all collections an empty array to work with
for (i in signGroups) {
markerCollection[signGroups[i].label] = [];
}
for (i in markerData) { for (i in markerData) {
var item = markerData[i]; var item = markerData[i];
@@ -202,11 +207,8 @@ function initMarkers() {
icon: iconURL, icon: iconURL,
visible: false visible: false
}); });
if (markerCollection[label]) {
markerCollection[label].push(marker); markerCollection[label].push(marker);
} else {
markerCollection[label] = [marker];
}
if (item.type == 'sign') { if (item.type == 'sign') {
prepareSignMarker(marker, item); prepareSignMarker(marker, item);

View File

@@ -144,7 +144,13 @@ class MapGen(object):
# write out the default marker table # write out the default marker table
with open(os.path.join(self.destdir, "markers.js"), 'w') as output: with open(os.path.join(self.destdir, "markers.js"), 'w') as output:
output.write("var markerData=%s" % json.dumps(self.world.POI)) output.write("var markerData=[\n")
for marker in self.world.POI:
output.write(json.dumps(marker))
if marker != self.world.POI[-1]:
output.write(",")
output.write("\n")
output.write("]\n")
# save persistent data # save persistent data
self.world.persistentData['POI'] = self.world.POI self.world.persistentData['POI'] = self.world.POI

View File

@@ -23,11 +23,14 @@ advdef = "advdef"
def check_programs(level): def check_programs(level):
path = os.environ.get("PATH").split(os.pathsep) path = os.environ.get("PATH").split(os.pathsep)
def exists_in_path(prog):
result = filter(lambda x: os.path.exists(os.path.join(x, prog)), path)
return len(result) != 0
for prog,l in [(pngcrush,1), (optipng,2), (advdef,2)]: for prog,l in [(pngcrush,1), (optipng,2), (advdef,2)]:
if l <= level: if l <= level:
result = filter(lambda x: os.path.exists(os.path.join(x, prog)), path) if (not exists_in_path(prog)) and (not exists_in_path(prog + ".exe")):
if len(result) == 0:
raise Exception("Optimization prog %s for level %d not found!" % (prog, l)) raise Exception("Optimization prog %s for level %d not found!" % (prog, l))
def optimize_image(imgpath, imgformat, optimizeimg): def optimize_image(imgpath, imgformat, optimizeimg):

View File

@@ -453,11 +453,13 @@ class QuadtreeGen(object):
ypos = -96 + (row-rowstart)*96 ypos = -96 + (row-rowstart)*96
# draw the chunk! # draw the chunk!
a = chunk.ChunkRenderer((chunkx, chunky), world, rendermode, poi_queue) try:
a.chunk_render(tileimg, xpos, ypos, None) a = chunk.ChunkRenderer((chunkx, chunky), world, rendermode, poi_queue)
# chunk.render_to_image((chunkx, chunky), tileimg, (xpos, ypos), self, False, None) a.chunk_render(tileimg, xpos, ypos, None)
except chunk.ChunkCorrupt:
# an error was already printed
pass
# Save them # Save them
tileimg.save(imgpath) tileimg.save(imgpath)

View File

@@ -272,10 +272,10 @@ def _build_full_block(top, side1, side2, side3, side4, bottom=None, blockID=None
build a full block with four differnts faces. All images should be 16x16 build a full block with four differnts faces. All images should be 16x16
image objects. Returns a 24x24 image. Can be used to render any block. image objects. Returns a 24x24 image. Can be used to render any block.
side1 is in the -y face of the cube (top left) side1 is in the -y face of the cube (top left, east)
side2 is in the +x (top right) side2 is in the +x (top right, south)
side3 is in the -x (bottom left) side3 is in the -x (bottom left, north)
side4 is in the +y (bottom right) side4 is in the +y (bottom right, west)
A non transparent block uses top, side 3 and side 4 A non transparent block uses top, side 3 and side 4
@@ -354,9 +354,9 @@ def _build_blockimages():
# 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 # 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
-1, -1, -1, -1, -1, 13, 12, 29, 28, 23, 22, -1, -1, 7, 8, 35, # Gold/iron blocks? Doublestep? TNT from above? -1, -1, -1, -1, -1, 13, 12, 29, 28, 23, 22, -1, -1, 7, 8, 35, # Gold/iron blocks? Doublestep? TNT from above?
# 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 # 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
36, 37, -1, -1, 65, 4, 25, -1, 98, 24, -1, -1, 86, -1, -1, -1, # Torch from above? leaving out fire. Redstone wire? Crops/furnaces handled elsewhere. sign post 36, 37, -1, -1, 65, -1, 25, -1, 98, 24, -1, -1, 86, -1, -1, -1, # Torch from above? leaving out fire. Redstone wire? Crops/furnaces handled elsewhere. sign post
# 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 # 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
-1, -1, -1, 16, -1, -1, -1, -1, -1, 51, 51, -1, -1, -1, 66, 67, # door,ladder left out. Minecart rail orientation, redstone torches -1, -1, -1, -1, -1, -1, -1, -1, -1, 51, 51, -1, -1, -1, 66, 67, # door,ladder left out. Minecart rail orientation, redstone torches
# 80 81 82 83 84 85 86 87 88 89 90 91 # 80 81 82 83 84 85 86 87 88 89 90 91
66, 69, 72, 73, 74, -1,102,103,104,105,-1, 102 # clay? 66, 69, 72, 73, 74, -1,102,103,104,105,-1, 102 # clay?
] ]
@@ -371,9 +371,9 @@ def _build_blockimages():
# 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 # 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
-1, -1, -1, -1, -1, 13, 12, 29, 28, 23, 22, -1, -1, 7, 8, 35, -1, -1, -1, -1, -1, 13, 12, 29, 28, 23, 22, -1, -1, 7, 8, 35,
# 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 # 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
36, 37, -1, -1, 65, 4, 25,101, 98, 24, -1, -1, 86, -1, -1, -1, 36, 37, -1, -1, 65, -1, 25,101, 98, 24, -1, -1, 86, -1, -1, -1,
# 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 # 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
-1, -1, -1, 16, -1, -1, -1, -1, -1, 51, 51, -1, -1, -1, 66, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, 51, 51, -1, -1, -1, 66, 67,
# 80 81 82 83 84 85 86 87 88 89 90 91 # 80 81 82 83 84 85 86 87 88 89 90 91
66, 69, 72, 73, 74,-1 ,118,103,104,105, -1, 118 66, 69, 72, 73, 74,-1 ,118,103,104,105, -1, 118
] ]
@@ -663,6 +663,75 @@ def generate_special_texture(blockID, data):
return (img.convert("RGB"), img.split()[3]) return (img.convert("RGB"), img.split()[3])
if blockID in (53,67): # wooden and cobblestone stairs.
if blockID == 53: # wooden
texture = terrain_images[4]
elif blockID == 67: # cobblestone
texture = terrain_images[16]
side = texture.copy()
half_block_u = texture.copy() # up, down, left, right
half_block_d = texture.copy()
half_block_l = texture.copy()
half_block_r = texture.copy()
# generate needed geometries
ImageDraw.Draw(side).rectangle((0,0,7,6),outline=(0,0,0,0),fill=(0,0,0,0))
ImageDraw.Draw(half_block_u).rectangle((0,8,15,15),outline=(0,0,0,0),fill=(0,0,0,0))
ImageDraw.Draw(half_block_d).rectangle((0,0,15,6),outline=(0,0,0,0),fill=(0,0,0,0))
ImageDraw.Draw(half_block_l).rectangle((8,0,15,15),outline=(0,0,0,0),fill=(0,0,0,0))
ImageDraw.Draw(half_block_r).rectangle((0,0,7,15),outline=(0,0,0,0),fill=(0,0,0,0))
if data == 0: # ascending south
img = _build_full_block(half_block_r, None, None, half_block_d, side.transpose(Image.FLIP_LEFT_RIGHT))
tmp1 = transform_image_side(half_block_u)
# Darken the vertical part of the second step
sidealpha = tmp1.split()[3]
# darken it a bit more than usual, looks better
tmp1 = ImageEnhance.Brightness(tmp1).enhance(0.8)
tmp1.putalpha(sidealpha)
composite.alpha_over(img, tmp1, (6,3))
tmp2 = transform_image(half_block_l)
composite.alpha_over(img, tmp2, (0,6))
elif data == 1: # ascending north
img = Image.new("RGBA", (24,24), (38,92,255,0)) # first paste the texture in the back
tmp1 = transform_image(half_block_r)
composite.alpha_over(img, tmp1, (0,6))
tmp2 = _build_full_block(half_block_l, None, None, texture, side)
composite.alpha_over(img, tmp2)
elif data == 2: # ascending west
img = Image.new("RGBA", (24,24), (38,92,255,0)) # first paste the texture in the back
tmp1 = transform_image(half_block_u)
composite.alpha_over(img, tmp1, (0,6))
tmp2 = _build_full_block(half_block_d, None, None, side, texture)
composite.alpha_over(img, tmp2)
elif data == 3: # ascending east
img = _build_full_block(half_block_u, None, None, side.transpose(Image.FLIP_LEFT_RIGHT), half_block_d)
tmp1 = transform_image_side(half_block_u).transpose(Image.FLIP_LEFT_RIGHT)
# Darken the vertical part of the second step
sidealpha = tmp1.split()[3]
# darken it a bit more than usual, looks better
tmp1 = ImageEnhance.Brightness(tmp1).enhance(0.7)
tmp1.putalpha(sidealpha)
composite.alpha_over(img, tmp1, (6,3))
tmp2 = transform_image(half_block_d)
composite.alpha_over(img, tmp2, (0,6))
# touch up a (horrible) pixel
img.putpixel((18,3),(0,0,0,0))
return (img.convert("RGB"), img.split()[3])
if blockID == 55: # redstone wire if blockID == 55: # redstone wire
if data & 0b1000000 == 64: # powered redstone wire if data & 0b1000000 == 64: # powered redstone wire
@@ -1146,8 +1215,8 @@ def getBiomeData(worlddir, chunkX, chunkY):
# (when adding new blocks here and in generate_special_textures, # (when adding new blocks here and in generate_special_textures,
# please, if possible, keep the ascending order of blockid value) # please, if possible, keep the ascending order of blockid value)
special_blocks = set([2, 9, 17, 18, 23, 35, 43, 44, 50, 51, 55, 58, 59, \ special_blocks = set([2, 9, 17, 18, 23, 35, 43, 44, 50, 51, 53, 55, 58, 59, \
61, 62, 64, 65, 66, 71, 75, 76, 85, 86, 91, 92]) 61, 62, 64, 65, 66, 67, 71, 75, 76, 85, 86, 91, 92])
# this is a map of special blockIDs to a list of all # this is a map of special blockIDs to a list of all
# possible values for ancillary data that it might have. # possible values for ancillary data that it might have.
@@ -1162,14 +1231,16 @@ special_map[43] = range(4) # stone, sandstone, wooden and cobblestone double-sl
special_map[44] = range(4) # stone, sandstone, wooden and cobblestone slab special_map[44] = range(4) # stone, sandstone, wooden and cobblestone slab
special_map[50] = (1,2,3,4,5) # torch, position in the block special_map[50] = (1,2,3,4,5) # torch, position in the block
special_map[51] = range(16) # fire, position in the block (not implemented) special_map[51] = range(16) # fire, position in the block (not implemented)
special_map[53] = range(4) # wooden stairs, orientation
special_map[55] = range(128) # redstone wire, all the possible combinations special_map[55] = range(128) # redstone wire, all the possible combinations
special_map[58] = (0,) # crafting table special_map[58] = (0,) # crafting table
special_map[59] = range(8) # crops, grow from 0 to 7 special_map[59] = range(8) # crops, grow from 0 to 7
special_map[61] = range(6) # furnace, orientation (not implemented) special_map[61] = range(6) # furnace, orientation (not implemented)
special_map[62] = range(6) # burning furnace, orientation (not implemented) special_map[62] = range(6) # burning furnace, orientation (not implemented)
special_map[64] = range(16) # wooden door, open/close and orientation special_map[64] = range(16) # wooden door, open/close and orientation
special_map[65] = (2,3,4,5) # ladder, orientation (not implemented) special_map[65] = (2,3,4,5) # ladder, orientation
special_map[66] = range(10) # minecrart tracks, orientation, slope special_map[66] = range(10) # minecrart tracks, orientation, slope
special_map[67] = range(4) # cobblestone stairs, orientation
special_map[71] = range(16) # iron door, open/close and orientation special_map[71] = range(16) # iron door, open/close and orientation
special_map[75] = (1,2,3,4,5) # off redstone torch, orientation special_map[75] = (1,2,3,4,5) # off redstone torch, orientation
special_map[76] = (1,2,3,4,5) # on redstone torch, orientation special_map[76] = (1,2,3,4,5) # on redstone torch, orientation

View File

@@ -1 +1,149 @@
# TODO: put something useful in this file! ################################################################################
# Please see the README or https://github.com/brownan/Minecraft-Overviewer/wiki/DTT-Upgrade-Guide
# for more details.
# To use this file, simply copy it to settings.py and make any necessary changes
# to suite your needs.
# This file is a python script, so you can import and python module you wish or
# use any built-in python function, though this is not normally necessary
# Lines that start with a hash mark are comments
# Some variables come with defaults (like procs or rendermode)
# If you specify a configuration option in both a settings.py file and on the
# command line, the value from the command line will take precedence
################################################################################
### procs
## Specify the number of processors to use for rendering
## Default: The number of CPU cores on your machine
## Type: integer
## Example: set the number of processors to use to be 1 less than the number of
## CPU cpus in your machine
import multiprocessing
procs = multiprocessing.cpu_count() - 1
if procs < 1: procs = 1
################################################################################
### zoom
## Sets the zoom level manually instead of calculating it. This can be useful
## if you have outlier chunks that make your world too big. This value will
## make the highest zoom level contain (2**ZOOM)^2 tiles
## Normally you should not need to set this variable.
## Default: Automatically calculated from your world
## Type: integer
## Example:
zoom = 9
################################################################################
### regionlist
## A file containing, on each line, a path to a chunkfile to update. Instead
## of scanning the world directory for chunks, it will just use this list.
## Normal caching rules still apply.
## Default: not yet
## Type: string
## Example: Dynamically create regionlist of only regions older than 2 days
import os, time
regionDir = os.path.join(args[0], "region")
regionFiles = filter(lambda x: x.endswith(".mcr"), os.listdir(regionDir))
def olderThanTwoDays(f):
return time.time() - os.stat(f).st_mtime > (60*60*24*2)
oldRegionFiles = filter(olderThanTwoDays, regionFiles)
with open("regionlist.txt", "w") as f:
f.write("\n".join(oldRegionFiles))
################################################################################
### rendermode
## Specifies the render types
## Default: "normal"
## Type: Either a list of strings, or a single string containing modes separated
## by commas
## Example: Render the using the 'lighting' mode, but if today is Sunday, then
## also render the 'night' mode
import time
rendermode=["lighting"]
if time.localtime().tm_wday == 6:
rendermode.append("night")
################################################################################
### imgformat
## The image output format to use. Currently supported: png(default), jpg.
## NOTE: png will always be used as the intermediate image format.
## Default: not yet
## Type: string
## Example:
imgformat = "jpg"
################################################################################
### optimizeimg
## If using png, perform image file size optimizations on the output. Specify 1
## for pngcrush, 2 for pngcrush+optipng+advdef. This may double (or more)
## render times, but will produce up to 30% smaller images. NOTE: requires
## corresponding programs in $PATH or %PATH%
## Default: not set
## Type: integer
## Example:
if imgformat != "jpg":
optimizeimg = 2
################################################################################
### web_assets_hook
## If provided, run this function after the web assets have been copied, but
## before actual tile rendering beings. It should accept a QuadtreeGen
## object as its only argument. Note: this is only called if skipjs is True
## Default: not yet
## Type: function
## Example: Call an external program to generate something useful
def web_assets_hook(o):
import subprocess
p = subprocess.Popen(["/path/to/my/script.pl", "--output_dir", args[1]])
p.wait()
if p.returncode != 0:
raise Exception("web_assets_hook failed")
################################################################################
### quiet
## Print less output. You can specify higher values to suppress additional output
## Default: 0
## Type: integer
## Example:
quiet = 1
################################################################################
### verbose
## Print more output. You can specify higher values to print additional output
## Default: 0
## Type: integer
## Example:
verbose = 1
################################################################################
### skipjs
## Don't output marker.js or region.js
## Default: False
## Type: boolean
## Example: Set skipjs if web_assets_hook is defined
if "web_assets_hook" in locals():
skipjs = True