Adds spawn output rendering (variant of night which shows dark areas in red) and support for multiple map types with buttons to switch between them.
This commit is contained in:
36
chunk.py
36
chunk.py
@@ -112,6 +112,18 @@ def iterate_chunkblocks(xoff,yoff):
|
|||||||
transparent_blocks = set([0, 6, 8, 9, 18, 20, 37, 38, 39, 40, 44, 50, 51, 52, 53,
|
transparent_blocks = set([0, 6, 8, 9, 18, 20, 37, 38, 39, 40, 44, 50, 51, 52, 53,
|
||||||
59, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 79, 81, 83, 85])
|
59, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 79, 81, 83, 85])
|
||||||
|
|
||||||
|
# This set holds block ids that are solid blocks
|
||||||
|
solid_blocks = set([1, 2, 3, 4, 5, 7, 12, 13, 14, 15, 16, 17, 18, 19, 20, 35,
|
||||||
|
41, 42, 43, 44, 45, 46, 47, 48, 49, 53, 54, 56, 57, 58, 60, 61, 62, 64, 65,
|
||||||
|
66, 67, 71, 73, 74, 78, 79, 80, 81, 82, 84, 86, 87, 88, 89, 91])
|
||||||
|
|
||||||
|
# This set holds block ids that are fluid blocks
|
||||||
|
fluid_blocks = set([8,9,10,11])
|
||||||
|
|
||||||
|
# This set holds block ids that are not candidates for spawning mobs on
|
||||||
|
# (glass, half blocks)
|
||||||
|
nospawn_blocks = set([20,44])
|
||||||
|
|
||||||
def render_and_save(chunkfile, cachedir, worldobj, cave=False, queue=None):
|
def render_and_save(chunkfile, cachedir, worldobj, cave=False, queue=None):
|
||||||
"""Used as the entry point for the multiprocessing workers (since processes
|
"""Used as the entry point for the multiprocessing workers (since processes
|
||||||
can't target bound methods) or to easily render and save one chunk
|
can't target bound methods) or to easily render and save one chunk
|
||||||
@@ -617,6 +629,13 @@ class ChunkRenderer(object):
|
|||||||
# block shaded with the current
|
# block shaded with the current
|
||||||
# block's light
|
# block's light
|
||||||
black_coeff, _ = self.get_lighting_coefficient(x, y, z)
|
black_coeff, _ = self.get_lighting_coefficient(x, y, z)
|
||||||
|
if self.world.spawn and black_coeff > 0.8 and blockid in solid_blocks and not (
|
||||||
|
blockid in nospawn_blocks or (
|
||||||
|
z != 127 and (blocks[x,y,z+1] in solid_blocks or blocks[x,y,z+1] in fluid_blocks)
|
||||||
|
)
|
||||||
|
):
|
||||||
|
composite.alpha_over(img, Image.blend(t[0], red_color, black_coeff), (imgx, imgy), t[1])
|
||||||
|
else:
|
||||||
composite.alpha_over(img, Image.blend(t[0], black_color, black_coeff), (imgx, imgy), t[1])
|
composite.alpha_over(img, Image.blend(t[0], black_color, black_coeff), (imgx, imgy), t[1])
|
||||||
else:
|
else:
|
||||||
# draw each face lit appropriately,
|
# draw each face lit appropriately,
|
||||||
@@ -625,18 +644,28 @@ class ChunkRenderer(object):
|
|||||||
|
|
||||||
# top face
|
# top face
|
||||||
black_coeff, face_occlude = self.get_lighting_coefficient(x, y, z + 1)
|
black_coeff, face_occlude = self.get_lighting_coefficient(x, y, z + 1)
|
||||||
|
# Use red instead of black for spawnable blocks
|
||||||
|
if self.world.spawn and black_coeff > 0.8 and blockid in solid_blocks and not (
|
||||||
|
blockid in nospawn_blocks or (
|
||||||
|
z != 127 and (blocks[x,y,z+1] in solid_blocks or blocks[x,y,z+1] in fluid_blocks)
|
||||||
|
)
|
||||||
|
):
|
||||||
|
over_color = red_color
|
||||||
|
else:
|
||||||
|
over_color = black_color
|
||||||
|
|
||||||
if not face_occlude:
|
if not face_occlude:
|
||||||
composite.alpha_over(img, black_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[0]).enhance(black_coeff))
|
composite.alpha_over(img, over_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[0]).enhance(black_coeff))
|
||||||
|
|
||||||
# left face
|
# left face
|
||||||
black_coeff, face_occlude = self.get_lighting_coefficient(x - 1, y, z)
|
black_coeff, face_occlude = self.get_lighting_coefficient(x - 1, y, z)
|
||||||
if not face_occlude:
|
if not face_occlude:
|
||||||
composite.alpha_over(img, black_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[1]).enhance(black_coeff))
|
composite.alpha_over(img, over_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[1]).enhance(black_coeff))
|
||||||
|
|
||||||
# right face
|
# right face
|
||||||
black_coeff, face_occlude = self.get_lighting_coefficient(x, y + 1, z)
|
black_coeff, face_occlude = self.get_lighting_coefficient(x, y + 1, z)
|
||||||
if not face_occlude:
|
if not face_occlude:
|
||||||
composite.alpha_over(img, black_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[2]).enhance(black_coeff))
|
composite.alpha_over(img, over_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[2]).enhance(black_coeff))
|
||||||
|
|
||||||
# Draw edge lines
|
# Draw edge lines
|
||||||
if blockid in (44,): # step block
|
if blockid in (44,): # step block
|
||||||
@@ -705,6 +734,7 @@ def generate_facemasks():
|
|||||||
return (top, left, right)
|
return (top, left, right)
|
||||||
facemasks = generate_facemasks()
|
facemasks = generate_facemasks()
|
||||||
black_color = Image.new("RGB", (24,24), (0,0,0))
|
black_color = Image.new("RGB", (24,24), (0,0,0))
|
||||||
|
red_color = Image.new("RGB", (24,24), (229,36,38))
|
||||||
|
|
||||||
# Render 128 different color images for color coded depth blending in cave mode
|
# Render 128 different color images for color coded depth blending in cave mode
|
||||||
def generate_depthcolors():
|
def generate_depthcolors():
|
||||||
|
|||||||
16
config.js
16
config.js
@@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
var config = {
|
var config = {
|
||||||
path: 'tiles',
|
|
||||||
fileExt: '{imgformat}',
|
fileExt: '{imgformat}',
|
||||||
tileSize: 384,
|
tileSize: 384,
|
||||||
defaultZoom: 1,
|
defaultZoom: 1,
|
||||||
@@ -28,6 +27,21 @@ var signGroups = [
|
|||||||
{label: "All", match: function(s) {return true}}
|
{label: "All", match: function(s) {return true}}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/* mapTypeData -- a list of alternate map renderings available. At least one rendering must be
|
||||||
|
* listed. When more than one are provided, controls to switch between them are provided, with
|
||||||
|
* the first one being the default.
|
||||||
|
*
|
||||||
|
* Required:
|
||||||
|
* label : string. Displayed on the control.
|
||||||
|
* path : string. Location of the rendered tiles.
|
||||||
|
*/
|
||||||
|
var mapTypeData=[
|
||||||
|
{'label': 'Unlit', 'path': 'tiles'},
|
||||||
|
// {'label': 'Day', 'path': 'lighting/tiles'},
|
||||||
|
// {'label': 'Night', 'path': 'night/tiles'},
|
||||||
|
// {'label': 'Spawn', 'path': 'spawn/tiles'}
|
||||||
|
];
|
||||||
|
|
||||||
// Please leave the following variables here:
|
// Please leave the following variables here:
|
||||||
var markerCollection = {}; // holds groups of markers
|
var markerCollection = {}; // holds groups of markers
|
||||||
|
|
||||||
|
|||||||
4
gmap.py
4
gmap.py
@@ -51,6 +51,7 @@ def main():
|
|||||||
parser.add_option("--chunklist", dest="chunklist", help="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.")
|
parser.add_option("--chunklist", dest="chunklist", help="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.")
|
||||||
parser.add_option("--lighting", dest="lighting", help="Renders shadows using light data from each chunk.", action="store_true")
|
parser.add_option("--lighting", dest="lighting", help="Renders shadows using light data from each chunk.", action="store_true")
|
||||||
parser.add_option("--night", dest="night", help="Renders shadows using light data from each chunk, as if it were night. Implies --lighting.", action="store_true")
|
parser.add_option("--night", dest="night", help="Renders shadows using light data from each chunk, as if it were night. Implies --lighting.", action="store_true")
|
||||||
|
parser.add_option("--spawn", dest="spawn", help="Renders shadows using light data from each chunk, as if it were night, while also highlighting areas that are dark enough to spawn mobs. Implies --lighting and --night.", action="store_true")
|
||||||
parser.add_option("--imgformat", dest="imgformat", help="The image output format to use. Currently supported: png(default), jpg. NOTE: png will always be used as the intermediate image format.")
|
parser.add_option("--imgformat", dest="imgformat", help="The image output format to use. Currently supported: png(default), jpg. NOTE: png will always be used as the intermediate image format.")
|
||||||
parser.add_option("--optimize-img", dest="optimizeimg", help="If using png, perform image file size optimizations on the output. Specify 1 for pngcrush, 2 for pngcrush+optipng+advdef. This may double (or more) render times, but will produce up to 30% smaller images. NOTE: requires corresponding programs in $PATH or %PATH%")
|
parser.add_option("--optimize-img", dest="optimizeimg", help="If using png, perform image file size optimizations on the output. Specify 1 for pngcrush, 2 for pngcrush+optipng+advdef. This may double (or more) render times, but will produce up to 30% smaller images. NOTE: requires corresponding programs in $PATH or %PATH%")
|
||||||
parser.add_option("-q", "--quiet", dest="quiet", action="count", default=0, help="Print less output. You can specify this option multiple times.")
|
parser.add_option("-q", "--quiet", dest="quiet", action="count", default=0, help="Print less output. You can specify this option multiple times.")
|
||||||
@@ -123,7 +124,8 @@ def main():
|
|||||||
logging.info("Notice: Not using biome data for tinting")
|
logging.info("Notice: Not using biome data for tinting")
|
||||||
|
|
||||||
# First generate the world's chunk images
|
# First generate the world's chunk images
|
||||||
w = world.WorldRenderer(worlddir, cachedir, chunklist=chunklist, lighting=options.lighting, night=options.night, useBiomeData=useBiomeData)
|
w = world.WorldRenderer(worlddir, cachedir, chunklist=chunklist, lighting=options.lighting, night=options.night, spawn=options.spawn, useBiomeData=useBiomeData)
|
||||||
|
|
||||||
w.go(options.procs)
|
w.go(options.procs)
|
||||||
|
|
||||||
# Now generate the tiles
|
# Now generate the tiles
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ function drawMapControls() {
|
|||||||
compassImg.src="compass.png";
|
compassImg.src="compass.png";
|
||||||
compassDiv.appendChild(compassImg);
|
compassDiv.appendChild(compassImg);
|
||||||
|
|
||||||
|
compassDiv.index = 0;
|
||||||
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(compassDiv);
|
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(compassDiv);
|
||||||
|
|
||||||
|
|
||||||
@@ -260,16 +261,23 @@ function initialize() {
|
|||||||
if (argname == "zoom") {zoom = parseInt(value);}
|
if (argname == "zoom") {zoom = parseInt(value);}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var mapTyepControlToggle = false
|
||||||
|
if (mapTypeIds.length > 1) {
|
||||||
|
mapTyepControlToggle = true
|
||||||
|
}
|
||||||
var mapOptions = {
|
var mapOptions = {
|
||||||
zoom: zoom,
|
zoom: zoom,
|
||||||
center: new google.maps.LatLng(lat, lng),
|
center: new google.maps.LatLng(lat, lng),
|
||||||
navigationControl: true,
|
navigationControl: true,
|
||||||
scaleControl: false,
|
scaleControl: false,
|
||||||
mapTypeControl: false,
|
mapTypeControl: mapTyepControlToggle,
|
||||||
|
mapTypeControlOptions: {
|
||||||
|
mapTypeIds: mapTypeIds
|
||||||
|
},
|
||||||
|
mapTypeId: mapTypeIdDefault
|
||||||
streetViewControl: false,
|
streetViewControl: false,
|
||||||
mapTypeId: 'mcmap'
|
|
||||||
};
|
};
|
||||||
map = new google.maps.Map(document.getElementById("mcmap"), mapOptions);
|
map = new google.maps.Map(document.getElementById('mcmap'), mapOptions);
|
||||||
|
|
||||||
if(config.debug) {
|
if(config.debug) {
|
||||||
map.overlayMapTypes.insertAt(0, new CoordMapType(new google.maps.Size(config.tileSize, config.tileSize)));
|
map.overlayMapTypes.insertAt(0, new CoordMapType(new google.maps.Size(config.tileSize, config.tileSize)));
|
||||||
@@ -287,11 +295,12 @@ function initialize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now attach the coordinate map type to the map's registry
|
// Now attach the coordinate map type to the map's registry
|
||||||
map.mapTypes.set('mcmap', MCMapType);
|
for (idx in MCMapType) {
|
||||||
|
map.mapTypes.set('mcmap' + MCMapType[idx].name, MCMapType[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
// We can now set the map to use the 'coordinate' map type
|
// We can now set the map to use the 'coordinate' map type
|
||||||
map.setMapTypeId('mcmap');
|
map.setMapTypeId(mapTypeIdDefault);
|
||||||
|
|
||||||
|
|
||||||
// initialize the markers and regions
|
// initialize the markers and regions
|
||||||
initMarkers();
|
initMarkers();
|
||||||
@@ -370,9 +379,9 @@ function initialize() {
|
|||||||
return new google.maps.LatLng(lat, lng);
|
return new google.maps.LatLng(lat, lng);
|
||||||
}
|
}
|
||||||
|
|
||||||
var MCMapOptions = {
|
function getTileUrlGenerator(path) {
|
||||||
getTileUrl: function(tile, zoom) {
|
return function(tile, zoom) {
|
||||||
var url = config.path;
|
var url = path;
|
||||||
if(tile.x < 0 || tile.x >= Math.pow(2, zoom) || tile.y < 0 || tile.y >= Math.pow(2, zoom)) {
|
if(tile.x < 0 || tile.x >= Math.pow(2, zoom) || tile.y < 0 || tile.y >= Math.pow(2, zoom)) {
|
||||||
url += '/blank';
|
url += '/blank';
|
||||||
} else if(zoom == 0) {
|
} else if(zoom == 0) {
|
||||||
@@ -390,17 +399,33 @@ function initialize() {
|
|||||||
url += '?c=' + Math.floor(d.getTime() / (1000 * 60 * config.cacheMinutes));
|
url += '?c=' + Math.floor(d.getTime() / (1000 * 60 * config.cacheMinutes));
|
||||||
}
|
}
|
||||||
return(url);
|
return(url);
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var MCMapOptions = new Array;
|
||||||
|
var MCMapType = new Array;
|
||||||
|
var mapTypeIdDefault = null;
|
||||||
|
var mapTypeIds = [];
|
||||||
|
for (idx in mapTypeData) {
|
||||||
|
var view = mapTypeData[idx];
|
||||||
|
|
||||||
|
MCMapOptions[view.label] = {
|
||||||
|
getTileUrl: getTileUrlGenerator(view.path),
|
||||||
tileSize: new google.maps.Size(config.tileSize, config.tileSize),
|
tileSize: new google.maps.Size(config.tileSize, config.tileSize),
|
||||||
maxZoom: config.maxZoom,
|
maxZoom: config.maxZoom,
|
||||||
minZoom: 0,
|
minZoom: 0,
|
||||||
isPng: !(config.fileExt.match(/^png$/i) == null)
|
isPng: !(config.fileExt.match(/^png$/i) == null)
|
||||||
};
|
};
|
||||||
|
|
||||||
var MCMapType = new google.maps.ImageMapType(MCMapOptions);
|
MCMapType[view.label] = new google.maps.ImageMapType(MCMapOptions[view.label]);
|
||||||
MCMapType.name = "MC Map";
|
MCMapType[view.label].name = view.label;
|
||||||
MCMapType.alt = "Minecraft Map";
|
MCMapType[view.label].alt = "Minecraft " + view.label + " Map";
|
||||||
MCMapType.projection = new MCMapProjection();
|
MCMapType[view.label].projection = new MCMapProjection();
|
||||||
|
if (mapTypeIdDefault == null) {
|
||||||
|
mapTypeIdDefault = 'mcmap' + view.label;
|
||||||
|
}
|
||||||
|
mapTypeIds.push('mcmap' + view.label);
|
||||||
|
}
|
||||||
|
|
||||||
function CoordMapType() {
|
function CoordMapType() {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ body { height: 100%; margin: 0px; padding: 0px ; background-color: #000; }
|
|||||||
|
|
||||||
#signControl > div#top {
|
#signControl > div#top {
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border: 1px solid #000;
|
border: 2px solid #000;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 70px;
|
width: 70px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|||||||
7
world.py
7
world.py
@@ -95,11 +95,12 @@ class WorldRenderer(object):
|
|||||||
files to update. If it includes a trailing newline, it is stripped, so you
|
files to update. If it includes a trailing newline, it is stripped, so you
|
||||||
can pass in file handles just fine.
|
can pass in file handles just fine.
|
||||||
"""
|
"""
|
||||||
def __init__(self, worlddir, cachedir, chunklist=None, lighting=False, night=False, useBiomeData=False):
|
def __init__(self, worlddir, cachedir, chunklist=None, lighting=False, night=False, spawn=False, useBiomeData=False):
|
||||||
self.worlddir = worlddir
|
self.worlddir = worlddir
|
||||||
self.caves = False
|
self.caves = False
|
||||||
self.lighting = lighting or night
|
self.lighting = lighting or night or spawn
|
||||||
self.night = night
|
self.night = night or spawn
|
||||||
|
self.spawn = spawn
|
||||||
self.cachedir = cachedir
|
self.cachedir = cachedir
|
||||||
self.useBiomeData = useBiomeData
|
self.useBiomeData = useBiomeData
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user