From 9f69f099adc49dacbaff364dd85510715b830af4 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Mon, 28 Mar 2011 02:50:36 -0400 Subject: [PATCH 01/78] initial support for map overlays --- chunk.py | 1 + config.js | 3 +- googlemap.py | 6 +- overviewer.py | 3 +- setup.py | 8 +- src/composite.c | 10 ++- src/overviewer.h | 5 +- src/rendermode-normal.c | 2 +- src/rendermode-overlay.c | 75 ++++++++++++++++++ src/rendermodes.c | 4 + src/rendermodes.h | 7 ++ web_assets/functions.js | 165 ++++++++++++++++++++++++--------------- web_assets/style.css | 6 +- 13 files changed, 216 insertions(+), 79 deletions(-) create mode 100644 src/rendermode-overlay.c diff --git a/chunk.py b/chunk.py index 99019b6..56e58ef 100644 --- a/chunk.py +++ b/chunk.py @@ -503,6 +503,7 @@ def generate_facemasks(): facemasks = generate_facemasks() black_color = Image.new("RGB", (24,24), (0,0,0)) red_color = Image.new("RGB", (24,24), (229,36,38)) +white_color = Image.new("RGB", (24,24), (255,255,255)) # Render 128 different color images for color coded depth blending in cave mode def generate_depthcolors(): diff --git a/config.js b/config.js index 9296853..f52c170 100644 --- a/config.js +++ b/config.js @@ -44,7 +44,8 @@ var mapTypeData=[ {'label': 'Unlit', 'path': 'tiles'}, // {'label': 'Day', 'path': 'lighting/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/'}, +// {'label': 'Overlay', 'path': 'overlay/tiles', 'overlay': true} ]; */ diff --git a/googlemap.py b/googlemap.py index 840d2ac..9ae846a 100644 --- a/googlemap.py +++ b/googlemap.py @@ -95,8 +95,12 @@ class MapGen(object): "{imgformat}", str(imgformat)) # create generated map type data, from given quadtrees + # FIXME hook this into render_modes in setup.py, somehow + overlay_types = ['overlay'] maptypedata = map(lambda q: {'label' : q.rendermode.capitalize(), - 'path' : q.tiledir}, self.quadtrees) + 'path' : q.tiledir, + 'overlay' : q.rendermode in overlay_types}, + self.quadtrees) config = config.replace("{maptypedata}", json.dumps(maptypedata)) with open(os.path.join(self.destdir, "config.js"), 'w') as output: diff --git a/overviewer.py b/overviewer.py index b2aa275..7082d0c 100755 --- a/overviewer.py +++ b/overviewer.py @@ -64,7 +64,8 @@ def main(): parser.add_option("-z", "--zoom", dest="zoom", help="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", action="store", type="int", configFileOnly=True) parser.add_option("-d", "--delete", dest="delete", help="Clear all caches. Next time you render your world, it will have to start completely over again. This is probably not a good idea for large worlds. Use this if you change texture packs and want to re-render everything.", action="store_true", commandLineOnly=True) 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("--rendermodes", dest="rendermode", help="Specifies the render type: normal (default), lighting, night, or spawn.", type="choice", choices=["normal", "lighting", "night", "spawn"], required=True, default="normal", listify=True) + # TODO hook this up to render_modes in setup.py + parser.add_option("--rendermodes", dest="rendermode", help="Specifies the render type: normal (default), lighting, night, or spawn.", type="choice", choices=["normal", "lighting", "night", "spawn", "overlay"], required=True, default="normal", listify=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.", configFileOnly=True ) 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%", configFileOnly=True) parser.add_option("--web-assets-hook", dest="web_assets_hook", help="If provided, run this function after the web assets have been copied, but before actual tile rendering begins. It should accept a QuadtreeGen object as its only argument.", action="store", metavar="SCRIPT", type="function", configFileOnly=True) diff --git a/setup.py b/setup.py index 34f646b..27bb755 100644 --- a/setup.py +++ b/setup.py @@ -49,9 +49,13 @@ try: except AttributeError: numpy_include = numpy.get_numpy_include() +# used to figure out what files to compile +# TODO and, potentially, to check which are available +render_modes = ['normal', 'lighting', 'night', 'spawn', 'overlay'] + +c_overviewer_files = ['src/main.c', 'src/composite.c', 'src/iterate.c', 'src/endian.c', 'src/rendermodes.c'] +c_overviewer_files += map(lambda mode: 'src/rendermode-%s.c' % (mode,), render_modes) -c_overviewer_files = ['src/main.c', 'src/composite.c', 'src/iterate.c', 'src/endian.c'] -c_overviewer_files += ['src/rendermodes.c', 'src/rendermode-normal.c', 'src/rendermode-lighting.c', 'src/rendermode-night.c', 'src/rendermode-spawn.c'] setup_kwargs['ext_modules'].append(Extension('c_overviewer', c_overviewer_files, include_dirs=['.', numpy_include], extra_link_args=[])) # tell build_ext to build the extension in-place # (NOT in build/) diff --git a/src/composite.c b/src/composite.c index 4a03d23..432ece8 100644 --- a/src/composite.c +++ b/src/composite.c @@ -273,7 +273,8 @@ alpha_over_wrap(PyObject *self, PyObject *args) * also, it multiplies instead of doing an over operation */ PyObject * -tint_with_mask(PyObject *dest, unsigned char sr, unsigned char sg, unsigned char sb, +tint_with_mask(PyObject *dest, unsigned char sr, unsigned char sg, + unsigned char sb, unsigned char sa, PyObject *mask, int dx, int dy, int xsize, int ysize) { /* libImaging handles */ Imaging imDest, imMask; @@ -332,9 +333,11 @@ tint_with_mask(PyObject *dest, unsigned char sr, unsigned char sg, unsigned char out++; *out = MULDIV255(*out, sb, tmp1); out++; + *out = MULDIV255(*out, sa, tmp1); + out++; } else if (*inmask == 0) { /* do nothing -- source is fully transparent */ - out += 3; + out += 4; } else { /* general case */ @@ -345,9 +348,10 @@ tint_with_mask(PyObject *dest, unsigned char sr, unsigned char sg, unsigned char out++; *out = MULDIV255(*out, (255 - *inmask) + MULDIV255(sb, *inmask, tmp1), tmp2); out++; + *out = MULDIV255(*out, (255 - *inmask) + MULDIV255(sa, *inmask, tmp1), tmp2); + out++; } - out++; inmask += mask_stride; } } diff --git a/src/overviewer.h b/src/overviewer.h index 3475fdf..4045313 100644 --- a/src/overviewer.h +++ b/src/overviewer.h @@ -44,7 +44,8 @@ PyObject *alpha_over(PyObject *dest, PyObject *src, PyObject *mask, PyObject *alpha_over_full(PyObject *dest, PyObject *src, PyObject *mask, float overall_alpha, int dx, int dy, int xsize, int ysize); PyObject *alpha_over_wrap(PyObject *self, PyObject *args); -PyObject *tint_with_mask(PyObject *dest, unsigned char sr, unsigned char sg, unsigned char sb, +PyObject *tint_with_mask(PyObject *dest, unsigned char sr, unsigned char sg, + unsigned char sb, unsigned char sa, PyObject *mask, int dx, int dy, int xsize, int ysize); /* in iterate.c */ @@ -79,7 +80,7 @@ PyObject *chunk_render(PyObject *self, PyObject *args); #include "rendermodes.h" /* in endian.c */ -void init_endian(); +void init_endian(void); unsigned short big_endian_ushort(unsigned short in); unsigned int big_endian_uint(unsigned int in); diff --git a/src/rendermode-normal.c b/src/rendermode-normal.c index d7a1367..f0cdb96 100644 --- a/src/rendermode-normal.c +++ b/src/rendermode-normal.c @@ -158,7 +158,7 @@ rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject * b = PyInt_AsLong(PyTuple_GET_ITEM(color, 2)); Py_DECREF(color); - tint_with_mask(state->img, r, g, b, facemask, state->imgx, state->imgy, 0, 0); + tint_with_mask(state->img, r, g, b, 255, facemask, state->imgx, state->imgy, 0, 0); } } } diff --git a/src/rendermode-overlay.c b/src/rendermode-overlay.c new file mode 100644 index 0000000..32cb03a --- /dev/null +++ b/src/rendermode-overlay.c @@ -0,0 +1,75 @@ +/* + * 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 . + */ + +#include "overviewer.h" + +static int +rendermode_overlay_start(void *data, RenderState *state) { + PyObject *facemasks_py; + RenderModeOverlay *self = (RenderModeOverlay *)data; + + facemasks_py = PyObject_GetAttrString(state->chunk, "facemasks"); + /* borrowed reference, needs to be incref'd if we keep it */ + self->facemask_top = PyTuple_GetItem(facemasks_py, 0); + Py_INCREF(self->facemask_top); + Py_DECREF(facemasks_py); + + self->white_color = PyObject_GetAttrString(state->chunk, "white_color"); + + return 0; +} + +static void +rendermode_overlay_finish(void *data, RenderState *state) { + RenderModeOverlay *self = (RenderModeOverlay *)data; + + Py_XDECREF(self->facemask_top); + Py_XDECREF(self->white_color); +} + +static int +rendermode_overlay_occluded(void *data, RenderState *state) { + int x = state->x, y = state->y, z = state->z; + + if ( (x != 0) && (y != 15) && (z != 127) && + !is_transparent(getArrayByte3D(state->blocks, x-1, y, z)) && + !is_transparent(getArrayByte3D(state->blocks, x, y, z+1)) && + !is_transparent(getArrayByte3D(state->blocks, x, y+1, z))) { + return 1; + } + + return 0; +} + +static void +rendermode_overlay_draw(void *data, RenderState *state, PyObject *src, PyObject *mask) { + RenderModeOverlay *self = (RenderModeOverlay *)data; + + /* clear the draw space -- set alpha to 0 within mask */ + tint_with_mask(state->img, 255, 255, 255, 0, mask, state->imgx, state->imgy, 0, 0); + + /* do the overlay */ + alpha_over_full(state->img, self->white_color, self->facemask_top, 0.5, state->imgx, state->imgy, 0, 0); +} + +RenderModeInterface rendermode_overlay = { + sizeof(RenderModeOverlay), + rendermode_overlay_start, + rendermode_overlay_finish, + rendermode_overlay_occluded, + rendermode_overlay_draw, +}; diff --git a/src/rendermodes.c b/src/rendermodes.c index f4fbe89..46cc432 100644 --- a/src/rendermodes.c +++ b/src/rendermodes.c @@ -31,6 +31,10 @@ RenderModeInterface *get_render_mode(RenderState *state) { iface = &rendermode_night; } else if (strcmp(rendermode, "spawn") == 0) { iface = &rendermode_spawn; + } else if (strcmp(rendermode, "overlay") == 0) { + /* TODO temporarily use overlay directly, but later on + you want to use overlay-derived modes */ + iface = &rendermode_overlay; } Py_DECREF(rendermode_py); diff --git a/src/rendermodes.h b/src/rendermodes.h index d26091d..87c7cb1 100644 --- a/src/rendermodes.h +++ b/src/rendermodes.h @@ -71,6 +71,13 @@ typedef struct { } RenderModeNormal; extern RenderModeInterface rendermode_normal; +/* OVERLAY */ +typedef struct { + /* top facemask and white color image, for drawing overlays */ + PyObject *facemask_top, *white_color; +} RenderModeOverlay; +extern RenderModeInterface rendermode_overlay; + /* LIGHTING */ typedef struct { /* inherits from normal render mode */ diff --git a/web_assets/functions.js b/web_assets/functions.js index 174a43a..9b7ac12 100644 --- a/web_assets/functions.js +++ b/web_assets/functions.js @@ -14,6 +14,61 @@ function prepareSignMarker(marker, item) { } +function createDropDown(title, items) { + var control = document.createElement("DIV"); + control.id = "customControl"; // let's let a style sheet do most of the styling here + + var controlBorder = document.createElement("DIV"); + controlBorder.id="top"; + control.appendChild(controlBorder); + + var controlText = document.createElement("DIV"); + + controlBorder.appendChild(controlText); + + controlText.innerHTML = title; + + var dropdownDiv = document.createElement("DIV"); + + + $(controlText).click(function() { + $(dropdownDiv).toggle(); + + }); + + + dropdownDiv.id="dropDown"; + control.appendChild(dropdownDiv); + dropdownDiv.innerHTML=""; + + map.controls[google.maps.ControlPosition.TOP_RIGHT].push(control); + + for (idx in items) { + var item = items[idx]; + //console.log(item); + label = item.label; + action = item.action; + var d = document.createElement("div"); + var n = document.createElement("input"); + n.type="checkbox"; + + $(n).data("label",label); + jQuery(n).click(function(e) { + var t = $(e.target); + action(idx, label, e.target.checked); + }); + + if (item.checked) { + n.checked = true; + action(idx, label, item.checked); + } + dropdownDiv.appendChild(d); + d.appendChild(n) + var textNode = document.createElement("text"); + textNode.innerHTML = label + "
"; + d.appendChild(textNode); + } +} function drawMapControls() { @@ -42,69 +97,43 @@ function drawMapControls() { if (signGroups.length > 0) { - // signpost display control - // - - var signControl = document.createElement("DIV"); - signControl.id = "signControl"; // let's let a style sheet do most of the styling here - - var controlBorder = document.createElement("DIV"); - controlBorder.id="top"; - signControl.appendChild(controlBorder); - - var controlText = document.createElement("DIV"); - - controlBorder.appendChild(controlText); - - controlText.innerHTML = "Signposts"; - - var dropdownDiv = document.createElement("DIV"); - - - $(controlText).click(function() { - $(dropdownDiv).toggle(); - - }); - - - dropdownDiv.id="dropDown"; - signControl.appendChild(dropdownDiv); - dropdownDiv.innerHTML=""; - - map.controls[google.maps.ControlPosition.TOP_RIGHT].push(signControl); - - - - var hasSignGroup = false; - for (idx in signGroups) { - var item = signGroups[idx]; - //console.log(item); - label = item.label; - hasSignGroup = true; - var d = document.createElement("div"); - var n = document.createElement("input"); - n.type="checkbox"; - - $(n).data("label",label); - jQuery(n).click(function(e) { - var t = $(e.target); - jQuery.each(markerCollection[t.data("label")], function(i,elem) {elem.setVisible(e.target.checked);}); - }); - - - if (item.checked) { - n.checked = true; - jQuery.each(markerCollection[label], function(i,elem) {elem.setVisible(n.checked);}); + // signpost display control + + var items = []; + for (idx in signGroups) { + var item = signGroups[idx]; + items.push({"label": item.label, "checked": item.checked, + "action": function(n, l, checked) { + jQuery.each(markerCollection[l], function(i,elem) {elem.setVisible(checked);}); + }}); } - dropdownDiv.appendChild(d); - d.appendChild(n) - var textNode = document.createElement("text"); - textNode.innerHTML = label + "
"; - d.appendChild(textNode); - + createDropDown("Signposts", items); } - - + + if (overlayMapTypes.length > 0) { + // overlay maps control + + var items = []; + for (idx in overlayMapTypes) { + var overlay = overlayMapTypes[idx]; + items.push({"label": overlay.name, "checked": false, + "action": function(i, l, checked) { + if (checked) { + map.overlayMapTypes.push(overlay); + } else { + var idx_to_delete = -1; + map.overlayMapTypes.forEach(function(e, j) { + if (e == overlay) { + idx_to_delete = j; + } + }); + if (idx_to_delete >= 0) { + map.overlayMapTypes.removeAt(idx_to_delete); + } + } + }}); + } + createDropDown("Overlays", items); } } @@ -303,7 +332,7 @@ function initialize() { 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 map.setMapTypeId(mapTypeIdDefault); @@ -412,6 +441,7 @@ var MCMapOptions = new Array; var MCMapType = new Array; var mapTypeIdDefault = null; var mapTypeIds = []; +var overlayMapTypes = []; for (idx in mapTypeData) { var view = mapTypeData[idx]; @@ -427,10 +457,15 @@ for (idx in mapTypeData) { MCMapType[view.label].name = view.label; MCMapType[view.label].alt = "Minecraft " + view.label + " Map"; MCMapType[view.label].projection = new MCMapProjection(); - if (mapTypeIdDefault == null) { - mapTypeIdDefault = 'mcmap' + view.label; + + if (view.overlay) { + overlayMapTypes.push(MCMapType[view.label]); + } else { + if (mapTypeIdDefault == null) { + mapTypeIdDefault = 'mcmap' + view.label; + } + mapTypeIds.push('mcmap' + view.label); } - mapTypeIds.push('mcmap' + view.label); } function CoordMapType() { diff --git a/web_assets/style.css b/web_assets/style.css index e6029dc..32389bf 100644 --- a/web_assets/style.css +++ b/web_assets/style.css @@ -17,13 +17,13 @@ body { height: 100%; margin: 0px; padding: 0px ; background-color: #000; } font-family: monospace; } -#signControl { +#customControl { padding: 5px; height: 15px; font-family: Arial, sans-serif; } -#signControl > div#top { +#customControl > div#top { background-color: #fff; border: 2px solid #000; text-align: center; @@ -33,7 +33,7 @@ body { height: 100%; margin: 0px; padding: 0px ; background-color: #000; } cursor: pointer; } -#signControl > div#dropDown { +#customControl > div#dropDown { border: 1px solid #000; font-size: 12px; background-color: #fff; From d4bd1d713c88e18569a3c1cb83a0f1fd2c7c4069 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Mon, 28 Mar 2011 03:09:00 -0400 Subject: [PATCH 02/78] overlay mode now only considers blocks where overlays make sense --- src/rendermode-overlay.c | 41 +++++++++++++++++++++++++++++++++++++--- src/rendermodes.h | 2 ++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/rendermode-overlay.c b/src/rendermode-overlay.c index 32cb03a..27321ce 100644 --- a/src/rendermode-overlay.c +++ b/src/rendermode-overlay.c @@ -30,6 +30,9 @@ rendermode_overlay_start(void *data, RenderState *state) { self->white_color = PyObject_GetAttrString(state->chunk, "white_color"); + self->solid_blocks = PyObject_GetAttrString(state->chunk, "solid_blocks"); + self->fluid_blocks = PyObject_GetAttrString(state->chunk, "fluid_blocks"); + return 0; } @@ -37,8 +40,10 @@ static void rendermode_overlay_finish(void *data, RenderState *state) { RenderModeOverlay *self = (RenderModeOverlay *)data; - Py_XDECREF(self->facemask_top); - Py_XDECREF(self->white_color); + Py_DECREF(self->facemask_top); + Py_DECREF(self->white_color); + Py_DECREF(self->solid_blocks); + Py_DECREF(self->fluid_blocks); } static int @@ -51,7 +56,7 @@ rendermode_overlay_occluded(void *data, RenderState *state) { !is_transparent(getArrayByte3D(state->blocks, x, y+1, z))) { return 1; } - + return 0; } @@ -61,7 +66,37 @@ rendermode_overlay_draw(void *data, RenderState *state, PyObject *src, PyObject /* clear the draw space -- set alpha to 0 within mask */ tint_with_mask(state->img, 255, 255, 255, 0, mask, state->imgx, state->imgy, 0, 0); + + /* skip rendering the overlay if we can't see it */ + if (state->z != 127) { + unsigned char top_block = getArrayByte3D(state->blocks, state->x, state->y, state->z+1); + if (!is_transparent(top_block)) { + return; + } + + /* check to be sure this block is solid/fluid */ + PyObject *top_block_py = PyInt_FromLong(top_block); + if (PySequence_Contains(self->solid_blocks, top_block_py) || + PySequence_Contains(self->fluid_blocks, top_block_py)) { + + /* top block is fluid or solid, skip drawing */ + Py_DECREF(top_block_py); + return; + } + Py_DECREF(top_block_py); + } + /* check to be sure this block is solid/fluid */ + PyObject *block_py = PyInt_FromLong(state->block); + if (!PySequence_Contains(self->solid_blocks, block_py) && + !PySequence_Contains(self->fluid_blocks, block_py)) { + + /* not fluid or solid, skip drawing the overlay */ + Py_DECREF(block_py); + return; + } + Py_DECREF(block_py); + /* do the overlay */ alpha_over_full(state->img, self->white_color, self->facemask_top, 0.5, state->imgx, state->imgy, 0, 0); } diff --git a/src/rendermodes.h b/src/rendermodes.h index 87c7cb1..848c070 100644 --- a/src/rendermodes.h +++ b/src/rendermodes.h @@ -75,6 +75,8 @@ extern RenderModeInterface rendermode_normal; typedef struct { /* top facemask and white color image, for drawing overlays */ PyObject *facemask_top, *white_color; + /* only show overlay on top of solid or fluid blocks */ + PyObject *solid_blocks, *fluid_blocks; } RenderModeOverlay; extern RenderModeInterface rendermode_overlay; From 83db528d818b2ff02ea02a1cb08251179487b9ba Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Mon, 28 Mar 2011 03:20:16 -0400 Subject: [PATCH 03/78] added callback for derived rendermodes to easily provide overlay color --- src/rendermode-overlay.c | 19 ++++++++++++++++++- src/rendermodes.h | 5 +++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/rendermode-overlay.c b/src/rendermode-overlay.c index 27321ce..08e3b30 100644 --- a/src/rendermode-overlay.c +++ b/src/rendermode-overlay.c @@ -17,6 +17,14 @@ #include "overviewer.h" +static void get_color(void *data, RenderState *state, + unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a) { + *r = 200; + *g = 200; + *b = 255; + *a = 155; +} + static int rendermode_overlay_start(void *data, RenderState *state) { PyObject *facemasks_py; @@ -33,6 +41,8 @@ rendermode_overlay_start(void *data, RenderState *state) { self->solid_blocks = PyObject_GetAttrString(state->chunk, "solid_blocks"); self->fluid_blocks = PyObject_GetAttrString(state->chunk, "fluid_blocks"); + self->get_color = get_color; + return 0; } @@ -63,6 +73,7 @@ rendermode_overlay_occluded(void *data, RenderState *state) { static void rendermode_overlay_draw(void *data, RenderState *state, PyObject *src, PyObject *mask) { RenderModeOverlay *self = (RenderModeOverlay *)data; + unsigned char r, g, b, a; /* clear the draw space -- set alpha to 0 within mask */ tint_with_mask(state->img, 255, 255, 255, 0, mask, state->imgx, state->imgy, 0, 0); @@ -97,8 +108,14 @@ rendermode_overlay_draw(void *data, RenderState *state, PyObject *src, PyObject } Py_DECREF(block_py); + /* get our color info */ + self->get_color(data, state, &r, &g, &b, &a); + /* do the overlay */ - alpha_over_full(state->img, self->white_color, self->facemask_top, 0.5, state->imgx, state->imgy, 0, 0); + if (a > 0) { + alpha_over(state->img, self->white_color, self->facemask_top, state->imgx, state->imgy, 0, 0); + tint_with_mask(state->img, r, g, b, a, self->facemask_top, state->imgx, state->imgy, 0, 0); + } } RenderModeInterface rendermode_overlay = { diff --git a/src/rendermodes.h b/src/rendermodes.h index 848c070..6129980 100644 --- a/src/rendermodes.h +++ b/src/rendermodes.h @@ -77,6 +77,11 @@ typedef struct { PyObject *facemask_top, *white_color; /* only show overlay on top of solid or fluid blocks */ PyObject *solid_blocks, *fluid_blocks; + /* can be overridden in derived classes to control + overlay alpha and color + last four vars are r, g, b, a out */ + void (*get_color)(void *, RenderState *, + unsigned char *, unsigned char *, unsigned char *, unsigned char *); } RenderModeOverlay; extern RenderModeInterface rendermode_overlay; From f23d3ddac9b5d59da1ad649b3787c816edcef38d Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Mon, 28 Mar 2011 03:40:02 -0400 Subject: [PATCH 04/78] converted spawn into a overlay-based rendermode --- chunk.py | 1 - googlemap.py | 2 +- overviewer.py | 2 +- src/rendermode-spawn.c | 117 ++++++++++++++++++----------------------- src/rendermodes.c | 4 -- src/rendermodes.h | 9 ++-- 6 files changed, 58 insertions(+), 77 deletions(-) diff --git a/chunk.py b/chunk.py index 56e58ef..bfe7e24 100644 --- a/chunk.py +++ b/chunk.py @@ -502,7 +502,6 @@ def generate_facemasks(): return (top, left, right) facemasks = generate_facemasks() black_color = Image.new("RGB", (24,24), (0,0,0)) -red_color = Image.new("RGB", (24,24), (229,36,38)) white_color = Image.new("RGB", (24,24), (255,255,255)) # Render 128 different color images for color coded depth blending in cave mode diff --git a/googlemap.py b/googlemap.py index 9ae846a..29e197f 100644 --- a/googlemap.py +++ b/googlemap.py @@ -96,7 +96,7 @@ class MapGen(object): # create generated map type data, from given quadtrees # FIXME hook this into render_modes in setup.py, somehow - overlay_types = ['overlay'] + overlay_types = ['spawn'] maptypedata = map(lambda q: {'label' : q.rendermode.capitalize(), 'path' : q.tiledir, 'overlay' : q.rendermode in overlay_types}, diff --git a/overviewer.py b/overviewer.py index 7082d0c..4ac0e8d 100755 --- a/overviewer.py +++ b/overviewer.py @@ -65,7 +65,7 @@ def main(): parser.add_option("-d", "--delete", dest="delete", help="Clear all caches. Next time you render your world, it will have to start completely over again. This is probably not a good idea for large worlds. Use this if you change texture packs and want to re-render everything.", action="store_true", commandLineOnly=True) 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.") # TODO hook this up to render_modes in setup.py - parser.add_option("--rendermodes", dest="rendermode", help="Specifies the render type: normal (default), lighting, night, or spawn.", type="choice", choices=["normal", "lighting", "night", "spawn", "overlay"], required=True, default="normal", listify=True) + parser.add_option("--rendermodes", dest="rendermode", help="Specifies the render type: normal (default), lighting, night, or spawn.", type="choice", choices=["normal", "lighting", "night", "spawn"], required=True, default="normal", listify=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.", configFileOnly=True ) 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%", configFileOnly=True) parser.add_option("--web-assets-hook", dest="web_assets_hook", help="If provided, run this function after the web assets have been copied, but before actual tile rendering begins. It should accept a QuadtreeGen object as its only argument.", action="store", metavar="SCRIPT", type="function", configFileOnly=True) diff --git a/src/rendermode-spawn.c b/src/rendermode-spawn.c index 1a7c96a..b0b78a4 100644 --- a/src/rendermode-spawn.c +++ b/src/rendermode-spawn.c @@ -18,21 +18,63 @@ #include "overviewer.h" #include +static void get_color(void *data, RenderState *state, + unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a) { + + RenderModeSpawn* self = (RenderModeSpawn *)data; + int x = state->x, y = state->y, z = state->z; + unsigned char blocklight, skylight; + PyObject *block_py; + + /* set a nice, pretty red color */ + *r = 229; + *g = 36; + *b = 38; + + /* default to no overlay, until told otherwise */ + *a = 0; + + /* if we're at the top, skip */ + if (z == 127) + return; + + block_py = PyInt_FromLong(state->block); + if (PySequence_Contains(self->nospawn_blocks, block_py)) { + /* nothing can spawn on this */ + Py_DECREF(block_py); + return; + } + Py_DECREF(block_py); + + blocklight = getArrayByte3D(self->blocklight, x, y, z+1); + skylight = getArrayByte3D(self->skylight, x, y, z+1); + + if (MAX(blocklight, skylight) <= 7) { + /* hostile mobs spawn in daylight */ + *a = 240; + } else if (MAX(blocklight, skylight - 11) <= 7) { + /* hostile mobs spawn at night */ + *a = 150; + } +} + static int rendermode_spawn_start(void *data, RenderState *state) { RenderModeSpawn* self; /* first, chain up */ - int ret = rendermode_night.start(data, state); + int ret = rendermode_overlay.start(data, state); if (ret != 0) return ret; /* now do custom initializations */ self = (RenderModeSpawn *)data; - self->solid_blocks = PyObject_GetAttrString(state->chunk, "solid_blocks"); self->nospawn_blocks = PyObject_GetAttrString(state->chunk, "nospawn_blocks"); - self->fluid_blocks = PyObject_GetAttrString(state->chunk, "fluid_blocks"); - self->red_color = PyObject_GetAttrString(state->chunk, "red_color"); + self->blocklight = PyObject_GetAttrString(state->self, "blocklight"); + self->skylight = PyObject_GetAttrString(state->self, "skylight"); + + /* setup custom color */ + self->parent.get_color = get_color; return 0; } @@ -40,81 +82,26 @@ rendermode_spawn_start(void *data, RenderState *state) { static void rendermode_spawn_finish(void *data, RenderState *state) { /* first free all *our* stuff */ - RenderModeSpawn* self = (RenderModeSpawn *)data; + RenderModeSpawn* self = (RenderModeSpawn *)data; - Py_DECREF(self->solid_blocks); Py_DECREF(self->nospawn_blocks); - Py_DECREF(self->fluid_blocks); + Py_DECREF(self->blocklight); + Py_DECREF(self->skylight); /* now, chain up */ - rendermode_night.finish(data, state); + rendermode_overlay.finish(data, state); } static int rendermode_spawn_occluded(void *data, RenderState *state) { /* no special occlusion here */ - return rendermode_night.occluded(data, state); + return rendermode_overlay.occluded(data, state); } static void rendermode_spawn_draw(void *data, RenderState *state, PyObject *src, PyObject *mask) { - /* different versions of self (spawn, lighting) */ - RenderModeSpawn* self = (RenderModeSpawn *)data; - RenderModeLighting *lighting = (RenderModeLighting *)self; - - int x = state->x, y = state->y, z = state->z; - PyObject *old_black_color = NULL; - - /* figure out the appropriate darkness: - this block for transparents, the block above for non-transparent */ - float darkness = 0.0; - if (is_transparent(state->block)) { - darkness = get_lighting_coefficient((RenderModeLighting *)self, state, x, y, z, NULL); - } else { - darkness = get_lighting_coefficient((RenderModeLighting *)self, state, x, y, z+1, NULL); - } - - /* if it's dark enough... */ - if (darkness > 0.8) { - PyObject *block_py = PyInt_FromLong(state->block); - - /* make sure it's solid */ - if (PySequence_Contains(self->solid_blocks, block_py)) { - int spawnable = 1; - - /* not spawnable if its in the nospawn list */ - if (PySequence_Contains(self->nospawn_blocks, block_py)) - spawnable = 0; - - /* check the block above for solid or fluid */ - if (spawnable && z != 127) { - PyObject *top_block_py = PyInt_FromLong(getArrayByte3D(state->blocks, x, y, z+1)); - if (PySequence_Contains(self->solid_blocks, top_block_py) || - PySequence_Contains(self->fluid_blocks, top_block_py)) { - - spawnable = 0; - } - - Py_DECREF(top_block_py); - } - - /* if we passed all the checks, replace black_color with red_color */ - if (spawnable) { - old_black_color = lighting->black_color; - lighting->black_color = self->red_color; - } - } - - Py_DECREF(block_py); - } - /* draw normally */ - rendermode_night.draw(data, state, src, mask); - - /* reset black_color, if needed */ - if (old_black_color != NULL) { - lighting->black_color = old_black_color; - } + rendermode_overlay.draw(data, state, src, mask); } RenderModeInterface rendermode_spawn = { diff --git a/src/rendermodes.c b/src/rendermodes.c index 46cc432..f4fbe89 100644 --- a/src/rendermodes.c +++ b/src/rendermodes.c @@ -31,10 +31,6 @@ RenderModeInterface *get_render_mode(RenderState *state) { iface = &rendermode_night; } else if (strcmp(rendermode, "spawn") == 0) { iface = &rendermode_spawn; - } else if (strcmp(rendermode, "overlay") == 0) { - /* TODO temporarily use overlay directly, but later on - you want to use overlay-derived modes */ - iface = &rendermode_overlay; } Py_DECREF(rendermode_py); diff --git a/src/rendermodes.h b/src/rendermodes.h index 6129980..a0d18a4 100644 --- a/src/rendermodes.h +++ b/src/rendermodes.h @@ -115,13 +115,12 @@ extern RenderModeInterface rendermode_night; /* SPAWN */ typedef struct { - /* inherits from night */ - RenderModeNight parent; + /* inherits from overlay */ + RenderModeOverlay parent; /* used to figure out which blocks are spawnable */ - PyObject *solid_blocks, *nospawn_blocks, *fluid_blocks; - /* replacement for black_color */ - PyObject *red_color; + PyObject *nospawn_blocks; + PyObject *skylight, *blocklight; } RenderModeSpawn; extern RenderModeInterface rendermode_spawn; From b24ae6c00ab185cd645bbc9b5310d4873d988efa Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Mon, 28 Mar 2011 05:18:41 -0400 Subject: [PATCH 05/78] signposts controls no longer toggle overlays --- web_assets/functions.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/web_assets/functions.js b/web_assets/functions.js index 9b7ac12..87e538f 100644 --- a/web_assets/functions.js +++ b/web_assets/functions.js @@ -46,26 +46,23 @@ function createDropDown(title, items) { for (idx in items) { var item = items[idx]; //console.log(item); - label = item.label; - action = item.action; var d = document.createElement("div"); var n = document.createElement("input"); n.type="checkbox"; - $(n).data("label",label); + $(n).data("label",item.label); jQuery(n).click(function(e) { - var t = $(e.target); - action(idx, label, e.target.checked); + item.action(idx, item.label, e.target.checked); }); if (item.checked) { n.checked = true; - action(idx, label, item.checked); + item.action(idx, item.label, item.checked); } dropdownDiv.appendChild(d); d.appendChild(n) var textNode = document.createElement("text"); - textNode.innerHTML = label + "
"; + textNode.innerHTML = item.label + "
"; d.appendChild(textNode); } } From 3eec8143dd435bbfe6000f14b5e06a9dc1142401 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Sun, 10 Apr 2011 22:13:24 -0400 Subject: [PATCH 06/78] get PIL include dir from the environ --- setup.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 55ee8bb..d3aee8a 100644 --- a/setup.py +++ b/setup.py @@ -35,7 +35,12 @@ if py2exe != None: # _composite.c extension # -setup_kwargs['ext_modules'].append(Extension('_composite', ['_composite.c'], include_dirs=['.'], extra_link_args=["/MANIFEST"] if platform.system() == "Windows" else [])) +try: + pil_include = os.environ['PIL_INCLUDE_DIR'].split(os.pathsep) +except: + pil_include = [] + +setup_kwargs['ext_modules'].append(Extension('_composite', ['_composite.c'], include_dirs=['.'] + pil_include, extra_link_args=["/MANIFEST"] if platform.system() == "Windows" else [])) # tell build_ext to build the extension in-place # (NOT in build/) setup_kwargs['options']['build_ext'] = {'inplace' : 1} From a2782a0499269f512bf232b3c07b7da0f0c7014a Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Tue, 12 Apr 2011 23:55:17 -0400 Subject: [PATCH 07/78] MSVC is strict about variable declaration --- src/rendermode-overlay.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/rendermode-overlay.c b/src/rendermode-overlay.c index 69d7b04..2a15302 100644 --- a/src/rendermode-overlay.c +++ b/src/rendermode-overlay.c @@ -74,6 +74,7 @@ static void rendermode_overlay_draw(void *data, RenderState *state, PyObject *src, PyObject *mask) { RenderModeOverlay *self = (RenderModeOverlay *)data; unsigned char r, g, b, a; + PyObject *top_block_py, *block_py; /* clear the draw space -- set alpha to 0 within mask */ tint_with_mask(state->img, 255, 255, 255, 0, mask, state->imgx, state->imgy, 0, 0); @@ -86,7 +87,7 @@ rendermode_overlay_draw(void *data, RenderState *state, PyObject *src, PyObject } /* check to be sure this block is solid/fluid */ - PyObject *top_block_py = PyInt_FromLong(top_block); + top_block_py = PyInt_FromLong(top_block); if (PySequence_Contains(self->solid_blocks, top_block_py) || PySequence_Contains(self->fluid_blocks, top_block_py)) { @@ -98,7 +99,7 @@ rendermode_overlay_draw(void *data, RenderState *state, PyObject *src, PyObject } /* check to be sure this block is solid/fluid */ - PyObject *block_py = PyInt_FromLong(state->block); + block_py = PyInt_FromLong(state->block); if (!PySequence_Contains(self->solid_blocks, block_py) && !PySequence_Contains(self->fluid_blocks, block_py)) { From 70bf8a7fb24bfb0e9aaa09b8211446434f23bcb9 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Wed, 13 Apr 2011 09:14:27 -0400 Subject: [PATCH 08/78] README update for settings.py, --rendermodes --- README.rst | 138 +++++++++++++++++++++++++++-------------------------- 1 file changed, 71 insertions(+), 67 deletions(-) diff --git a/README.rst b/README.rst index 2b07d45..616e8d2 100644 --- a/README.rst +++ b/README.rst @@ -8,14 +8,19 @@ http://github.com/brownan/Minecraft-Overviewer Generates large resolution images of a Minecraft map. In short, this program reads in Minecraft world files and renders very large -resolution images. It performs a similar function to the existing Minecraft -Cartographer program but with a slightly different goal in mind: to generate -large resolution images such that one can zoom in and see details. +resolution images that can be viewed through a Google Maps interface. It +performs a similar function to the existing Minecraft Cartographer program but +with a slightly different goal in mind: to generate large resolution images +such that one can zoom in and see details. See some examples here! http://github.com/brownan/Minecraft-Overviewer/wiki/Map-examples -(To contact me, send me a message on Github) +Further documentation may be found at +https://github.com/brownan/Minecraft-Overviewer/wiki/Documentation + +To contact the developers and other users, go to the site at the top of this +README, or go to #overviewer on irc.freenode.net. Features ======== @@ -56,6 +61,12 @@ If something doesn't work, let me know. Using the Overviewer ==================== +For a quick-start guide, see +https://github.com/brownan/Minecraft-Overviewer/wiki/Quick-Start-Guide + +If you are upgrading from an older Overviewer to the new DTT code, see +https://github.com/brownan/Minecraft-Overviewer/wiki/DTT-Upgrade-Guide + Disclaimers ----------- Before you dive into using this, just be aware that, for large maps, there is a @@ -89,7 +100,7 @@ you can use the Overviewer: texture packs out there. Biome Tinting -~~~~~~~~~~~~~ +------------- With the Halloween update, biomes were added to Minecraft. In order to get biome-accurate tinting, the Overviewer can use biome data produced by the Minecraft Biome Extractor tool. This tool can be downloaded from: @@ -102,12 +113,12 @@ then the Overviewer will use a static tinting for grass and leaves. Compiling the C Extension ------------------------- -The C Extension for Overviewer is no longer optional. In addition to providing -a higher quality image compositing function that looks better on maps with lighting -enabled, it now does the bulk of the rendering. +The C Extension for Overviewer is no longer optional. In addition to +providing a higher quality image compositing function that looks better on +maps with lighting enabled, it now does the bulk of the rendering. -If you downloaded Overviewer as a binary package, this extension will already be -compiled for you. +If you downloaded Overviewer as a binary package, this extension will already +be compiled for you. If you have a C compiler and the Python development libraries set up, you can compile this extension like this:: @@ -119,7 +130,7 @@ look for a package named 'python-dev', 'python-devel' or similar. Also, some Python distributions do not install "Imaging.h" and "ImPlatform.h" properly. If you get errors complaining about them, you can get them from the PIL source, or at . Just put them in -the same directory as "_composite.c". +the same directory as "overviewer.py". For more detailed instructions, check the wiki: https://github.com/brownan/Minecraft-Overviewer/wiki/Build-Instructions @@ -142,12 +153,6 @@ Options -h, --help Shows the list of options and exits ---imgformat=FORMAT - Set the output image format used for the tiles. The default is 'png', - but 'jpg' is also supported. Note that regardless of what you choose, - Overviewer will still use PNG for cached images to avoid recompression - artifacts. - -p PROCS, --processes=PROCS Adding the "-p" option will utilize more cores during processing. This can speed up rendering quite a bit. The default is set to the same @@ -157,34 +162,6 @@ Options python overviewer.py -p 5 --z ZOOM, --zoom=ZOOM - The Overviewer by default will detect how many zoom levels are required - to show your entire map. This option sets it manually. - - *You do not normally need to set this option!* - - This is equivalent to setting the dimensions of the highest zoom level. It - does not actually change how the map is rendered, but rather *how much of - the map is rendered.* (Calling this option "zoom" may be a bit misleading, - I know) - - To be precise, it sets the width and height of the highest zoom level, in - tiles. A zoom level of z means the highest zoom level of your map will be - 2^z by 2^z tiles. - - This option map be useful if you have some outlier chunks causing your map - to be too large, or you want to render a smaller portion of your map, - instead of rendering everything. - - This will render your map with 7 zoom levels:: - - python overviewer.py -z 7 - - 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. - Tiles with no content will not be rendered, but they still take a small - amount of time to process. - -d, --delete This option changes the mode of execution. No tiles are rendered, and instead, files are deleted. @@ -204,38 +181,65 @@ Options a certain date. Or perhaps you can incrementally update your map by passing in a subset of regions each time. It's up to you! ---lighting - This option enables map lighting, using lighting information stored by - Minecraft inside the chunks. This will make your map prettier, at the cost - of update speed. - - Note that for existing, unlit maps, you may want to clear your cache - (with -d) before updating the map to use lighting. Otherwise, only updated - chunks will have lighting enabled. +--rendermodes=MODE1[,MODE2,...] + Use this option to specify which render mode to use, such as lighting or + night. Use --list-rendermodes to get a list of available rendermodes, and + a short description of each. If you provide more than one mode (separated + by commas), Overviewer will render all of them at once, and provide a + toggle on the resulting map to switch between them. ---night - This option enables --lighting, and renders the world at night. - ---web-assets-hook=HOOK - This option lets you specify a script to run after the web assets have been - copied into the output directory, but before any tile rendering takes - place. This is an ideal time to do any custom postprocessing for markers.js - or other web assets. - - The script should be executable, and it should accept one argument: - the path to the output directory. +--list-rendermodes + List the available render modes, and a short description of each. Settings -------- - You can optionally store settings in a file named settings.py. It is a regular python script, so you can use any python functions or modules you want. -This section needs to be expanded +For a sample settings file, look at 'sample.settings.py'. Note that this file +is not meant to be used directly, but instead it should be used as a +collection of examples to guide writing your own. -For a sample settings file, look at sample.settings.py +Here's a (possibly incomplete) list of available settings, which are available +in settings.py. Note that you can also set command-line options in a similar +way. +imgformat=FORMAT + Set the output image format used for the tiles. The default is 'png', + but 'jpg' is also supported. + +zoom=ZOOM + The Overviewer by default will detect how many zoom levels are required + to show your entire map. This option sets it manually. + + *You do not normally need to set this option!* + + This is equivalent to setting the dimensions of the highest zoom level. It + does not actually change how the map is rendered, but rather *how much of + the map is rendered.* (Calling this option "zoom" may be a bit misleading, + I know) + + To be precise, it sets the width and height of the highest zoom level, in + tiles. A zoom level of z means the highest zoom level of your map will be + 2^z by 2^z tiles. + + This option map be useful if you have some outlier chunks causing your map + to be too large, or you want to render a smaller portion of your map, + instead of rendering everything. + + 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. + Tiles with no content will not be rendered, but they still take a small + amount of time to process. + +web_assets_hook + This option lets you define a function to run after the web assets have + been copied into the output directory, but before any tile rendering takes + place. This is an ideal time to do any custom postprocessing for + markers.js or other web assets. + + This function should accept one argument: a QuadtreeGen object. Viewing the Results ------------------- From bbf52a77aefdc4c43aeea971bb4907b40f7340c5 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Wed, 13 Apr 2011 11:15:19 -0400 Subject: [PATCH 09/78] added CONTRIBUTORS.rst --- CONTRIBUTORS.rst | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ README.rst | 2 +- 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 CONTRIBUTORS.rst diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst new file mode 100644 index 0000000..e251b41 --- /dev/null +++ b/CONTRIBUTORS.rst @@ -0,0 +1,53 @@ +============ +Contributors +============ + +This file contains a list of every person who has contributed code to +Overviewer. It was created from the git commit log, and should include +everyone, but we may have missed a few. + +Not currently included (but hopefully soon) are countless testers and bug +reporters that helped fixed the many bugs that have popped up in the course of +development. + +--------------- +Original Author +--------------- + + * Andrew Brown + +------------------------- +Long-term Contributions +------------------------- + +These contributors have made many changes, over a fairly long time span, or +for many different parts of the code. + + * Alejandro Aguilera + * Andrew Chin + * Aaron Griffith + * Alex Headley + * Alex Jurkiewicz + * Xon + +------------------------ +Short-term Contributions +------------------------ + +These contributors have made specific changes for a particular bug fix or +feature. + + * arrai + * Kyle Brantley + * cbarber + * Alex Cline + * Stephen Fluin + * Benjamin Herr + * Ryan Hitchman + * Jenny + * Michael Jensen + * Ryan McCue + * Morlok8k + * Gregory Short + * Sam Steele + * timwolla diff --git a/README.rst b/README.rst index 616e8d2..1d0e9ab 100644 --- a/README.rst +++ b/README.rst @@ -1,7 +1,7 @@ ==================== Minecraft Overviewer ==================== -By Andrew Brown and contributors +By Andrew Brown and contributors (see CONTRIBUTORS.rst). http://github.com/brownan/Minecraft-Overviewer From 4036c4a55000aee2f1aead11fece339a16bc4c6d Mon Sep 17 00:00:00 2001 From: Michael Writhe Date: Wed, 13 Apr 2011 10:56:24 -0700 Subject: [PATCH 10/78] indentation and comments added. --- web_assets/functions.js | 262 ++++++++++++++++++++-------------------- 1 file changed, 130 insertions(+), 132 deletions(-) diff --git a/web_assets/functions.js b/web_assets/functions.js index 7bb170f..6c9bda7 100644 --- a/web_assets/functions.js +++ b/web_assets/functions.js @@ -1,14 +1,15 @@ +// var def +var map; // god of the overviewer... bow before the google api. var markerCollection = {}; // holds groups of markers - -var map; - -var markersInit = false; -var regionsInit = false; +var markersInit = false; // only have to load the markers once, this just makes sure we only do it once +var regionsInit = false; // same thing for the regions var prevInfoWindow = null; +// add a popup info window to the marker and then the marker to the map. +// marker is the clickable image on the map with all data. +// item is just the same item in the markers.js function prepareSignMarker(marker, item) { - var c = "

" + item.msg.replace(/\n/g,"
") + "

"; var infowindow = new google.maps.InfoWindow({content: c }); @@ -17,51 +18,53 @@ function prepareSignMarker(marker, item) { prevInfoWindow.close() infowindow.open(map,marker); prevInfoWindow = infowindow - }); + }); } +// reusable function for making drop down menus. +// title = string +// items = array function createDropDown(title, items) { var control = document.createElement("DIV"); control.id = "customControl"; // let's let a style sheet do most of the styling here + var controlText = document.createElement("DIV"); + controlText.innerHTML = title; + var controlBorder = document.createElement("DIV"); controlBorder.id="top"; control.appendChild(controlBorder); - - var controlText = document.createElement("DIV"); - controlBorder.appendChild(controlText); - controlText.innerHTML = title; - var dropdownDiv = document.createElement("DIV"); - - - $(controlText).click(function() { - $(dropdownDiv).toggle(); - - }); - - dropdownDiv.id="dropDown"; control.appendChild(dropdownDiv); dropdownDiv.innerHTML=""; + // add the functionality to toggle visibility of the items + $(controlText).click(function() { + $(dropdownDiv).toggle(); + }); + + // add that control box we've made back to the map. map.controls[google.maps.ControlPosition.TOP_RIGHT].push(control); for (idx in items) { + // create the visible elements of the item var item = items[idx]; - //console.log(item); + //console.log(item); // debug var d = document.createElement("div"); var n = document.createElement("input"); n.type="checkbox"; + // give it a name $(n).data("label",item.label); jQuery(n).click(function(e) { - item.action(idx, item.label, e.target.checked); - }); + item.action(idx, item.label, e.target.checked); + }); + // if its checked, its gotta do something, do that here. if (item.checked) { n.checked = true; item.action(idx, item.label, item.checked); @@ -74,32 +77,28 @@ function createDropDown(title, items) { } } +// need to define the controls including the compass and layer controls. top right! +// input variables are for chumps... and reusable functions. this is neither. function drawMapControls() { - // viewstate link + // viewstate link (little link to where you're looking at the map, normally bottom left) var viewStateDiv = document.createElement('DIV'); - - // - viewStateDiv.id="link"; - - - map.controls[google.maps.ControlPosition.BOTTOM_RIGHT].push(viewStateDiv); - + // add it to the map, bottom left. + map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(viewStateDiv); // compass rose, in the top right corner var compassDiv = document.createElement('DIV'); - compassDiv.style.padding = '5px'; - var compassImg = document.createElement('IMG'); compassImg.src="compass.png"; compassDiv.appendChild(compassImg); - compassDiv.index = 0; + // add it to the map, top right. map.controls[google.maps.ControlPosition.TOP_RIGHT].push(compassDiv); + // only need to create the control if there are items in the list. as definned in config.js if (signGroups.length > 0) { // signpost display control @@ -107,9 +106,9 @@ function drawMapControls() { for (idx in signGroups) { var item = signGroups[idx]; items.push({"label": item.label, "checked": item.checked, - "action": function(n, l, checked) { - jQuery.each(markerCollection[l], function(i,elem) {elem.setVisible(checked);}); - }}); + "action": function(n, l, checked) { + jQuery.each(markerCollection[l], function(i,elem) {elem.setVisible(checked);}); + }}); } createDropDown("Signposts", items); } @@ -121,26 +120,26 @@ function drawMapControls() { for (idx in overlayMapTypes) { var overlay = overlayMapTypes[idx]; items.push({"label": overlay.name, "checked": false, - "action": function(i, l, checked) { - if (checked) { - map.overlayMapTypes.push(overlay); - } else { - var idx_to_delete = -1; - map.overlayMapTypes.forEach(function(e, j) { - if (e == overlay) { - idx_to_delete = j; - } - }); - if (idx_to_delete >= 0) { - map.overlayMapTypes.removeAt(idx_to_delete); - } + "action": function(i, l, checked) { + if (checked) { + map.overlayMapTypes.push(overlay); + } else { + var idx_to_delete = -1; + map.overlayMapTypes.forEach(function(e, j) { + if (e == overlay) { idx_to_delete = j; } + }); + if (idx_to_delete >= 0) { + map.overlayMapTypes.removeAt(idx_to_delete); } - }}); + } + }}); } createDropDown("Overlays", items); } } +// will be recoded by pi, currently always displays all regions all the time. +// parse the data as definned in the regions.js function initRegions() { if (regionsInit) { return; } @@ -180,12 +179,11 @@ function initRegions() { } } - - +// will initalize all the markers data as found in markers.js +// may need to be reviewed by agrif or someone else... little finicky right now. function initMarkers() { - if (markersInit) { return; } - - markersInit = true; + if (markersInit) { return; } // oh, we've already done this? nevermind, exit the function. + markersInit = true; // now that we've started, dont have to do it twice. // first, give all collections an empty array to work with for (i in signGroups) { @@ -206,8 +204,7 @@ function initMarkers() { map: map, title: jQuery.trim(item.msg), icon: iconURL - }); - + }); continue; } @@ -220,11 +217,11 @@ function initMarkers() { if (testfunc(item)) { matched = true; - if (item.type == 'sign') { iconURL = 'signpost_icon.png';} + // can add custom types of images for externally definned item types, like 'command' here. + if (item.type == 'sign') { iconURL = 'signpost_icon.png'; } - //console.log(signGroup.icon); - if (signGroup.icon) { iconURL = signGroup.icon; - } + //console.log(signGroup.icon); //debug + if (signGroup.icon) { iconURL = signGroup.icon; } var converted = fromWorldToLatLng(item.x, item.y, item.z); var marker = new google.maps.Marker({position: converted, @@ -232,7 +229,7 @@ function initMarkers() { title: jQuery.trim(item.msg), icon: iconURL, visible: false - }); + }); markerCollection[label].push(marker); @@ -271,7 +268,7 @@ function initMarkers() { } } - +// update the link in the viewstate. function makeLink() { var a=location.href.substring(0,location.href.lastIndexOf(location.search)) + "?lat=" + map.getCenter().lat().toFixed(6) @@ -280,6 +277,7 @@ function makeLink() { document.getElementById("link").innerHTML = a; } +// load the map up and add all the functions relevant stuff to the map. function initialize() { var query = location.search.substring(1); @@ -364,87 +362,87 @@ function initialize() { } - // our custom projection maps Latitude to Y, and Longitude to X as normal, - // but it maps the range [0.0, 1.0] to [0, tileSize] in both directions - // so it is easier to position markers, etc. based on their position - // (find their position in the lowest-zoom image, and divide by tileSize) - function MCMapProjection() { +// our custom projection maps Latitude to Y, and Longitude to X as normal, +// but it maps the range [0.0, 1.0] to [0, tileSize] in both directions +// so it is easier to position markers, etc. based on their position +// (find their position in the lowest-zoom image, and divide by tileSize) +function MCMapProjection() { this.inverseTileSize = 1.0 / config.tileSize; - } +} - MCMapProjection.prototype.fromLatLngToPoint = function(latLng) { +MCMapProjection.prototype.fromLatLngToPoint = function(latLng) { var x = latLng.lng() * config.tileSize; var y = latLng.lat() * config.tileSize; return new google.maps.Point(x, y); - }; +}; - MCMapProjection.prototype.fromPointToLatLng = function(point) { +MCMapProjection.prototype.fromPointToLatLng = function(point) { var lng = point.x * this.inverseTileSize; var lat = point.y * this.inverseTileSize; return new google.maps.LatLng(lat, lng); - }; +}; - // helper to get map LatLng from world coordinates - // takes arguments in X, Y, Z order - // (arguments are *out of order*, because within the function we use - // the axes like the rest of Minecraft Overviewer -- with the Z and Y - // flipped from normal minecraft usage.) - function fromWorldToLatLng(x, z, y) - { +// helper to get map LatLng from world coordinates +// takes arguments in X, Y, Z order +// (arguments are *out of order*, because within the function we use +// the axes like the rest of Minecraft Overviewer -- with the Z and Y +// flipped from normal minecraft usage.) +function fromWorldToLatLng(x, z, y) +{ // the width and height of all the highest-zoom tiles combined, inverted var perPixel = 1.0 / (config.tileSize * Math.pow(2, config.maxZoom)); - + // This information about where the center column is may change with a different // drawing implementation -- check it again after any drawing overhauls! - + // point (0, 0, 127) is at (0.5, 0.0) of tile (tiles/2 - 1, tiles/2) // so the Y coordinate is at 0.5, and the X is at 0.5 - ((tileSize / 2) / (tileSize * 2^maxZoom)) // or equivalently, 0.5 - (1 / 2^(maxZoom + 1)) var lng = 0.5 - (1.0 / Math.pow(2, config.maxZoom + 1)); var lat = 0.5; - + // the following metrics mimic those in ChunkRenderer.chunk_render in "chunk.py" // or, equivalently, chunk_render in src/iterate.c - + // each block on X axis adds 12px to x and subtracts 6px from y lng += 12 * x * perPixel; lat -= 6 * x * perPixel; - + // each block on Y axis adds 12px to x and adds 6px to y lng += 12 * y * perPixel; lat += 6 * y * perPixel; - + // each block down along Z adds 12px to y lat += 12 * (128 - z) * perPixel; // add on 12 px to the X coordinate to center our point lng += 12 * perPixel; - + return new google.maps.LatLng(lat, lng); - } +} function getTileUrlGenerator(path, path_base) { - return function(tile, zoom) { - var url = path; - var url_base = ( path_base ? path_base : '' ); - if(tile.x < 0 || tile.x >= Math.pow(2, zoom) || tile.y < 0 || tile.y >= Math.pow(2, zoom)) { - url += '/blank'; - } else if(zoom == 0) { - url += '/base'; - } else { - for(var z = zoom - 1; z >= 0; --z) { - var x = Math.floor(tile.x / Math.pow(2, z)) % 2; - var y = Math.floor(tile.y / Math.pow(2, z)) % 2; - url += '/' + (x + 2 * y); + return function(tile, zoom) { + var url = path; + var url_base = ( path_base ? path_base : '' ); + if(tile.x < 0 || tile.x >= Math.pow(2, zoom) || tile.y < 0 || tile.y >= Math.pow(2, zoom)) { + url += '/blank'; + } else if(zoom == 0) { + url += '/base'; + } else { + for(var z = zoom - 1; z >= 0; --z) { + var x = Math.floor(tile.x / Math.pow(2, z)) % 2; + var y = Math.floor(tile.y / Math.pow(2, z)) % 2; + url += '/' + (x + 2 * y); + } } - } - url = url + '.' + config.fileExt; - if(config.cacheMinutes > 0) { - var d = new Date(); - url += '?c=' + Math.floor(d.getTime() / (1000 * 60 * config.cacheMinutes)); - } - return(url_base + url); - } + url = url + '.' + config.fileExt; + if(config.cacheMinutes > 0) { + var d = new Date(); + url += '?c=' + Math.floor(d.getTime() / (1000 * 60 * config.cacheMinutes)); + } + return(url_base + url); + } } var MCMapOptions = new Array; @@ -453,39 +451,39 @@ var mapTypeIdDefault = null; var mapTypeIds = []; var overlayMapTypes = []; for (idx in mapTypeData) { - var view = mapTypeData[idx]; + var view = mapTypeData[idx]; - MCMapOptions[view.label] = { - getTileUrl: getTileUrlGenerator(view.path, view.base), - tileSize: new google.maps.Size(config.tileSize, config.tileSize), - maxZoom: config.maxZoom, - minZoom: 0, - isPng: !(config.fileExt.match(/^png$/i) == null) - }; + MCMapOptions[view.label] = { + getTileUrl: getTileUrlGenerator(view.path, view.base), + tileSize: new google.maps.Size(config.tileSize, config.tileSize), + maxZoom: config.maxZoom, + minZoom: 0, + isPng: !(config.fileExt.match(/^png$/i) == null) + }; - MCMapType[view.label] = new google.maps.ImageMapType(MCMapOptions[view.label]); - MCMapType[view.label].name = view.label; - MCMapType[view.label].alt = "Minecraft " + view.label + " Map"; - MCMapType[view.label].projection = new MCMapProjection(); - - if (view.overlay) { - overlayMapTypes.push(MCMapType[view.label]); - } else { + MCMapType[view.label] = new google.maps.ImageMapType(MCMapOptions[view.label]); + MCMapType[view.label].name = view.label; + MCMapType[view.label].alt = "Minecraft " + view.label + " Map"; + MCMapType[view.label].projection = new MCMapProjection(); + + if (view.overlay) { + overlayMapTypes.push(MCMapType[view.label]); + } else { if (mapTypeIdDefault == null) { - mapTypeIdDefault = 'mcmap' + view.label; + mapTypeIdDefault = 'mcmap' + view.label; } mapTypeIds.push('mcmap' + view.label); } } - function CoordMapType() { - } +function CoordMapType() { +} - function CoordMapType(tileSize) { +function CoordMapType(tileSize) { this.tileSize = tileSize; - } +} - CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) { +CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) { var div = ownerDocument.createElement('DIV'); div.innerHTML = "(" + coord.x + ", " + coord.y + ", " + zoom + ")"; div.innerHTML += "
"; @@ -497,4 +495,4 @@ for (idx in mapTypeData) { div.style.borderWidth = '1px'; div.style.borderColor = '#AAAAAA'; return div; - }; +}; \ No newline at end of file From 1b74ab4b4513854bc27150d45235702e9932375a Mon Sep 17 00:00:00 2001 From: Michael Writhe Date: Wed, 13 Apr 2011 14:45:24 -0600 Subject: [PATCH 11/78] Added the spawn button --- web_assets/functions.js | 31 +++++++++++++++++++++++++++++++ web_assets/style.css | 7 +++++++ 2 files changed, 38 insertions(+) diff --git a/web_assets/functions.js b/web_assets/functions.js index 6c9bda7..6cc1efb 100644 --- a/web_assets/functions.js +++ b/web_assets/functions.js @@ -77,6 +77,31 @@ function createDropDown(title, items) { } } +function HomeControl(controlDiv, map) { + + controlDiv.style.padding = '5px'; + + // Set CSS for the control border + var controlUI = document.createElement('DIV'); + control.id='customControl'; + //controlUI.className='controlUI'; + controlUI.title = 'Click to set the map to Spawn'; + controlDiv.appendChild(controlUI); + + // Set CSS for the control interior + var controlText = document.createElement('DIV'); + //controlText.className='controlText'; + controlText.innerHTML = 'Spawn'; + controlUI.appendChild(controlText); + + // Setup the click event listeners: simply set the map to map center as definned below + google.maps.event.addDomListener(controlUI, 'click', function() { + map.panTo(defaultCenter); + }); + +} + + // need to define the controls including the compass and layer controls. top right! // input variables are for chumps... and reusable functions. this is neither. function drawMapControls() { @@ -96,6 +121,12 @@ function drawMapControls() { compassDiv.index = 0; // add it to the map, top right. map.controls[google.maps.ControlPosition.TOP_RIGHT].push(compassDiv); + + // Spawn button + var homeControlDiv = document.createElement('DIV'); + var homeControl = new HomeControl(homeControlDiv, map); + homeControlDiv.index = 1; + map.controls[google.maps.ControlPosition.TOP_RIGHT].push(homeControlDiv); // only need to create the control if there are items in the list. as definned in config.js diff --git a/web_assets/style.css b/web_assets/style.css index 32389bf..8585eb3 100644 --- a/web_assets/style.css +++ b/web_assets/style.css @@ -40,6 +40,13 @@ body { height: 100%; margin: 0px; padding: 0px ; background-color: #000; } display: none; } +#customControl > div#button { + border: 1px solid #000; + font-size: 12px; + background-color: #fff; + display: none; +} + #link { background-color: #fff; /* fallback */ From 33bfdca28a9b508b427f50ed8a077e061c3f6747 Mon Sep 17 00:00:00 2001 From: Michael Writhe Date: Wed, 13 Apr 2011 15:55:49 -0600 Subject: [PATCH 12/78] fixed css references for Spawn Button --- web_assets/functions.js | 42 ++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/web_assets/functions.js b/web_assets/functions.js index 6cc1efb..c1430b7 100644 --- a/web_assets/functions.js +++ b/web_assets/functions.js @@ -2,7 +2,8 @@ var map; // god of the overviewer... bow before the google api. var markerCollection = {}; // holds groups of markers var markersInit = false; // only have to load the markers once, this just makes sure we only do it once -var regionsInit = false; // same thing for the regions +var regionCollection = {}; // holds groups of regions +var regionsInit = false; // only have to load the regions once, this just makes sure we only do it once var prevInfoWindow = null; @@ -82,21 +83,22 @@ function HomeControl(controlDiv, map) { controlDiv.style.padding = '5px'; // Set CSS for the control border - var controlUI = document.createElement('DIV'); - control.id='customControl'; - //controlUI.className='controlUI'; - controlUI.title = 'Click to set the map to Spawn'; - controlDiv.appendChild(controlUI); + var control = document.createElement('DIV'); + control.id='top'; + control.title = 'Click to set the map to Spawn'; + controlDiv.appendChild(control); // Set CSS for the control interior var controlText = document.createElement('DIV'); - //controlText.className='controlText'; controlText.innerHTML = 'Spawn'; - controlUI.appendChild(controlText); + controlText.id='button'; + control.appendChild(controlText); // Setup the click event listeners: simply set the map to map center as definned below - google.maps.event.addDomListener(controlUI, 'click', function() { - map.panTo(defaultCenter); + google.maps.event.addDomListener(control, 'click', function() { + map.panTo(fromWorldToLatLng(config.center[0], + config.center[1], + config.center[2])); }); } @@ -125,6 +127,7 @@ function drawMapControls() { // Spawn button var homeControlDiv = document.createElement('DIV'); var homeControl = new HomeControl(homeControlDiv, map); + homeControlDiv.id = "customControl"; homeControlDiv.index = 1; map.controls[google.maps.ControlPosition.TOP_RIGHT].push(homeControlDiv); @@ -173,11 +176,23 @@ function drawMapControls() { // parse the data as definned in the regions.js function initRegions() { if (regionsInit) { return; } - regionsInit = true; + + /* remove comment on this if we decide to add regionGroups in the config.js + this would let us selectivley show groups of regions based on the name of the region, or flags set. + could be good... + + for (i in regionGroups) { + regionCollection[regionGroups[i].label] = []; + } + remove next line if this is kept. + */ + regionCollection['All Regions'] = []; for (i in regionData) { var region = regionData[i]; + + // pull all the points out of the regions file. var converted = new google.maps.MVCArray(); for (j in region.path) { var point = region.path[j]; @@ -185,7 +200,7 @@ function initRegions() { } if (region.closed) { - new google.maps.Polygon({clickable: false, + var region = new google.maps.Polygon({clickable: false, geodesic: false, map: map, strokeColor: region.color, @@ -197,7 +212,7 @@ function initRegions() { paths: converted }); } else { - new google.maps.Polyline({clickable: false, + var region = new google.maps.Polyline({clickable: false, geodesic: false, map: map, strokeColor: region.color, @@ -207,6 +222,7 @@ function initRegions() { path: converted }); } + regionCollection['All Regions'].push(region); //if we add groups to config.js this will need to be changed. } } From b89ea8db8c16523de47318f139f468c6e5fdf0fa Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Wed, 13 Apr 2011 19:53:03 +0200 Subject: [PATCH 13/78] Working cave rendermode without tinting. --- chunk.py | 16 +++- setup.py | 2 +- src/rendermode-cave.c | 190 ++++++++++++++++++++++++++++++++++++++++++ src/rendermodes.c | 1 + src/rendermodes.h | 14 ++++ 5 files changed, 221 insertions(+), 2 deletions(-) create mode 100644 src/rendermode-cave.c diff --git a/chunk.py b/chunk.py index 977fdfa..9db1194 100644 --- a/chunk.py +++ b/chunk.py @@ -284,7 +284,14 @@ class ChunkRenderer(object): self._load_up_right() return self._up_right_blocks up_right_blocks = property(_load_up_right_blocks) - + + def _load_up_right_skylight(self): + """Loads and returns lower-right skylight array""" + if not hasattr(self, "_up_right_skylight"): + self._load_up_right() + return self._up_right_skylight + up_right_skylight = property(_load_up_right_skylight) + def _load_up_left(self): """Loads and sets data from upper-left chunk""" chunk_path = self.world.get_region_path(self.chunkX, self.chunkY - 1) @@ -305,6 +312,13 @@ class ChunkRenderer(object): return self._up_left_blocks up_left_blocks = property(_load_up_left_blocks) + def _load_up_left_skylight(self): + """Loads and returns lower-right skylight array""" + if not hasattr(self, "_up_left_skylight"): + self._load_up_left() + return self._up_left_skylight + up_left_skylight = property(_load_up_left_skylight) + def generate_pseudo_ancildata(self,x,y,z,blockid, north_position = 0 ): """ Generates a pseudo ancillary data for blocks that depend of what are surrounded and don't have ancillary data diff --git a/setup.py b/setup.py index 0a36bcf..32360fb 100644 --- a/setup.py +++ b/setup.py @@ -55,7 +55,7 @@ except: pil_include = [] c_overviewer_files = ['src/main.c', 'src/composite.c', 'src/iterate.c', 'src/endian.c'] -c_overviewer_files += ['src/rendermodes.c', 'src/rendermode-normal.c', 'src/rendermode-lighting.c', 'src/rendermode-night.c', 'src/rendermode-spawn.c'] +c_overviewer_files += ['src/rendermodes.c', 'src/rendermode-normal.c', 'src/rendermode-lighting.c', 'src/rendermode-night.c', 'src/rendermode-spawn.c', 'src/rendermode-cave.c'] c_overviewer_files += ['src/Draw.c'] c_overviewer_includes = ['src/overviewer.h', 'src/rendermodes.h'] setup_kwargs['ext_modules'].append(Extension('c_overviewer', c_overviewer_files, include_dirs=['.', numpy_include] + pil_include, depends=c_overviewer_includes, extra_link_args=[])) diff --git a/src/rendermode-cave.c b/src/rendermode-cave.c new file mode 100644 index 0000000..85d7d93 --- /dev/null +++ b/src/rendermode-cave.c @@ -0,0 +1,190 @@ +/* + * 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 . + */ + +#include "overviewer.h" +#include +//~ +//~ /* figures out the black_coeff from a given skylight and blocklight, used in + //~ lighting calculations -- note this is *different* from the one in + //~ rendermode-lighting.c (the "skylight - 11" part) */ +//~ static float calculate_darkness(unsigned char skylight, unsigned char blocklight) { + //~ return 1.0f - powf(0.8f, 15.0 - MAX(blocklight, skylight - 11)); +//~ } + +static int +rendermode_cave_occluded(void *data, RenderState *state) { + int x = state->x, y = state->y, z = state->z; + RenderModeCave* self; + self = (RenderModeCave *)data; + + /* check if the block is touching skylight */ + if (z != 127) { + + if (getArrayByte3D(self->skylight, x, y, z+1) != 0) { + return 1; + } + + if ((x == 15)) { + if (self->up_right_skylight != Py_None) { + if (getArrayByte3D(self->up_right_skylight, 0, y, z) != 0) { + return 1; + } + } + } else { + if (getArrayByte3D(self->skylight, x+1, y, z) != 0) { + return 1; + } + } + + if (x == 0) { + if (self->left_skylight != Py_None) { + if (getArrayByte3D(self->left_skylight, 15, y, z) != 0) { + return 1; + } + } + } else { + if (getArrayByte3D(self->skylight, x-1, y, z) != 0) { + return 1; + } + } + + if (y == 15) { + if (self->right_skylight != Py_None) { + if (getArrayByte3D(self->right_skylight, 0, y, z) != 0) { + return 1; + } + } + } else { + if (getArrayByte3D(self->skylight, x, y+1, z) != 0) { + return 1; + } + } + + if (y == 0) { + if (self->up_left_skylight != Py_None) { + if (getArrayByte3D(self->up_left_skylight, 15, y, z) != 0) { + return 1; + } + } + } else { + if (getArrayByte3D(self->skylight, x, y-1, z) != 0) { + return 1; + } + } + + /* check for normal occlusion */ + /* use ajacent chunks, if not you get blocks spreaded in chunk edges */ + if ( (x == 0) && (y != 15) ) { + if (state->left_blocks != Py_None) { + if (!is_transparent(getArrayByte3D(state->left_blocks, 15, y, z)) && + !is_transparent(getArrayByte3D(state->blocks, x, y, z+1)) && + !is_transparent(getArrayByte3D(state->blocks, x, y+1, z))) { + return 1; + } + } else { + return 1; + } + } + + if ( (x != 0) && (y == 15) ) { + if (state->right_blocks != Py_None) { + if (!is_transparent(getArrayByte3D(state->blocks, x-1, y, z)) && + !is_transparent(getArrayByte3D(state->right_blocks, x, 0, z)) && + !is_transparent(getArrayByte3D(state->blocks, x, y, z+1))) { + return 1; + } + } else { + return 1; + } + } + + if ( (x == 0) && (y == 15) ) { + if ((state->left_blocks != Py_None) && + (state->right_blocks != Py_None)) { + if (!is_transparent(getArrayByte3D(state->left_blocks, 15, y, z)) && + !is_transparent(getArrayByte3D(state->right_blocks, x, 0, z)) && + !is_transparent(getArrayByte3D(state->blocks, x, y, z+1))) { + return 1; + } + } else { + return 1; + } + } + + if ( (x != 0) && (y != 15) && + !is_transparent(getArrayByte3D(state->blocks, x-1, y, z)) && + !is_transparent(getArrayByte3D(state->blocks, x, y, z+1)) && + !is_transparent(getArrayByte3D(state->blocks, x, y+1, z))) { + return 1; + } + + } else { /* if z == 127 don't skip */ + return 1; + } + + return 0; +} + +static int +rendermode_cave_start(void *data, RenderState *state) { + RenderModeCave* self; + self = (RenderModeCave *)data; + + /* first, chain up */ + int ret = rendermode_normal.start(data, state); + if (ret != 0) + return ret; + + /* if there's skylight we are in the surface! */ + self->skylight = PyObject_GetAttrString(state->self, "skylight"); + self->left_skylight = PyObject_GetAttrString(state->self, "left_skylight"); + self->right_skylight = PyObject_GetAttrString(state->self, "right_skylight"); + self->up_left_skylight = PyObject_GetAttrString(state->self, "up_left_skylight"); + self->up_right_skylight = PyObject_GetAttrString(state->self, "up_right_skylight"); + + return 0; +} + +static void +rendermode_cave_finish(void *data, RenderState *state) { + RenderModeCave* self; + self = (RenderModeCave *)data; + + Py_DECREF(self->skylight); + Py_DECREF(self->left_skylight); + Py_DECREF(self->right_skylight); + Py_DECREF(self->up_left_skylight); + Py_DECREF(self->up_right_skylight); + + rendermode_normal.finish(data, state); +} + +static void +rendermode_cave_draw(void *data, RenderState *state, PyObject *src, PyObject *mask) { + /* nothing special to do */ + rendermode_normal.draw(data, state, src, mask); + +} + +RenderModeInterface rendermode_cave = { + "cave", "render only caves in normal mode", + sizeof(RenderModeCave), + rendermode_cave_start, + rendermode_cave_finish, + rendermode_cave_occluded, + rendermode_cave_draw, +}; diff --git a/src/rendermodes.c b/src/rendermodes.c index 0ef5550..08ac140 100644 --- a/src/rendermodes.c +++ b/src/rendermodes.c @@ -26,6 +26,7 @@ static RenderModeInterface *render_modes[] = { &rendermode_lighting, &rendermode_night, &rendermode_spawn, + &rendermode_cave, NULL }; diff --git a/src/rendermodes.h b/src/rendermodes.h index 3027a7f..babc551 100644 --- a/src/rendermodes.h +++ b/src/rendermodes.h @@ -119,4 +119,18 @@ typedef struct { } RenderModeSpawn; extern RenderModeInterface rendermode_spawn; +/* CAVE */ +typedef struct { + /* render blocks with lighting mode */ + RenderModeNormal 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; + +} RenderModeCave; +extern RenderModeInterface rendermode_cave; + #endif /* __RENDERMODES_H_INCLUDED__ */ From 1fb77cf6e6c15d53bc2bbec95794ce143f93691b Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Wed, 13 Apr 2011 20:10:44 +0200 Subject: [PATCH 14/78] Add code to remove lakes and seas. --- src/rendermode-cave.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/rendermode-cave.c b/src/rendermode-cave.c index 85d7d93..f532a00 100644 --- a/src/rendermode-cave.c +++ b/src/rendermode-cave.c @@ -27,7 +27,7 @@ static int rendermode_cave_occluded(void *data, RenderState *state) { - int x = state->x, y = state->y, z = state->z; + int x = state->x, y = state->y, z = state->z, dz = 0; RenderModeCave* self; self = (RenderModeCave *)data; @@ -132,10 +132,30 @@ rendermode_cave_occluded(void *data, RenderState *state) { return 1; } - } else { /* if z == 127 don't skip */ + } else { /* if z == 127 skip */ return 1; } + /* check for lakes and seas and don't render them */ + /* at this point of the code the block has no skylight + * and is not occluded, but a deep sea can fool these + * 2 tests */ + + if ((getArrayByte3D(state->blocks, x, y, z) == 9) || + (getArrayByte3D(state->blocks, x, y, z+1) == 9)) { + + for (dz = z+1; dz < 127; dz++) { + if (getArrayByte3D(self->skylight, x, y, dz) != 0) { + return 1; + } + if (getArrayByte3D(state->blocks, x, y, dz) != 9) { + /* we are out of the water! */ + return 0; + } + } + } + + return 0; } From 8165ce979d2f3411b840fd9d0161f230331944c8 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Thu, 14 Apr 2011 00:32:12 +0200 Subject: [PATCH 15/78] Add depth tinting to cave rendermode. --- chunk.py | 6 ++++-- src/rendermode-cave.c | 29 +++++++++++++++++++++++++---- src/rendermodes.h | 4 ++++ 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/chunk.py b/chunk.py index 9db1194..a5766d6 100644 --- a/chunk.py +++ b/chunk.py @@ -472,8 +472,10 @@ def generate_depthcolors(): g = 0 b = 0 for z in range(128): - img = Image.new("RGB", (24,24), (r,g,b)) - depth_colors.append(img) + depth_colors.append(r) + depth_colors.append(g) + depth_colors.append(b) + if z < 32: g += 7 elif z < 64: diff --git a/src/rendermode-cave.c b/src/rendermode-cave.c index f532a00..88a7d83 100644 --- a/src/rendermode-cave.c +++ b/src/rendermode-cave.c @@ -144,12 +144,13 @@ rendermode_cave_occluded(void *data, RenderState *state) { if ((getArrayByte3D(state->blocks, x, y, z) == 9) || (getArrayByte3D(state->blocks, x, y, z+1) == 9)) { - for (dz = z+1; dz < 127; dz++) { + for (dz = z+1; dz < 127; dz++) { /* go up and check for skylight */ if (getArrayByte3D(self->skylight, x, y, dz) != 0) { return 1; } if (getArrayByte3D(state->blocks, x, y, dz) != 9) { - /* we are out of the water! */ + /* we are out of the water! and there's no skylight + * , i.e. is a cave lake or something similar */ return 0; } } @@ -176,6 +177,10 @@ rendermode_cave_start(void *data, RenderState *state) { self->up_left_skylight = PyObject_GetAttrString(state->self, "up_left_skylight"); self->up_right_skylight = PyObject_GetAttrString(state->self, "up_right_skylight"); + /* colors for tinting */ + self->depth_colors = PyObject_GetAttrString(state->chunk, "depth_colors"); + + return 0; } @@ -190,14 +195,30 @@ rendermode_cave_finish(void *data, RenderState *state) { Py_DECREF(self->up_left_skylight); Py_DECREF(self->up_right_skylight); + Py_DECREF(self->depth_colors); + rendermode_normal.finish(data, state); } static void rendermode_cave_draw(void *data, RenderState *state, PyObject *src, PyObject *mask) { - /* nothing special to do */ + RenderModeCave* self; + self = (RenderModeCave *)data; + + int z = state->z; + int r = 0, g = 0, b = 0; + + /* draw the normal block */ rendermode_normal.draw(data, state, src, mask); - + + /* get the colors and tint and tint */ + /* TODO TODO for a nether mode there isn't tinting! */ + 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, mask, state->imgx, state->imgy, 0, 0); + } RenderModeInterface rendermode_cave = { diff --git a/src/rendermodes.h b/src/rendermodes.h index babc551..70e9c46 100644 --- a/src/rendermodes.h +++ b/src/rendermodes.h @@ -123,12 +123,16 @@ extern RenderModeInterface rendermode_spawn; typedef struct { /* render blocks with lighting mode */ RenderModeNormal 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; + + /* colors used for tinting */ + PyObject *depth_colors; } RenderModeCave; extern RenderModeInterface rendermode_cave; From 183d278f810b60eabf185fd2450c8e16f844b68b Mon Sep 17 00:00:00 2001 From: Michael Writhe Date: Wed, 13 Apr 2011 21:59:52 -0600 Subject: [PATCH 16/78] first steps to getting toggle for regions working --- config.js | 5 ++ web_assets/functions.js | 101 ++++++++++++++++++++++++++++------------ 2 files changed, 77 insertions(+), 29 deletions(-) diff --git a/config.js b/config.js index 43b4982..0954116 100644 --- a/config.js +++ b/config.js @@ -33,6 +33,11 @@ var signGroups = [ {label: "All", match: function(s) {return true}}, ]; +//piTODO: document this +var regionGroups = [ + {label: "WorldGuard", 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. diff --git a/web_assets/functions.js b/web_assets/functions.js index c1430b7..ea59263 100644 --- a/web_assets/functions.js +++ b/web_assets/functions.js @@ -23,6 +23,21 @@ function prepareSignMarker(marker, item) { } +// add a popup info window to the region and then the region to the map. +// region is the clickable image on the map with all data. +// item is just the same item in the regions.js +function prepareRegionShape(shape, region) { + var c = "

" + region.label + "

"; + var infowindow = new google.maps.InfoWindow({content: c }); + google.maps.event.addListener(shape, 'click', function() { + if (prevInfoWindow) + prevInfoWindow.close() + infowindow.open(map,shape); + prevInfoWindow = infowindow + }); + +} + // reusable function for making drop down menus. // title = string // items = array @@ -85,7 +100,7 @@ function HomeControl(controlDiv, map) { // Set CSS for the control border var control = document.createElement('DIV'); control.id='top'; - control.title = 'Click to set the map to Spawn'; + control.title = 'Click to center the map on the Spawn'; controlDiv.appendChild(control); // Set CSS for the control interior @@ -147,6 +162,29 @@ function drawMapControls() { createDropDown("Signposts", items); } + // if there are any regions data, lets show the option to hide/show them. + if (regionGroups.length > 0) { + // region display control + + var items = []; + for (idx in regionGroups) { + var item = regionGroups[idx]; + items.push({"label": item.label, "checked": item.checked, + "action": function(n, l, checked) { + if (checked) { + jQuery.each(regionCollection[l], function(i,elem) { + elem.setVisible('visible'); + }); + } else { + jQuery.each(regionCollection[l], function(i,elem) { + elem.setVisible('hidden'); + }); + } + }}); + } + createDropDown("Regions", items); + } + if (overlayMapTypes.length > 0) { // overlay maps control @@ -178,16 +216,9 @@ function initRegions() { if (regionsInit) { return; } regionsInit = true; - /* remove comment on this if we decide to add regionGroups in the config.js - this would let us selectivley show groups of regions based on the name of the region, or flags set. - could be good... - for (i in regionGroups) { regionCollection[regionGroups[i].label] = []; } - remove next line if this is kept. - */ - regionCollection['All Regions'] = []; for (i in regionData) { var region = regionData[i]; @@ -198,31 +229,43 @@ function initRegions() { var point = region.path[j]; converted.push(fromWorldToLatLng(point.x, point.y, point.z)); } + + for (idx in regionGroups) { + var regionGroup = regionGroups[idx]; + var testfunc = regionGroup.match; + var label = regionGroup.label; - if (region.closed) { - var region = new google.maps.Polygon({clickable: false, - geodesic: false, - map: map, - strokeColor: region.color, - strokeOpacity: region.opacity, - strokeWeight: 2, - fillColor: region.color, - fillOpacity: region.opacity * 0.25, - zIndex: i, - paths: converted + if (region.closed) { + var shape = new google.maps.Polygon({ + name: region.label, + clickable: false, + geodesic: false, + map: map, + strokeColor: region.color, + strokeOpacity: region.opacity, + strokeWeight: 2, + fillColor: region.color, + fillOpacity: region.opacity * 0.25, + zIndex: i, + paths: converted }); - } else { - var region = new google.maps.Polyline({clickable: false, - geodesic: false, - map: map, - strokeColor: region.color, - strokeOpacity: region.opacity, - strokeWeight: 2, - zIndex: i, - path: converted + } else { + var shape = new google.maps.Polyline({ + name: region.label, + clickable: false, + geodesic: false, + map: map, + strokeColor: region.color, + strokeOpacity: region.opacity, + strokeWeight: 2, + zIndex: i, + path: converted }); + } + regionCollection[label].push(shape); + prepareRegionShape(shape, region); + } - regionCollection['All Regions'].push(region); //if we add groups to config.js this will need to be changed. } } From d51d863bed28d1c8eed8c685a30c168e279bbfeb Mon Sep 17 00:00:00 2001 From: Michael Writhe Date: Thu, 14 Apr 2011 08:30:56 -0600 Subject: [PATCH 17/78] toggle regions --- web_assets/functions.js | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/web_assets/functions.js b/web_assets/functions.js index ea59263..c109603 100644 --- a/web_assets/functions.js +++ b/web_assets/functions.js @@ -171,15 +171,9 @@ function drawMapControls() { var item = regionGroups[idx]; items.push({"label": item.label, "checked": item.checked, "action": function(n, l, checked) { - if (checked) { - jQuery.each(regionCollection[l], function(i,elem) { - elem.setVisible('visible'); - }); - } else { - jQuery.each(regionCollection[l], function(i,elem) { - elem.setVisible('hidden'); - }); - } + jQuery.each(regionCollection[l], function(i,elem) { + elem.setMap(checked ? map : null); + }); }}); } createDropDown("Regions", items); @@ -240,7 +234,7 @@ function initRegions() { name: region.label, clickable: false, geodesic: false, - map: map, + map: null, strokeColor: region.color, strokeOpacity: region.opacity, strokeWeight: 2, @@ -254,7 +248,7 @@ function initRegions() { name: region.label, clickable: false, geodesic: false, - map: map, + map: null, strokeColor: region.color, strokeOpacity: region.opacity, strokeWeight: 2, @@ -263,8 +257,6 @@ function initRegions() { }); } regionCollection[label].push(shape); - prepareRegionShape(shape, region); - } } } From 5cc1c55ff11871f07673ae777b1e0f27ea4a9146 Mon Sep 17 00:00:00 2001 From: Michael Writhe Date: Thu, 14 Apr 2011 08:32:49 -0600 Subject: [PATCH 18/78] regions toggle --- web_assets/functions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_assets/functions.js b/web_assets/functions.js index c109603..e2d1123 100644 --- a/web_assets/functions.js +++ b/web_assets/functions.js @@ -172,7 +172,7 @@ function drawMapControls() { items.push({"label": item.label, "checked": item.checked, "action": function(n, l, checked) { jQuery.each(regionCollection[l], function(i,elem) { - elem.setMap(checked ? map : null); + elem.setMap(checked ? map : null); // Thanks to LeastWeasel for this line! }); }}); } From eac56a6513a8f1942b962cae93d2050e3ec3a1fc Mon Sep 17 00:00:00 2001 From: Michael Writhe Date: Thu, 14 Apr 2011 09:32:47 -0600 Subject: [PATCH 19/78] clickable and now toggleable regions --- config.js | 20 ++++++++++++++++++-- web_assets/functions.js | 24 ++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/config.js b/config.js index 0954116..90415f4 100644 --- a/config.js +++ b/config.js @@ -33,9 +33,25 @@ var signGroups = [ {label: "All", match: function(s) {return true}}, ]; -//piTODO: document this +/* regionGroups -- A list of region groups. A region can fall into zero, one, or more than one + * group. See below for some examples. + * regions have been designed to work with the + * WorldGuard Overviewer Region importer at https://github.com/pironic/WG2OvR But your host must support php in order + * to run WG2OvR. You can also continue to use any other region format, but your regions + * must now have a label definned in the regions.js. + * + * Required: + * label : string. Displayed in the drop down menu control. + * clickable : boolean. Will determine if we should generate an experimental info window + * that shows details about the clicked region. + * match : function. Applied to each region (from region.js). It returns true if the region + * Should be part of the group. + * + * Optional: + * checked : boolean. Set to true to have the group visible by default + */ var regionGroups = [ - {label: "WorldGuard", match: function(s) {return true}}, + //{label: "WorldGuard", clickable: false, checked: false, match: function(s) {return true}}, ]; /* mapTypeData -- a list of alternate map renderings available. At least one rendering must be diff --git a/web_assets/functions.js b/web_assets/functions.js index e2d1123..1ad1714 100644 --- a/web_assets/functions.js +++ b/web_assets/functions.js @@ -219,20 +219,23 @@ function initRegions() { // pull all the points out of the regions file. var converted = new google.maps.MVCArray(); + var infoPoint = ""; for (j in region.path) { var point = region.path[j]; converted.push(fromWorldToLatLng(point.x, point.y, point.z)); + } for (idx in regionGroups) { var regionGroup = regionGroups[idx]; var testfunc = regionGroup.match; + var clickable = regionGroup.clickable var label = regionGroup.label; if (region.closed) { var shape = new google.maps.Polygon({ name: region.label, - clickable: false, + clickable: clickable, geodesic: false, map: null, strokeColor: region.color, @@ -246,7 +249,7 @@ function initRegions() { } else { var shape = new google.maps.Polyline({ name: region.label, - clickable: false, + clickable: clickable, geodesic: false, map: null, strokeColor: region.color, @@ -257,6 +260,23 @@ function initRegions() { }); } regionCollection[label].push(shape); + + if (clickable) { + // add the region infowindow popup + infowindow = new google.maps.InfoWindow(); + google.maps.event.addListener(shape, 'click', function(e,i) { + + var contentString = "Region: "+this.name+"
"; + contentString += "Clicked Location:
" + e.latLng.lat() + "," + e.latLng.lng() + "
"; + + // Replace our Info Window's content and position + infowindow.setContent(contentString); + infowindow.setPosition(e.latLng); + + infowindow.open(map); + + }); + } } } } From 8fa515fa5986edcc932ef8a56465cbd828006d22 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Thu, 14 Apr 2011 15:12:18 -0400 Subject: [PATCH 20/78] fixes for building cave mode on windows --- src/rendermode-cave.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/rendermode-cave.c b/src/rendermode-cave.c index 88a7d83..ae5b565 100644 --- a/src/rendermode-cave.c +++ b/src/rendermode-cave.c @@ -163,10 +163,11 @@ rendermode_cave_occluded(void *data, RenderState *state) { static int rendermode_cave_start(void *data, RenderState *state) { RenderModeCave* self; + int ret; self = (RenderModeCave *)data; /* first, chain up */ - int ret = rendermode_normal.start(data, state); + ret = rendermode_normal.start(data, state); if (ret != 0) return ret; @@ -203,10 +204,11 @@ rendermode_cave_finish(void *data, RenderState *state) { static void rendermode_cave_draw(void *data, RenderState *state, PyObject *src, PyObject *mask) { RenderModeCave* self; + int z, r, g, b; self = (RenderModeCave *)data; - int z = state->z; - int r = 0, g = 0, b = 0; + z = state->z; + r = 0, g = 0, b = 0; /* draw the normal block */ rendermode_normal.draw(data, state, src, mask); From 26c6b686b3f505e7366c65ac503362d96bc50480 Mon Sep 17 00:00:00 2001 From: Michael Writhe Date: Thu, 14 Apr 2011 14:14:31 -0600 Subject: [PATCH 21/78] region label is now optional --- config.js | 8 ++++---- web_assets/functions.js | 28 +++++++--------------------- 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/config.js b/config.js index 90415f4..ed28985 100644 --- a/config.js +++ b/config.js @@ -37,13 +37,13 @@ var signGroups = [ * group. See below for some examples. * regions have been designed to work with the * WorldGuard Overviewer Region importer at https://github.com/pironic/WG2OvR But your host must support php in order - * to run WG2OvR. You can also continue to use any other region format, but your regions - * must now have a label definned in the regions.js. + * to run WG2OvR. You can also continue to use any other region format. * * Required: * label : string. Displayed in the drop down menu control. * clickable : boolean. Will determine if we should generate an experimental info window - * that shows details about the clicked region. + * that shows details about the clicked region. + * NOTE: if a region (as definned in region.js) does not have a label, this will default to false. * match : function. Applied to each region (from region.js). It returns true if the region * Should be part of the group. * @@ -51,7 +51,7 @@ var signGroups = [ * checked : boolean. Set to true to have the group visible by default */ var regionGroups = [ - //{label: "WorldGuard", clickable: false, checked: false, match: function(s) {return true}}, + //{label: "All", clickable: false, checked: false, match: function(s) {return true}}, ]; /* mapTypeData -- a list of alternate map renderings available. At least one rendering must be diff --git a/web_assets/functions.js b/web_assets/functions.js index 1ad1714..3fb40d6 100644 --- a/web_assets/functions.js +++ b/web_assets/functions.js @@ -20,22 +20,6 @@ function prepareSignMarker(marker, item) { infowindow.open(map,marker); prevInfoWindow = infowindow }); - -} - -// add a popup info window to the region and then the region to the map. -// region is the clickable image on the map with all data. -// item is just the same item in the regions.js -function prepareRegionShape(shape, region) { - var c = "

" + region.label + "

"; - var infowindow = new google.maps.InfoWindow({content: c }); - google.maps.event.addListener(shape, 'click', function() { - if (prevInfoWindow) - prevInfoWindow.close() - infowindow.open(map,shape); - prevInfoWindow = infowindow - }); - } // reusable function for making drop down menus. @@ -232,6 +216,13 @@ function initRegions() { var clickable = regionGroup.clickable var label = regionGroup.label; + if(region.label) { + var name = region.label + } else { + var name = 'rawr'; + clickable = false; // if it doesn't have a name, we dont have to show it. + } + if (region.closed) { var shape = new google.maps.Polygon({ name: region.label, @@ -338,10 +329,7 @@ function initMarkers() { if (item.type == 'sign') { prepareSignMarker(marker, item); } - } - - } if (!matched) { @@ -365,8 +353,6 @@ function initMarkers() { prepareSignMarker(marker, item); } } - - } } From 428b3b937e86fb83361a5f4617a7a5a2f7206cd5 Mon Sep 17 00:00:00 2001 From: Michael Writhe Date: Thu, 14 Apr 2011 17:16:25 -0600 Subject: [PATCH 22/78] Issue brownan/master/323 implemented, icons --- web_assets/functions.js | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/web_assets/functions.js b/web_assets/functions.js index 3fb40d6..c89a95e 100644 --- a/web_assets/functions.js +++ b/web_assets/functions.js @@ -72,7 +72,7 @@ function createDropDown(title, items) { dropdownDiv.appendChild(d); d.appendChild(n) var textNode = document.createElement("text"); - textNode.innerHTML = item.label + "
"; + textNode.innerHTML = "" + item.label + "
"; d.appendChild(textNode); } } @@ -137,11 +137,20 @@ function drawMapControls() { var items = []; for (idx in signGroups) { - var item = signGroups[idx]; - items.push({"label": item.label, "checked": item.checked, + var signGroup = signGroups[idx]; + var iconURL = signGroup.icon; + if (!iconURL) { iconURL = 'signpost.png'; } + items.push({ + "label": signGroup.label, + "checked": signGroup.checked, + "icon": iconURL, "action": function(n, l, checked) { - jQuery.each(markerCollection[l], function(i,elem) {elem.setVisible(checked);}); - }}); + jQuery.each(markerCollection[l], function(i,elem) { + elem.setVisible(checked); + }); + //alert(signGroup.label); + } + }); } createDropDown("Signposts", items); } @@ -152,8 +161,8 @@ function drawMapControls() { var items = []; for (idx in regionGroups) { - var item = regionGroups[idx]; - items.push({"label": item.label, "checked": item.checked, + var regionGroup = regionGroups[idx]; + items.push({"label": regionGroup.label, "checked": regionGroup.checked, "action": function(n, l, checked) { jQuery.each(regionCollection[l], function(i,elem) { elem.setMap(checked ? map : null); // Thanks to LeastWeasel for this line! @@ -215,7 +224,7 @@ function initRegions() { var testfunc = regionGroup.match; var clickable = regionGroup.clickable var label = regionGroup.label; - + if(region.label) { var name = region.label } else { @@ -225,7 +234,7 @@ function initRegions() { if (region.closed) { var shape = new google.maps.Polygon({ - name: region.label, + name: name, clickable: clickable, geodesic: false, map: null, @@ -239,7 +248,7 @@ function initRegions() { }); } else { var shape = new google.maps.Polyline({ - name: region.label, + name: name, clickable: clickable, geodesic: false, map: null, @@ -282,6 +291,7 @@ function initMarkers() { for (i in signGroups) { markerCollection[signGroups[i].label] = []; } + for (i in markerData) { var item = markerData[i]; @@ -331,7 +341,7 @@ function initMarkers() { } } } - + if (!matched) { // is this signpost doesn't match any of the groups in config.js, add it automatically to the "__others__" group if (item.type == 'sign') { iconURL = 'signpost_icon.png';} @@ -353,6 +363,9 @@ function initMarkers() { prepareSignMarker(marker, item); } } + + + } } From 3f8b445f8e8b77a9872d953db6220f149da095fe Mon Sep 17 00:00:00 2001 From: Michael Writhe Date: Thu, 14 Apr 2011 17:25:03 -0600 Subject: [PATCH 23/78] corrected icons for signposts, regions and overlays dont have icons --- web_assets/functions.js | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/web_assets/functions.js b/web_assets/functions.js index c89a95e..09b0172 100644 --- a/web_assets/functions.js +++ b/web_assets/functions.js @@ -72,7 +72,12 @@ function createDropDown(title, items) { dropdownDiv.appendChild(d); d.appendChild(n) var textNode = document.createElement("text"); - textNode.innerHTML = "" + item.label + "
"; + if(item.icon) { + textNode.innerHTML = "" + item.label + "
"; + } else { + textNode.innerHTML = item.label + "
"; + } + d.appendChild(textNode); } } @@ -162,12 +167,15 @@ function drawMapControls() { var items = []; for (idx in regionGroups) { var regionGroup = regionGroups[idx]; - items.push({"label": regionGroup.label, "checked": regionGroup.checked, + items.push({ + "label": regionGroup.label, + "checked": regionGroup.checked, "action": function(n, l, checked) { - jQuery.each(regionCollection[l], function(i,elem) { - elem.setMap(checked ? map : null); // Thanks to LeastWeasel for this line! - }); - }}); + jQuery.each(regionCollection[l], function(i,elem) { + elem.setMap(checked ? map : null); // Thanks to LeastWeasel for this line! + }); + } + }); } createDropDown("Regions", items); } From 0e04becbe9d1cc0bec4bcb08615e3e44ae8197c9 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Thu, 14 Apr 2011 21:24:08 -0400 Subject: [PATCH 24/78] Fix missing path component in utils.py --- util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util.py b/util.py index 83f5383..7a0323d 100644 --- a/util.py +++ b/util.py @@ -39,7 +39,7 @@ def findGitVersion(): with open(os.path.join(this_dir,".git","HEAD")) as f: data = f.read().strip() if data.startswith("ref: "): - if not os.path.exists(os.path.join(this_dir,data[5:])): + if not os.path.exists(os.path.join(this_dir, ".git", data[5:])): return data with open(os.path.join(this_dir, ".git", data[5:])) as g: return g.read().strip() From af559f6b880d9fccac1ff34997c5038582f210d0 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Fri, 15 Apr 2011 09:02:39 -0700 Subject: [PATCH 25/78] bumped extension version for cave mode --- src/overviewer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/overviewer.h b/src/overviewer.h index 6eac848..db93a67 100644 --- a/src/overviewer.h +++ b/src/overviewer.h @@ -26,7 +26,7 @@ // increment this value if you've made a change to the c extesion // and want to force users to rebuild -#define OVERVIEWER_EXTENSION_VERSION 3 +#define OVERVIEWER_EXTENSION_VERSION 4 /* Python PIL, and numpy headers */ #include From 9cc01ddc218d633c363f8384c8cda3c14e89fbf2 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Fri, 15 Apr 2011 21:36:31 -0400 Subject: [PATCH 26/78] removed some blocks from solid_blocks, fixed overlays on snow, half-steps --- chunk.py | 2 +- src/rendermode-overlay.c | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/chunk.py b/chunk.py index dd06ffe..8ed85b8 100644 --- a/chunk.py +++ b/chunk.py @@ -120,7 +120,7 @@ transparent_blocks = set([0, 6, 8, 9, 18, 20, 37, 38, 39, 40, 44, 50, 51, 52, 53 # 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, 21, 22, 23, 24, 25, 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, 92]) + 61, 62, 67, 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]) diff --git a/src/rendermode-overlay.c b/src/rendermode-overlay.c index 2a15302..4029ae9 100644 --- a/src/rendermode-overlay.c +++ b/src/rendermode-overlay.c @@ -76,6 +76,13 @@ rendermode_overlay_draw(void *data, RenderState *state, PyObject *src, PyObject unsigned char r, g, b, a; PyObject *top_block_py, *block_py; + // exactly analogous to edge-line code for these special blocks + int increment=0; + if (state->block == 44) // half-step + increment=6; + else if (state->block == 78) // snow + increment=9; + /* clear the draw space -- set alpha to 0 within mask */ tint_with_mask(state->img, 255, 255, 255, 0, mask, state->imgx, state->imgy, 0, 0); @@ -114,8 +121,8 @@ rendermode_overlay_draw(void *data, RenderState *state, PyObject *src, PyObject /* do the overlay */ if (a > 0) { - alpha_over(state->img, self->white_color, self->facemask_top, state->imgx, state->imgy, 0, 0); - tint_with_mask(state->img, r, g, b, a, self->facemask_top, state->imgx, state->imgy, 0, 0); + alpha_over(state->img, self->white_color, self->facemask_top, state->imgx, state->imgy + increment, 0, 0); + tint_with_mask(state->img, r, g, b, a, self->facemask_top, state->imgx, state->imgy + increment, 0, 0); } } From ad358fa7fdb08f890b532a71239254f188f5964d Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Fri, 15 Apr 2011 21:44:59 -0400 Subject: [PATCH 27/78] fixed spawn mode for chunk tops --- src/rendermode-spawn.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/rendermode-spawn.c b/src/rendermode-spawn.c index ebbdc25..0d5138e 100644 --- a/src/rendermode-spawn.c +++ b/src/rendermode-spawn.c @@ -23,6 +23,7 @@ static void get_color(void *data, RenderState *state, RenderModeSpawn* self = (RenderModeSpawn *)data; int x = state->x, y = state->y, z = state->z; + int z_light = z + 1; unsigned char blocklight, skylight; PyObject *block_py; @@ -34,10 +35,6 @@ static void get_color(void *data, RenderState *state, /* default to no overlay, until told otherwise */ *a = 0; - /* if we're at the top, skip */ - if (z == 127) - return; - block_py = PyInt_FromLong(state->block); if (PySequence_Contains(self->nospawn_blocks, block_py)) { /* nothing can spawn on this */ @@ -46,8 +43,12 @@ static void get_color(void *data, RenderState *state, } Py_DECREF(block_py); - blocklight = getArrayByte3D(self->blocklight, x, y, z+1); - skylight = getArrayByte3D(self->skylight, x, y, z+1); + /* if we're at the top, use the top-most light instead */ + if (z_light == 128) + z_light--; + + blocklight = getArrayByte3D(self->blocklight, x, y, z_light); + skylight = getArrayByte3D(self->skylight, x, y, z_light); if (MAX(blocklight, skylight) <= 7) { /* hostile mobs spawn in daylight */ From 1ef6efab8d3e070c88da7a614e4094bd3305fed0 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Sat, 16 Apr 2011 13:11:37 +0200 Subject: [PATCH 28/78] Change _iterate_regionfiles to use glob instead of os.walk. The function gets simpler in this way With this you can fool overviewer to render the nether just poiting the "DIM-1" instead the world dir. (and you also need to copy the level.dat to the DIM-1 directory, because nether has not spawn) --- world.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/world.py b/world.py index b1b0ca7..7f7bab1 100644 --- a/world.py +++ b/world.py @@ -16,6 +16,7 @@ import functools import os import os.path +from glob import glob import multiprocessing import Queue import sys @@ -287,12 +288,10 @@ class World(object): p = f.split(".") yield (int(p[1]), int(p[2]), join(self.worlddir, 'region', f)) else: - for dirpath, dirnames, filenames in os.walk(os.path.join(self.worlddir, 'region')): - if not dirnames and filenames and "DIM-1" not in dirpath: - for f in filenames: - if f.startswith("r.") and f.endswith(".mcr"): - p = f.split(".") - yield (int(p[1]), int(p[2]), join(dirpath, f)) + for path in glob(os.path.join(self.worlddir, 'region') + "/r.*.*.mcr"): + dirpath, f = os.path.split(path) + p = f.split(".") + yield (int(p[1]), int(p[2]), join(dirpath, f)) def get_save_dir(): """Returns the path to the local saves directory From f30a5db2a185564ee77a7ffd2aa96b68f6f77a79 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sat, 16 Apr 2011 11:18:46 -0400 Subject: [PATCH 29/78] destination directory will now be created recursively, if needed --- quadtree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quadtree.py b/quadtree.py index d4018f6..51cb46e 100644 --- a/quadtree.py +++ b/quadtree.py @@ -69,7 +69,7 @@ class QuadtreeGen(object): # Make the destination dir if not os.path.exists(destdir): - os.mkdir(destdir) + os.makedirs(os.path.abspath(destdir)) if tiledir is None: tiledir = rendermode self.tiledir = tiledir From 558ebe0899efc305c86682dace8f4091b88a32b1 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sat, 16 Apr 2011 12:03:12 -0400 Subject: [PATCH 30/78] fixed for-loop scoping on createDropDown() closures --- web_assets/functions.js | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/web_assets/functions.js b/web_assets/functions.js index 09b0172..038f0c2 100644 --- a/web_assets/functions.js +++ b/web_assets/functions.js @@ -60,9 +60,11 @@ function createDropDown(title, items) { // give it a name $(n).data("label",item.label); - jQuery(n).click(function(e) { - item.action(idx, item.label, e.target.checked); - }); + jQuery(n).click((function(local_idx, local_item) { + return function(e) { + item.action(local_idx, local_item, e.target.checked); + }; + })(idx, item)); // if its checked, its gotta do something, do that here. if (item.checked) { @@ -149,11 +151,11 @@ function drawMapControls() { "label": signGroup.label, "checked": signGroup.checked, "icon": iconURL, - "action": function(n, l, checked) { - jQuery.each(markerCollection[l], function(i,elem) { + "action": function(n, item, checked) { + jQuery.each(markerCollection[item.label], function(i,elem) { elem.setVisible(checked); }); - //alert(signGroup.label); + //alert(item.label); } }); } @@ -170,8 +172,8 @@ function drawMapControls() { items.push({ "label": regionGroup.label, "checked": regionGroup.checked, - "action": function(n, l, checked) { - jQuery.each(regionCollection[l], function(i,elem) { + "action": function(n, item, checked) { + jQuery.each(regionCollection[item.label], function(i,elem) { elem.setMap(checked ? map : null); // Thanks to LeastWeasel for this line! }); } @@ -186,14 +188,14 @@ function drawMapControls() { var items = []; for (idx in overlayMapTypes) { var overlay = overlayMapTypes[idx]; - items.push({"label": overlay.name, "checked": false, - "action": function(i, l, checked) { + items.push({"label": overlay.name, "checked": false, "overlay": overlay, + "action": function(i, item, checked) { if (checked) { - map.overlayMapTypes.push(overlay); + map.overlayMapTypes.push(item.overlay); } else { var idx_to_delete = -1; map.overlayMapTypes.forEach(function(e, j) { - if (e == overlay) { idx_to_delete = j; } + if (e == item.overlay) { idx_to_delete = j; } }); if (idx_to_delete >= 0) { map.overlayMapTypes.removeAt(idx_to_delete); From 26b35906a41b86018bc54202feb776d19041cabf Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sat, 16 Apr 2011 19:20:21 -0400 Subject: [PATCH 31/78] fix for cave mode merge --- src/rendermode-cave.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rendermode-cave.c b/src/rendermode-cave.c index ae5b565..e51742c 100644 --- a/src/rendermode-cave.c +++ b/src/rendermode-cave.c @@ -219,7 +219,7 @@ rendermode_cave_draw(void *data, RenderState *state, PyObject *src, PyObject *ma 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, mask, state->imgx, state->imgy, 0, 0); + tint_with_mask(state->img, r, g, b, 255, mask, state->imgx, state->imgy, 0, 0); } From 05c4083b7e1d15ae79ab9de5adf8165b2ec28123 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sat, 16 Apr 2011 19:25:40 -0400 Subject: [PATCH 32/78] support for mixed png/jpg tilesets, and overlays with imgformat=jpg --- chunk.py | 4 ++++ config.js | 11 ++++++----- googlemap.py | 16 ++++++---------- quadtree.py | 10 +++++----- web_assets/functions.js | 9 +++++---- 5 files changed, 26 insertions(+), 24 deletions(-) diff --git a/chunk.py b/chunk.py index baf9efc..0fdce6c 100644 --- a/chunk.py +++ b/chunk.py @@ -129,6 +129,10 @@ fluid_blocks = set([8,9,10,11]) # (glass, half blocks) nospawn_blocks = set([20,44]) +# overlay rendermodes +# FIXME hook this into render_modes in setup.py, somehow +overlay_rendermodes = ['spawn'] + class ChunkCorrupt(Exception): pass diff --git a/config.js b/config.js index ed28985..8627c1e 100644 --- a/config.js +++ b/config.js @@ -1,6 +1,5 @@ var config = { - fileExt: '{imgformat}', tileSize: 384, defaultZoom: 2, maxZoom: {maxzoom}, @@ -59,15 +58,17 @@ var regionGroups = [ * the first one being the default. * * Required: - * label : string. Displayed on the control. - * path : string. Location of the rendered tiles. + * label : string. Displayed on the control. + * path : string. Location of the rendered tiles. * 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. + * imgformat : string. File extension used for these tiles. Defaults to png. + * overlay : bool. If true, this tile set will be treated like an overlay var mapTypeData=[ {'label': 'Unlit', 'path': 'tiles'}, // {'label': 'Day', 'path': 'lighting/tiles'}, -// {'label': 'Night', 'path': 'night/tiles'}, +// {'label': 'Night', 'path': 'night/tiles', 'imgformat': 'jpg'}, // {'label': 'Spawn', 'path': 'spawn/tiles', 'base': 'http://example.cdn.amazon.com/'}, // {'label': 'Overlay', 'path': 'overlay/tiles', 'overlay': true} ]; diff --git a/googlemap.py b/googlemap.py index dde8ad7..0f883d3 100644 --- a/googlemap.py +++ b/googlemap.py @@ -23,6 +23,7 @@ from time import strftime, gmtime import json import util +from chunk import overlay_rendermodes """ This module has routines related to generating a Google Maps-based @@ -72,12 +73,11 @@ class MapGen(object): 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") + if i.destdir != self.destdir or i.world != self.world: + raise ValueError("all the given quadtrees must have the same destdir and world") self.quadtrees = quadtrees @@ -85,24 +85,20 @@ class MapGen(object): """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)) config = config.replace("{spawn_coords}", json.dumps(list(self.world.spawn))) # create generated map type data, from given quadtrees - # FIXME hook this into render_modes in setup.py, somehow - overlay_types = ['spawn'] maptypedata = map(lambda q: {'label' : q.rendermode.capitalize(), 'path' : q.tiledir, - 'overlay' : q.rendermode in overlay_types}, + 'overlay' : q.rendermode in overlay_rendermodes, + 'imgformat' : q.imgformat}, self.quadtrees) config = config.replace("{maptypedata}", json.dumps(maptypedata)) @@ -114,7 +110,7 @@ class MapGen(object): 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)) + blank.save(os.path.join(tileDir, "blank."+quadtree.imgformat)) # copy web assets into destdir: mirror_dir(os.path.join(util.get_program_path(), "web_assets"), self.destdir) diff --git a/quadtree.py b/quadtree.py index 51cb46e..40773e9 100644 --- a/quadtree.py +++ b/quadtree.py @@ -60,12 +60,12 @@ class QuadtreeGen(object): """ assert(imgformat) self.imgformat = imgformat - self.optimizeimg = optimizeimg - - self.lighting = rendermode in ("lighting", "night", "spawn") - self.night = rendermode in ("night", "spawn") - self.spawn = rendermode in ("spawn",) + self.optimizeimg = optimizeimg self.rendermode = rendermode + + # force png renderformat if we're using an overlay mode + if rendermode in chunk.overlay_rendermodes: + self.imgformat = "png" # Make the destination dir if not os.path.exists(destdir): diff --git a/web_assets/functions.js b/web_assets/functions.js index 038f0c2..9c8b46a 100644 --- a/web_assets/functions.js +++ b/web_assets/functions.js @@ -532,7 +532,7 @@ function fromWorldToLatLng(x, z, y) return new google.maps.LatLng(lat, lng); } -function getTileUrlGenerator(path, path_base) { +function getTileUrlGenerator(path, path_base, path_ext) { return function(tile, zoom) { var url = path; var url_base = ( path_base ? path_base : '' ); @@ -547,7 +547,7 @@ function getTileUrlGenerator(path, path_base) { url += '/' + (x + 2 * y); } } - url = url + '.' + config.fileExt; + url = url + '.' + path_ext; if(config.cacheMinutes > 0) { var d = new Date(); url += '?c=' + Math.floor(d.getTime() / (1000 * 60 * config.cacheMinutes)); @@ -563,13 +563,14 @@ var mapTypeIds = []; var overlayMapTypes = []; for (idx in mapTypeData) { var view = mapTypeData[idx]; + var imgformat = view.imgformat ? view.imgformat : 'png'; MCMapOptions[view.label] = { - getTileUrl: getTileUrlGenerator(view.path, view.base), + getTileUrl: getTileUrlGenerator(view.path, view.base, imgformat), tileSize: new google.maps.Size(config.tileSize, config.tileSize), maxZoom: config.maxZoom, minZoom: 0, - isPng: !(config.fileExt.match(/^png$/i) == null) + isPng: !(imgformat.match(/^png$/i) == null) }; MCMapType[view.label] = new google.maps.ImageMapType(MCMapOptions[view.label]); From 5294b88df9463cc8b8c46f1093d081c5332a43af Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sat, 16 Apr 2011 19:33:21 -0400 Subject: [PATCH 33/78] more fixes for spawn overlay at z == 127 --- src/rendermode-spawn.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/rendermode-spawn.c b/src/rendermode-spawn.c index 0d5138e..ff73780 100644 --- a/src/rendermode-spawn.c +++ b/src/rendermode-spawn.c @@ -43,12 +43,14 @@ static void get_color(void *data, RenderState *state, } Py_DECREF(block_py); - /* if we're at the top, use the top-most light instead */ - if (z_light == 128) - z_light--; + blocklight = getArrayByte3D(self->blocklight, x, y, MAX(127, z_light)); - blocklight = getArrayByte3D(self->blocklight, x, y, z_light); - skylight = getArrayByte3D(self->skylight, x, y, z_light); + /* if we're at the top, force 15 (brightest!) skylight */ + if (z_light == 128) { + skylight = 15; + } else { + skylight = getArrayByte3D(self->skylight, x, y, z_light); + } if (MAX(blocklight, skylight) <= 7) { /* hostile mobs spawn in daylight */ From 5c3b3be41861d08476d3f2261e03cba1dcf42e94 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sat, 16 Apr 2011 20:08:38 -0400 Subject: [PATCH 34/78] basic rendermode inheritance introspection (no more hacky overlay list) --- chunk.py | 4 -- googlemap.py | 4 +- quadtree.py | 3 +- src/main.c | 10 +++++ src/rendermode-cave.c | 1 + src/rendermode-lighting.c | 1 + src/rendermode-night.c | 1 + src/rendermode-normal.c | 1 + src/rendermode-overlay.c | 1 + src/rendermode-spawn.c | 1 + src/rendermodes.c | 84 ++++++++++++++++++++++++++++++++++++++- src/rendermodes.h | 10 ++++- 12 files changed, 111 insertions(+), 10 deletions(-) diff --git a/chunk.py b/chunk.py index 0fdce6c..baf9efc 100644 --- a/chunk.py +++ b/chunk.py @@ -129,10 +129,6 @@ fluid_blocks = set([8,9,10,11]) # (glass, half blocks) nospawn_blocks = set([20,44]) -# overlay rendermodes -# FIXME hook this into render_modes in setup.py, somehow -overlay_rendermodes = ['spawn'] - class ChunkCorrupt(Exception): pass diff --git a/googlemap.py b/googlemap.py index 0f883d3..b8416b5 100644 --- a/googlemap.py +++ b/googlemap.py @@ -23,7 +23,7 @@ from time import strftime, gmtime import json import util -from chunk import overlay_rendermodes +from c_overviewer import get_render_mode_inheritance """ This module has routines related to generating a Google Maps-based @@ -97,7 +97,7 @@ class MapGen(object): # create generated map type data, from given quadtrees maptypedata = map(lambda q: {'label' : q.rendermode.capitalize(), 'path' : q.tiledir, - 'overlay' : q.rendermode in overlay_rendermodes, + 'overlay' : 'overlay' in get_render_mode_inheritance(q.rendermode), 'imgformat' : q.imgformat}, self.quadtrees) config = config.replace("{maptypedata}", json.dumps(maptypedata)) diff --git a/quadtree.py b/quadtree.py index 40773e9..4b2cc68 100644 --- a/quadtree.py +++ b/quadtree.py @@ -34,6 +34,7 @@ from PIL import Image import nbt import chunk +from c_overviewer import get_render_mode_inheritance from optimizeimages import optimize_image import composite @@ -64,7 +65,7 @@ class QuadtreeGen(object): self.rendermode = rendermode # force png renderformat if we're using an overlay mode - if rendermode in chunk.overlay_rendermodes: + if 'overlay' in get_render_mode_inheritance(rendermode): self.imgformat = "png" # Make the destination dir diff --git a/src/main.c b/src/main.c index ddbe0af..4de7eec 100644 --- a/src/main.c +++ b/src/main.c @@ -25,14 +25,24 @@ PyObject *get_extension_version(PyObject *self, PyObject *args) { static PyMethodDef COverviewerMethods[] = { {"alpha_over", alpha_over_wrap, METH_VARARGS, "alpha over composite function"}, + {"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_parent", get_render_mode_parent, METH_VARARGS, + "returns parent 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"}, + {"extension_version", get_extension_version, METH_VARARGS, "Returns the extension version"}, + {NULL, NULL, 0, NULL} /* Sentinel */ }; diff --git a/src/rendermode-cave.c b/src/rendermode-cave.c index e51742c..f8334b2 100644 --- a/src/rendermode-cave.c +++ b/src/rendermode-cave.c @@ -225,6 +225,7 @@ rendermode_cave_draw(void *data, RenderState *state, PyObject *src, PyObject *ma RenderModeInterface rendermode_cave = { "cave", "render only caves in normal mode", + &rendermode_normal, sizeof(RenderModeCave), rendermode_cave_start, rendermode_cave_finish, diff --git a/src/rendermode-lighting.c b/src/rendermode-lighting.c index 628e5c4..83b38d3 100644 --- a/src/rendermode-lighting.c +++ b/src/rendermode-lighting.c @@ -229,6 +229,7 @@ rendermode_lighting_draw(void *data, RenderState *state, PyObject *src, PyObject RenderModeInterface rendermode_lighting = { "lighting", "draw shadows from the lighting data", + &rendermode_normal, sizeof(RenderModeLighting), rendermode_lighting_start, rendermode_lighting_finish, diff --git a/src/rendermode-night.c b/src/rendermode-night.c index 1e54f05..46ca7c2 100644 --- a/src/rendermode-night.c +++ b/src/rendermode-night.c @@ -61,6 +61,7 @@ rendermode_night_draw(void *data, RenderState *state, PyObject *src, PyObject *m RenderModeInterface rendermode_night = { "night", "like \"lighting\", except at night", + &rendermode_lighting, sizeof(RenderModeNight), rendermode_night_start, rendermode_night_finish, diff --git a/src/rendermode-normal.c b/src/rendermode-normal.c index 983050c..9f139a3 100644 --- a/src/rendermode-normal.c +++ b/src/rendermode-normal.c @@ -221,6 +221,7 @@ rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject * RenderModeInterface rendermode_normal = { "normal", "nothing special, just render the blocks", + NULL, sizeof(RenderModeNormal), rendermode_normal_start, rendermode_normal_finish, diff --git a/src/rendermode-overlay.c b/src/rendermode-overlay.c index 4029ae9..fb4e765 100644 --- a/src/rendermode-overlay.c +++ b/src/rendermode-overlay.c @@ -128,6 +128,7 @@ rendermode_overlay_draw(void *data, RenderState *state, PyObject *src, PyObject RenderModeInterface rendermode_overlay = { "overlay", "base rendermode for informational overlays", + NULL, sizeof(RenderModeOverlay), rendermode_overlay_start, rendermode_overlay_finish, diff --git a/src/rendermode-spawn.c b/src/rendermode-spawn.c index ff73780..edd9c44 100644 --- a/src/rendermode-spawn.c +++ b/src/rendermode-spawn.c @@ -109,6 +109,7 @@ rendermode_spawn_draw(void *data, RenderState *state, PyObject *src, PyObject *m RenderModeInterface rendermode_spawn = { "spawn", "draws a red overlay where monsters can spawn at night", + &rendermode_overlay, sizeof(RenderModeSpawn), rendermode_spawn_start, rendermode_spawn_finish, diff --git a/src/rendermodes.c b/src/rendermodes.c index 08ac140..5ee7d54 100644 --- a/src/rendermodes.c +++ b/src/rendermodes.c @@ -98,5 +98,87 @@ PyObject *get_render_mode_info(PyObject *self, PyObject *args) { } Py_DECREF(info); - Py_RETURN_NONE; + return PyErr_Format(PyExc_ValueError, "invalid rendermode: \"%s\"", rendermode); +} + +/* bindings -- get parent's name */ +PyObject *get_render_mode_parent(PyObject *self, PyObject *args) { + const char *rendermode; + unsigned int i; + if (!PyArg_ParseTuple(args, "s", &rendermode)) + return NULL; + + for (i = 0; render_modes[i] != NULL; i++) { + if (strcmp(render_modes[i]->name, rendermode) == 0) { + if (render_modes[i]->parent) { + /* has parent */ + return PyString_FromString(render_modes[i]->parent->name); + } else { + /* no parent */ + Py_RETURN_NONE; + } + } + } + + 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; + if (!PyArg_ParseTuple(args, "s", &rendermode)) + return NULL; + + parents = PyList_New(0); + if (!parents) + return NULL; + + RenderModeInterface *iface = NULL; + 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; + 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); + } + } + + return children; } diff --git a/src/rendermodes.h b/src/rendermodes.h index 980968c..fd0b479 100644 --- a/src/rendermodes.h +++ b/src/rendermodes.h @@ -38,12 +38,15 @@ #include /* rendermode interface */ -typedef struct { +typedef struct _RenderModeInterface RenderModeInterface; +struct _RenderModeInterface { /* the name of this mode */ const char* name; /* the short description of this render mode */ const char* description; + /* the rendermode this is derived from, or NULL */ + RenderModeInterface *parent; /* the size of the local storage for this rendermode */ unsigned int data_size; @@ -54,13 +57,16 @@ typedef struct { int (*occluded)(void *, RenderState *); /* last two arguments are img and mask, from texture lookup */ void (*draw)(void *, RenderState *, PyObject *, PyObject *); -} RenderModeInterface; +}; /* figures out the render mode to use from the given ChunkRenderer */ RenderModeInterface *get_render_mode(RenderState *state); /* python bindings */ PyObject *get_render_modes(PyObject *self, PyObject *args); PyObject *get_render_mode_info(PyObject *self, PyObject *args); +PyObject *get_render_mode_parent(PyObject *self, PyObject *args); +PyObject *get_render_mode_inheritance(PyObject *self, PyObject *args); +PyObject *get_render_mode_children(PyObject *self, PyObject *args); /* individual rendermode interface declarations follow */ From ed5f3eaad400763753923386ee7f5f864fae0bbd Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Sun, 17 Apr 2011 14:10:27 -0400 Subject: [PATCH 35/78] Stronger support for setting a background color Works by setting "bg_color='#rrggbb'" in settings.py. Works for both png and jpg imgformats --- config.js | 2 +- configParser.py | 3 ++- googlemap.py | 12 ++++++++---- overviewer.py | 7 +++++-- quadtree.py | 7 ++++--- 5 files changed, 20 insertions(+), 11 deletions(-) diff --git a/config.js b/config.js index 78dfd7d..3ec0a84 100644 --- a/config.js +++ b/config.js @@ -8,7 +8,7 @@ //center: [0,0,0], center: {spawn_coords}, cacheMinutes: 0, // Change this to have browsers automatically request new images every x minutes - bg_color: '#1A1A1A', + bg_color: '{bg_color}', // You can set this in settings.py debug: false }; diff --git a/configParser.py b/configParser.py index 88925d7..5b275f0 100644 --- a/configParser.py +++ b/configParser.py @@ -4,7 +4,8 @@ import os.path import logging class OptionsResults(object): - pass + def get(self, *args): + return self.__dict__.get(*args) class ConfigOptionParser(object): def __init__(self, **kwargs): diff --git a/googlemap.py b/googlemap.py index f6f271e..630101a 100644 --- a/googlemap.py +++ b/googlemap.py @@ -59,14 +59,15 @@ def mirror_dir(src, dst, entities=None): # if this stills throws an error, let it propagate up class MapGen(object): - def __init__(self, quadtrees, skipjs=False, web_assets_hook=None): + def __init__(self, quadtrees, configInfo): """Generates a Google Maps interface for the given list of quadtrees. All of the quadtrees must have the same destdir, image format, and world. Note:tiledir for each quadtree should be unique. By default the tiledir is determined by the rendermode""" - self.skipjs = skipjs - self.web_assets_hook = web_assets_hook + self.skipjs = configInfo.get('skipjs', None) + self.web_assets_hook = configInfo.get('web_assets_hook', None) + self.bg_color = configInfo.get('bg_color') if not len(quadtrees) > 0: raise ValueError("there must be at least one quadtree to work on") @@ -96,6 +97,8 @@ class MapGen(object): config = config.replace("{spawn_coords}", json.dumps(list(self.world.spawn))) + + config = config.replace("{bg_color}", self.bg_color) # create generated map type data, from given quadtrees maptypedata = map(lambda q: {'label' : q.rendermode.capitalize(), @@ -105,9 +108,10 @@ class MapGen(object): with open(os.path.join(self.destdir, "config.js"), 'w') as output: output.write(config) + bgcolor = (int(self.bg_color[1:3],16), int(self.bg_color[3:5],16), int(self.bg_color[5:7],16), 0) + blank = Image.new("RGBA", (1,1), bgcolor) # 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)) diff --git a/overviewer.py b/overviewer.py index 6e755bd..925d241 100755 --- a/overviewer.py +++ b/overviewer.py @@ -97,6 +97,7 @@ def main(): parser.add_option("--rendermodes", dest="rendermode", help="Specifies the render types, separated by commas. Use --list-rendermodes to list them all.", type="choice", choices=avail_rendermodes, 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.", commandLineOnly=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.", configFileOnly=True ) + parser.add_option("--bg_color", dest="bg_color", help="Configures the background color for the GoogleMap output. Specify in #RRGGBB format", configFileOnly=True, type="string", default="#1A1A1A") 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%", configFileOnly=True) parser.add_option("--web-assets-hook", dest="web_assets_hook", help="If provided, run this function after the web assets have been copied, but before actual tile rendering begins. It should accept a QuadtreeGen object as its only argument.", action="store", metavar="SCRIPT", type="function", configFileOnly=True) parser.add_option("-q", "--quiet", dest="quiet", action="count", default=0, help="Print less output. You can specify this option multiple times.") @@ -214,10 +215,12 @@ def main(): logging.info("Rending 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 # TODO chunklist q = [] - qtree_args = {'depth' : options.zoom, 'imgformat' : imgformat, 'optimizeimg' : optimizeimg} + qtree_args = {'depth' : options.zoom, 'imgformat' : imgformat, 'optimizeimg' : optimizeimg, 'bgcolor':bgcolor} for rendermode in options.rendermode: if rendermode == 'normal': qtree = quadtree.QuadtreeGen(w, destdir, rendermode=rendermode, tiledir='tiles', **qtree_args) @@ -229,7 +232,7 @@ def main(): r = rendernode.RenderNode(q) # write out the map and web assets - m = googlemap.MapGen(q, skipjs=options.skipjs, web_assets_hook=options.web_assets_hook) + m = googlemap.MapGen(q, configInfo=options) m.go(options.procs) # render the tiles! diff --git a/quadtree.py b/quadtree.py index 51cb46e..48d816f 100644 --- a/quadtree.py +++ b/quadtree.py @@ -48,7 +48,7 @@ def iterate_base4(d): return itertools.product(xrange(4), repeat=d) class QuadtreeGen(object): - def __init__(self, worldobj, destdir, depth=None, tiledir=None, imgformat=None, optimizeimg=None, rendermode="normal"): + def __init__(self, worldobj, destdir, bgcolor, depth=None, tiledir=None, imgformat=None, optimizeimg=None, rendermode="normal"): """Generates a quadtree from the world given into the given dest directory @@ -61,6 +61,7 @@ class QuadtreeGen(object): assert(imgformat) self.imgformat = imgformat self.optimizeimg = optimizeimg + self.bgcolor = bgcolor self.lighting = rendermode in ("lighting", "night", "spawn") self.night = rendermode in ("night", "spawn") @@ -320,7 +321,7 @@ class QuadtreeGen(object): #logging.debug("writing out innertile {0}".format(imgpath)) # Create the actual image now - img = Image.new("RGBA", (384, 384), (38,92,255,0)) + img = Image.new("RGBA", (384, 384), self.bgcolor) # we'll use paste (NOT alpha_over) for quadtree generation because # this is just straight image stitching, not alpha blending @@ -442,7 +443,7 @@ class QuadtreeGen(object): #logging.debug("writing out worldtile {0}".format(imgpath)) # Compile this image - tileimg = Image.new("RGBA", (width, height), (38,92,255,0)) + tileimg = Image.new("RGBA", (width, height), self.bgcolor) world = self.world rendermode = self.rendermode From 45dcca82bbf9af1fc2cd5cf8234cf37671a20033 Mon Sep 17 00:00:00 2001 From: Ryan Finnie Date: Sun, 17 Apr 2011 22:38:29 -0700 Subject: [PATCH 36/78] Add a Minecraft-friendly coordinates system * Add x/y/z query arguments to specify MC world coordinates. If world coordinates are specified, display a POI icon indicating where the coordinates specified are. Gmaps-style "lat" and "lng" are still accepted, and will take precedence over x/y/z. * Expand functionality of the "zoom" query argument. "max" specifies the maximum zoom, and negative numbers are steps out from max. Gmaps-style zoom is still supported. * Change the URL current position area to use x/y/z arguments. Displayed zoom uses the new zoom logic. --- web_assets/functions.js | 94 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 5 deletions(-) diff --git a/web_assets/functions.js b/web_assets/functions.js index 96742af..f94568a 100644 --- a/web_assets/functions.js +++ b/web_assets/functions.js @@ -178,6 +178,20 @@ function initMarkers() { continue; } + if (item.type == 'querypos') { + // Set on page load if MC x/y/z coords are given in the query string + + iconURL = 'http://google-maps-icons.googlecode.com/files/regroup.png'; + var converted = fromWorldToLatLng(item.x, item.y, item.z); + var marker = new google.maps.Marker({position: converted, + map: map, + title: jQuery.trim(item.msg), + icon: iconURL + }); + + continue; + } + var matched = false; for (idx in signGroups) { var signGroup = signGroups[idx]; @@ -240,10 +254,19 @@ function initMarkers() { function makeLink() { + var displayZoom = map.getZoom(); + if (displayZoom == config.maxZoom) { + displayZoom = "max"; + } else { + displayZoom -= config.maxZoom; + } + var xyz; + var xyz = fromLatLngToWorld(map.getCenter().lat(), map.getCenter().lng()); var a=location.href.substring(0,location.href.lastIndexOf(location.search)) - + "?lat=" + map.getCenter().lat().toFixed(6) - + "&lng=" + map.getCenter().lng().toFixed(6) - + "&zoom=" + map.getZoom(); + + "?x=" + Math.floor(xyz.x) + + "&y=" + Math.floor(xyz.y) + + "&z=" + Math.floor(xyz.z) + + "&zoom=" + displayZoom; document.getElementById("link").innerHTML = a; } @@ -254,6 +277,11 @@ function initialize() { var lat = 0.5; var lng = 0.5; var zoom = config.defaultZoom; + var hasquerypos = false; + var queryx = 0; + var queryy = 64; + var queryz = 0; + var mapcenter; var pairs = query.split("&"); for (var i=0; i Date: Mon, 18 Apr 2011 11:03:29 -0400 Subject: [PATCH 37/78] windows build fixes --- src/rendermodes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rendermodes.c b/src/rendermodes.c index 5ee7d54..43658e1 100644 --- a/src/rendermodes.c +++ b/src/rendermodes.c @@ -128,6 +128,7 @@ PyObject *get_render_mode_inheritance(PyObject *self, PyObject *args) { const char *rendermode; PyObject *parents; unsigned int i; + RenderModeInterface *iface = NULL; if (!PyArg_ParseTuple(args, "s", &rendermode)) return NULL; @@ -135,7 +136,6 @@ PyObject *get_render_mode_inheritance(PyObject *self, PyObject *args) { if (!parents) return NULL; - RenderModeInterface *iface = NULL; for (i = 0; render_modes[i] != NULL; i++) { if (strcmp(render_modes[i]->name, rendermode) == 0) { iface = render_modes[i]; From 5f6ceebc8156aec7eb9a8e5de0ae5d7f84687af1 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Mon, 18 Apr 2011 11:02:39 -0700 Subject: [PATCH 38/78] fixed MIN/MAX mixup that prevented spawn overlay from working --- src/rendermode-spawn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rendermode-spawn.c b/src/rendermode-spawn.c index edd9c44..498ed17 100644 --- a/src/rendermode-spawn.c +++ b/src/rendermode-spawn.c @@ -43,7 +43,7 @@ static void get_color(void *data, RenderState *state, } Py_DECREF(block_py); - blocklight = getArrayByte3D(self->blocklight, x, y, MAX(127, z_light)); + blocklight = getArrayByte3D(self->blocklight, x, y, MIN(127, z_light)); /* if we're at the top, force 15 (brightest!) skylight */ if (z_light == 128) { From 2d25d74bd774fedbb86da2c1d2a3f92b0bd4ba8b Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Mon, 18 Apr 2011 20:16:06 -0400 Subject: [PATCH 39/78] moved quadtree preprocessing out of RenderNode, fixes issue #326 --- overviewer.py | 7 ++++++- rendernode.py | 1 - 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/overviewer.py b/overviewer.py index 925d241..115644f 100755 --- a/overviewer.py +++ b/overviewer.py @@ -227,8 +227,12 @@ def main(): else: qtree = quadtree.QuadtreeGen(w, destdir, rendermode=rendermode, **qtree_args) q.append(qtree) + + # do quadtree-level preprocessing + for qtree in q: + qtree.go(options.procs) - #create the distributed render + # create the distributed render r = rendernode.RenderNode(q) # write out the map and web assets @@ -238,6 +242,7 @@ def main(): # render the tiles! r.go(options.procs) + # finish up the map m.finalize() diff --git a/rendernode.py b/rendernode.py index d762b73..9dce5cc 100644 --- a/rendernode.py +++ b/rendernode.py @@ -149,7 +149,6 @@ class RenderNode(object): total += 4**q.p if q.p > max_p: max_p = q.p - q.go(procs) self.max_p = max_p # Render the highest level of tiles from the chunks results = collections.deque() From be230000503737d3fd3fabaa69018b31271f644c Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Thu, 21 Apr 2011 00:49:19 +0200 Subject: [PATCH 40/78] Add the detector and powered rails to textures.py --- textures.py | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/textures.py b/textures.py index e3e714c..8a91c79 100644 --- a/textures.py +++ b/textures.py @@ -938,11 +938,27 @@ def generate_special_texture(blockID, data): return (img.convert("RGB"), img.split()[3]) - if blockID == 66: # minetrack: - - raw_straight = terrain_images[128] - raw_corner = terrain_images[112] + if blockID in (27, 28, 66): # minetrack: + if blockID == 27: # powered rail + if data & 0x8 == 0: # unpowered + raw_straight = terrain_images[163] + raw_corner = terrain_images[112] # they don't exist but make the code + # much simplier + elif data & 0x8 == 0x8: # powered + raw_straight = terrain_images[179] + raw_corner = terrain_images[112] # leave corners for code simplicity + # filter the 'powered' bit + data = data & 0x7 + + elif blockID == 28: # detector rail + raw_straight = terrain_images[195] + raw_corner = terrain_images[112] # leave corners for code simplicity + + elif blockID == 66: # normal rail + raw_straight = terrain_images[128] + raw_corner = terrain_images[112] + ## use transform_image to scale and shear if data == 0: track = transform_image(raw_straight, blockID) @@ -1215,8 +1231,9 @@ def getBiomeData(worlddir, chunkX, chunkY): # (when adding new blocks here and in generate_special_textures, # please, if possible, keep the ascending order of blockid value) -special_blocks = set([2, 9, 17, 18, 23, 35, 43, 44, 50, 51, 53, 55, 58, 59, \ - 61, 62, 64, 65, 66, 67, 71, 75, 76, 85, 86, 91, 92]) +special_blocks = set([ 2, 9, 17, 18, 23, 27, 28, 35, 43, 44, 50, 51, 53, + 55, 58, 59, 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 # possible values for ancillary data that it might have. @@ -1226,6 +1243,8 @@ special_map = {} special_map[9] = range(32) # water: spring,flowing, waterfall, and others (unknown) ancildata values. special_map[17] = range(4) # wood: normal, birch and pine special_map[23] = range(6) # dispensers, orientation +special_map[27] = range(14) # powered rail, orientation/slope and powered/unpowered +special_map[28] = range(6) # detector rail, orientation/slope special_map[35] = range(16) # wool, colored and white special_map[43] = range(4) # stone, sandstone, wooden and cobblestone double-slab special_map[44] = range(4) # stone, sandstone, wooden and cobblestone slab From 3bad62f0af4d1b1604b8ac413b1d05eafefec2d7 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Thu, 21 Apr 2011 00:53:56 +0200 Subject: [PATCH 41/78] Add the new rail blocks to the transparent blocks list. --- chunk.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/chunk.py b/chunk.py index baf9efc..59ccae0 100644 --- a/chunk.py +++ b/chunk.py @@ -114,8 +114,9 @@ def get_tileentity_data(level): return data # This set holds blocks ids that can be seen through, for occlusion calculations -transparent_blocks = set([0, 6, 8, 9, 18, 20, 37, 38, 39, 40, 44, 50, 51, 52, 53, 55, - 59, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 79, 81, 83, 85, 92]) +transparent_blocks = set([ 0, 6, 8, 9, 18, 20, 27, 28, 37, 38, 39, 40, 44, 50, + 51, 52, 53, 55, 59, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 74, 75, 76, 77, 78, 79, 81, 83, 85, 92]) # 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, 21, 22, From 5a70c4686cf73e9b5c4c01552667114ec3093999 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Thu, 21 Apr 2011 01:25:36 +0200 Subject: [PATCH 42/78] Add saplings to generate_special_textures function. Also, remove all the torches from the _build_blocks. --- textures.py | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/textures.py b/textures.py index 8a91c79..850185c 100644 --- a/textures.py +++ b/textures.py @@ -226,8 +226,7 @@ def _build_block(top, side, blockID=None): ## special case for non-block things # TODO once torches are handled by generate_special_texture, remove # them from this list - if blockID in (37,38,6,39,40,50,83,75,76): ## flowers, sapling, mushrooms, regular torch, reeds, - # redstone torch on, redstone torch off + if blockID in (37,38,6,39,40,83): ## flowers, sapling, mushrooms, reeds # # instead of pasting these blocks at the cube edges, place them in the middle: # and omit the top @@ -348,7 +347,7 @@ def _build_blockimages(): # texture array (terrain_images), which comes from terrain.png's cells, left to right top to # bottom. # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - topids = [ -1, 1, 0, 2, 16, 4, 15, 17,205,205,237,237, 18, 19, 32, 33, + topids = [ -1, 1, 0, 2, 16, 4, -1, 17,205,205,237,237, 18, 19, 32, 33, # 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 34, -1, 52, 48, 49,160,144, -1,176, 74, -1, -1, -1, -1, -1, -1, # Cloths are left out, sandstone (it has top, side, and bottom wich is ignored here), note block # 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 @@ -365,7 +364,7 @@ def _build_blockimages(): # And side textures of all block types # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - sideids = [ -1, 1, 3, 2, 16, 4, 15, 17,205,205,237,237, 18, 19, 32, 33, + sideids = [ -1, 1, 3, 2, 16, 4, -1, 17,205,205,237,237, 18, 19, 32, 33, # 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 34, -1, 52, 48, 49,160,144, -1,192, 74, -1, -1,- 1, -1, -1, -1, # 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 @@ -438,6 +437,23 @@ def generate_special_texture(blockID, data): return (img.convert("RGB"), img.split()[3]) + if blockID == 6: # saplings + if data == 1: # spruce sapling + toptexture = terrain_images[64] + sidetexture = terrain_images[64] + + if data == 2: # birch sapling + toptexture = terrain_images[80] + sidetexture = terrain_images[80] + + else: # usual and future saplings + toptexture = terrain_images[15] + sidetexture = terrain_images[15] + + img = _build_block(toptexture, sidetexture, blockID) + return (img.convert("RGB"),img.split()[3]) + + if blockID == 9: # spring water, flowing water and waterfall water watertexture = _load_image("water.png") @@ -1231,15 +1247,16 @@ def getBiomeData(worlddir, chunkX, chunkY): # (when adding new blocks here and in generate_special_textures, # please, if possible, keep the ascending order of blockid value) -special_blocks = set([ 2, 9, 17, 18, 23, 27, 28, 35, 43, 44, 50, 51, 53, - 55, 58, 59, 61, 62, 64, 65, 66, 67, 71, 75, 76, 85, - 86, 91, 92]) +special_blocks = set([ 2, 6, 9, 17, 18, 23, 27, 28, 35, 43, 44, 50, 51, + 53, 55, 58, 59, 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 # possible values for ancillary data that it might have. special_map = {} +special_map[6] = range(4) # saplings: usual, spruce, birch and future ones (rendered as usual saplings) special_map[9] = range(32) # water: spring,flowing, waterfall, and others (unknown) ancildata values. special_map[17] = range(4) # wood: normal, birch and pine special_map[23] = range(6) # dispensers, orientation From b513977a794c58d5fde3a9f2204169190c4bfee2 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Thu, 21 Apr 2011 01:28:14 +0200 Subject: [PATCH 43/78] Fix textures for saplings. --- textures.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/textures.py b/textures.py index 850185c..ac214b5 100644 --- a/textures.py +++ b/textures.py @@ -439,12 +439,12 @@ def generate_special_texture(blockID, data): if blockID == 6: # saplings if data == 1: # spruce sapling - toptexture = terrain_images[64] - sidetexture = terrain_images[64] + toptexture = terrain_images[63] + sidetexture = terrain_images[63] if data == 2: # birch sapling - toptexture = terrain_images[80] - sidetexture = terrain_images[80] + toptexture = terrain_images[79] + sidetexture = terrain_images[79] else: # usual and future saplings toptexture = terrain_images[15] From eea97d1b1c3a5f793f18f5248450456e22406a36 Mon Sep 17 00:00:00 2001 From: Alex Headley Date: Fri, 22 Apr 2011 11:11:14 -0400 Subject: [PATCH 44/78] added per-rendermode bg_color setting --- config.js | 1 - googlemap.py | 3 ++- web_assets/functions.js | 16 +++++++++++----- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/config.js b/config.js index 41ee9e4..6ccd3ee 100644 --- a/config.js +++ b/config.js @@ -7,7 +7,6 @@ //center: [0,0,0], center: {spawn_coords}, cacheMinutes: 0, // Change this to have browsers automatically request new images every x minutes - bg_color: '{bg_color}', // You can set this in settings.py debug: false }; diff --git a/googlemap.py b/googlemap.py index 9e04b22..868297c 100644 --- a/googlemap.py +++ b/googlemap.py @@ -95,11 +95,12 @@ class MapGen(object): config = config.replace("{spawn_coords}", json.dumps(list(self.world.spawn))) - config = config.replace("{bg_color}", self.bg_color) + #config = config.replace("{bg_color}", self.bg_color) # create generated map type data, from given quadtrees maptypedata = map(lambda q: {'label' : q.rendermode.capitalize(), 'path' : q.tiledir, + 'bg_color': self.bg_color, 'overlay' : 'overlay' in get_render_mode_inheritance(q.rendermode), 'imgformat' : q.imgformat}, self.quadtrees) diff --git a/web_assets/functions.js b/web_assets/functions.js index b8ace5e..639970a 100644 --- a/web_assets/functions.js +++ b/web_assets/functions.js @@ -477,7 +477,6 @@ function initialize() { }, mapTypeId: mapTypeIdDefault, streetViewControl: false, - backgroundColor: config.bg_color, }; map = new google.maps.Map(document.getElementById('mcmap'), mapOptions); @@ -501,9 +500,6 @@ function initialize() { map.mapTypes.set('mcmap' + MCMapType[idx].name, MCMapType[idx]); } - // We can now set the map to use the 'coordinate' map type - map.setMapTypeId(mapTypeIdDefault); - // initialize the markers and regions initMarkers(); initRegions(); @@ -518,7 +514,17 @@ function initialize() { google.maps.event.addListener(map, 'center_changed', function() { makeLink(); }); - + google.maps.event.addListener(map, 'maptypeid_changed', function() { + var newType = map.getMapTypeId(); + for(i in mapTypeData) { + if( 'mcmap' + mapTypeData[i].label == newType ) { + $('#mcmap').css('background-color', mapTypeData[i].bg_color); + break; + } + } + }); + // We can now set the map to use the 'coordinate' map type + map.setMapTypeId(mapTypeIdDefault); } From fa49aff4b0097711de4217dbd3cf080e9ee432f1 Mon Sep 17 00:00:00 2001 From: Alex Headley Date: Fri, 22 Apr 2011 11:19:02 -0400 Subject: [PATCH 45/78] added minzoom config.js setting --- config.js | 1 + googlemap.py | 2 ++ web_assets/functions.js | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/config.js b/config.js index 6ccd3ee..839d724 100644 --- a/config.js +++ b/config.js @@ -2,6 +2,7 @@ var config = { tileSize: 384, defaultZoom: 2, + minZoom: {minzoom}, maxZoom: {maxzoom}, // center on this point, in world coordinates, ex: //center: [0,0,0], diff --git a/googlemap.py b/googlemap.py index 868297c..25b5c70 100644 --- a/googlemap.py +++ b/googlemap.py @@ -89,6 +89,8 @@ class MapGen(object): configpath = os.path.join(util.get_program_path(), "config.js") config = open(configpath, 'r').read() + config = config.replace( + "{minzoom}", str(0)) config = config.replace( "{maxzoom}", str(zoomlevel)) diff --git a/web_assets/functions.js b/web_assets/functions.js index 639970a..9fd7d0b 100644 --- a/web_assets/functions.js +++ b/web_assets/functions.js @@ -659,7 +659,7 @@ for (idx in mapTypeData) { getTileUrl: getTileUrlGenerator(view.path, view.base, imgformat), tileSize: new google.maps.Size(config.tileSize, config.tileSize), maxZoom: config.maxZoom, - minZoom: 0, + minZoom: config.minZoom, isPng: !(imgformat.match(/^png$/i) == null) }; From f9f98960a056ab69278b94aeca64ccd13b9bff7a Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Fri, 22 Apr 2011 23:24:57 -0400 Subject: [PATCH 46/78] Don't let a missing markers.js or region.js foul up everything Fixes #330 --- web_assets/functions.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web_assets/functions.js b/web_assets/functions.js index 9fd7d0b..847fba9 100644 --- a/web_assets/functions.js +++ b/web_assets/functions.js @@ -211,6 +211,7 @@ function drawMapControls() { // parse the data as definned in the regions.js function initRegions() { if (regionsInit) { return; } + if (typeof(regionData) == "undefined") { return; } // skip this if we have no region.js file regionsInit = true; for (i in regionGroups) { @@ -295,6 +296,7 @@ function initRegions() { // may need to be reviewed by agrif or someone else... little finicky right now. function initMarkers() { if (markersInit) { return; } // oh, we've already done this? nevermind, exit the function. + if (typeof(markerData) == "undefined") { return; } // no markers.js file, so skip this. markersInit = true; // now that we've started, dont have to do it twice. // first, give all collections an empty array to work with From 48d99a674f9bcbedba98ae12a41990940e4e287c Mon Sep 17 00:00:00 2001 From: Alex Headley Date: Sat, 23 Apr 2011 14:02:00 -0400 Subject: [PATCH 47/78] moving style stuff out of index.html --- web_assets/index.html | 2 +- web_assets/style.css | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/web_assets/index.html b/web_assets/index.html index 89554e8..961dd75 100644 --- a/web_assets/index.html +++ b/web_assets/index.html @@ -14,6 +14,6 @@ -
+
diff --git a/web_assets/style.css b/web_assets/style.css index 8585eb3..19b9b34 100644 --- a/web_assets/style.css +++ b/web_assets/style.css @@ -1,6 +1,18 @@ -html { height: 100% } -body { height: 100%; margin: 0px; padding: 0px ; background-color: #000; } -#mcmap { height: 100% } +html { + height: 100%; +} + +body { + height: 100%; + margin: 0px; + padding: 0px; + background-color: #000; +} + +#mcmap { + width: 100%; + height: 100%; +} .infoWindow { height: 100px; From df2117544d603c0331038aac1aef658b26525a95 Mon Sep 17 00:00:00 2001 From: aheadley Date: Sat, 23 Apr 2011 18:54:12 -0400 Subject: [PATCH 48/78] new js stuff ready for testing --- web_assets/index.html | 12 +- web_assets/overviewer.js | 706 +++++++++++++++++++++++++++++++++ web_assets/overviewerConfig.js | 38 ++ 3 files changed, 748 insertions(+), 8 deletions(-) create mode 100644 web_assets/overviewer.js create mode 100644 web_assets/overviewerConfig.js diff --git a/web_assets/index.html b/web_assets/index.html index 961dd75..14c6666 100644 --- a/web_assets/index.html +++ b/web_assets/index.html @@ -3,17 +3,13 @@ - - - - - + + + - +
diff --git a/web_assets/overviewer.js b/web_assets/overviewer.js new file mode 100644 index 0000000..3b10189 --- /dev/null +++ b/web_assets/overviewer.js @@ -0,0 +1,706 @@ +var overviewer = { + 'map': null, + 'collections': { + 'markerDatas': [], + 'markers': {}, + 'regionDatas': [], + 'regions': {}, + 'overlays': [], + 'mapTypes': {}, + 'infoWindow': null + }, + 'util': { + 'initialize': function() { + overviewer.util.initializeClassPrototypes(); + overviewer.util.initializeMapTypes(); + overviewer.util.initializeMap(); + overviewer.util.initializeMarkers(); + overviewer.util.initializeRegions(); + overviewer.util.createMapControls(); + }, + 'initializeClassPrototypes': function() { + overviewer.classes.MapProjection.prototype.fromLatLngToPoint = function(latLng) { + var x = latLng.lng() * overviewerConfig.CONST.tileSize; + var y = latLng.lat() * overviewerConfig.CONST.tileSize; + return new google.maps.Point(x, y); + }; + + overviewer.classes.MapProjection.prototype.fromPointToLatLng = function(point) { + var lng = point.x * this.inverseTileSize; + var lat = point.y * this.inverseTileSize; + return new google.maps.LatLng(lat, lng); + }; + + overviewer.classes.CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) { + var div = ownerDocument.createElement('DIV'); + div.innerHTML = '(' + coord.x + ', ' + coord.y + ', ' + zoom + ')'; + div.innerHTML += '
'; + div.innerHTML += overviewer.collections.mapTypes[0].getTileUrl(coord, zoom); + div.style.width = this.tileSize.width + 'px'; + div.style.height = this.tileSize.height + 'px'; + div.style.fontSize = '10'; + div.style.borderStyle = 'solid'; + div.style.borderWidth = '1px'; + div.style.borderColor = '#AAAAAA'; + return div; + }; + }, + /** + * I think this was old code that was replaced by stuff that is now + * in initializeMap() + */ + 'initializeMapTypes': function() { + var mapOptions = {}; + for (i in overviewerConfig.mapTypes) { + var view = overviewerConfig.mapTypes[i]; + var imageFormat = view.imgformat ? view.imgformat : 'png'; + mapOptions[view.label] = { + 'getTileUrl': overviewer.gmap.getTileUrlGenerator(view.path, + view.base, imageFormat), + 'tileSize': new google.maps.Size( + overviewerConfig.CONST.tileSize, + overviewerConfig.CONST.tileSize), + 'maxZoom': overviewerConfig.map.maxZoom, + 'minZoom': overviewerConfig.map.minZoom, + 'isPng': imageFormat.toLowerCase() == 'png' + } + overviewer.collections.mapTypes[view.label] = new google.maps.ImageMapType( + mapOptions[view.label]); + overviewer.collections.mapTypes[view.label].name = view.label; + overviewer.collections.mapTypes[view.label].alt = 'Minecraft ' + + view.label + ' Map'; + overviewer.collections.mapTypes[view.label].projection = + new overviewer.classes.MapProjection(); + if (view.overlay) { + overviewer.collections.overlays.push( + overviewer.collections.mapTypes[view.label]); + } else { + overviewer.collections.mapTypeIds.push( + overviewerConfig.CONST.mapDivId + view.label); + } + } + }, + 'initilizeMap': function() { + var defaultCenter = overviewer.util.fromWorldToLatLng( + overviewerConfig.map.center[0], overviewerConfig.map.center[1], + overviewerConfig.map.center[2]); + var lat = defaultCenter.lat(); + var lng = defaultCenter.lng(); + var zoom = overviewerConfig.map.defaultZoom; + var mapcenter; + queryParams = overviewer.util.parseQueryString(); + if (queryParams.lat) { + lat = parseFloat(queryParams.lat); + } + if (queryParams.lng) { + lng = parseFloat(queryParams.lng); + } + if (queryParams.zoom) { + if (queryParams.zoom == 'max') { + zoom = overviewerConfig.map.maxZoom; + } else if (queryParams.zoom == 'min') { + zoom = overviewerConfig.map.minZoom; + } else { + zoom = parseInt(queryParams.zoom); + if (zoom < 0 && zoom + overvierConfig.map.maxZoom >= 0) { + //if zoom is negative, try to treat as "zoom out from max zoom" + zoom += overviewerConfig.map.maxZoom; + } else { + //fall back to default zoom + zoom = overviewerConfig.map.defaultZoom; + } + } + } + if (queryParams.x && queryParams.y && queryParams.z) { + mapcenter = overviewer.util.fromWorldToLatLng(queryParams.x, + queryParams.y, queryParams.z); + // Add a market indicating the user-supplied position + overviewer.collections.markers.push({ + 'msg': 'Coordinates ' + queryParams.x + ', ' + + queryParams.y + ', ' + queryParams.z, + 'y': parseFloat(queryParams.y), + 'x': parseFloat(queryParams.x), + 'z': parseFloat(queryParams.z), + 'type': 'querypos'}); + } else { + mapcenter = new google.maps.LatLng(lat, lng); + } + var mapOptions = { + zoom: zoom, + center: mapcenter, + navigationControl: overviewerConfig.map.controls.navigation, + scaleControl: false, + mapTypeControl: overviewer.collections.mapTypeIds.length > 1, + mapTypeControlOptions: { + mapTypeIds: overviewer.collections.mapTypeIds + }, + mapTypeId: overviewer.util.getDefaultMapTypeId(), + streetViewControl: false + }; + overviewer.map = new google.maps.Map(document.getElementById( + overviewerConfig.CONST.mapDivId), mapOptions); + + if (overviewerConfig.map.debug) { + overviewer.map.overlayMapTypes.insertAt(0, + new CoordMapType(new google.maps.Size( + overviewerConfig.CONST.tileSize, + overviewerConfig.CONST.tileSize))); + google.maps.event.addListener(overviewer.map, 'click', function(event) { + overviewer.util.debug('latLng: (' + event.latLng.lat() + + ', ' + event.latLng.lng() + ')'); + var pnt = overviewer.map.getProjection().fromLatLngToPoint(event.latLng); + overviewer.util.debug('point: ' + pnt); + var pxx = pnt.x * config.tileSize * Math.pow(2, config.maxZoom); + var pxy = pnt.y * config.tileSize * Math.pow(2, config.maxZoom); + overviewer.util.debug('pixel: (' + pxx + ', ' + pxy + ')'); + }); + } + + // Now attach the coordinate map type to the map's registry + for (i in overviewer.collections.mapTypes) { + overviewer.map.mapTypes.set(overviewerConfig.CONST.mapDivId + + overviewer.collections.mapTypes[i].name, + overviewer.collections.mapTypes[i]); + } + + // Make the link again whenever the map changes + google.maps.event.addListener(overviewer.map, 'zoom_changed', function() { + overviewer.util.setViewUrl(); + }); + google.maps.event.addListener(overviewer.map, 'center_changed', function() { + overviewer.util.setViewUrl(); + }); + google.maps.event.addListener(overviewer.map, 'maptypeid_changed', function() { + var newType = overviewer.map.getMapTypeId(); + for(i in overviewerConfig.mapTypes) { + if( overviewerConfig.CONST.mapDivId + + overviewerConfig.mapTypes[i].label == newType ) { + $('#'+overviewerConfig.CONST.mapDivId).css( + 'background-color', overviewerConfig.mapTypes[i].bg_color); + break; + } + } + }); + // We can now set the map to use the 'coordinate' map type + overviewer.map.setMapTypeId(overviewer.util.getDefaultMapTypeId()); + }, + 'initializeMarkers': function() { + //first, give all collections an empty array to work with + for (i in overviewerConfig.objectGroups.markers) { + overviewer.collections.markers[ + overviewerConfig.objectGroups.markers[i].label] = []; + } + for (i in overviewer.collections.markerDatas) { + var markerData = overviewer.collections.markerDatas[i]; + for (j in markerData) { + var item = markerData[j]; + // a default: + var iconURL = ''; + if (item.type == 'spawn') { + // don't filter spawn, always display + var marker = new google.maps.Marker({ + 'position': overviewer.util.fromWorldToLatLng(item.x, + item.y, item.z), + 'map': overviewer.map, + 'title': jQuery.trim(item.msg), + 'icon': overviewerConfig.CONST.image.spawnMarker + }); + continue; + } + + if (item.type == 'querypos') { + // Set on page load if MC x/y/z coords are given in the + // query string + var marker = new google.maps.Marker({ + 'position': overviewer.util.fromWorldToLatLng(item.x, + item.y, item.z), + 'map': overviewer.map, + 'title': jQuery.trim(item.msg), + 'icon': overviewerConfig.CONST.image.queryMarker + }); + continue; + } + + var matched = false; + for (j in overviewerConfig.objectGroups.signs) { + var signGroup = overviewerConfig.objectGroups.signs[j]; + var label = signGroup.label; + if (signGroup.match(item)) { + matched = true; + // can add custom types of images for externally defined + // item types, like 'command' here. + if (item.type == 'sign') { + iconURL = overviewerConfig.CONST.image.signMarker; + } + overviewer.util.debug('Sign icon: ' + signGroup.icon); + if (signGroup.icon) { + iconURL = signGroup.icon; + } + var converted = fromWorldToLatLng(item.x, item.y, item.z); + var marker = new google.maps.Marker({ + 'position': overviewer.util.fromWorldToLatLng(item.x, + item.y, item.z), + 'map': overviewer.map, + 'title': jQuery.trim(item.msg), + 'icon': iconURL, + 'visible': false + }); + overviewer.collections.markers[label].push(marker); + if (item.type == 'sign') { + overviewer.util.createMarkerInfoWindow(marker); + } + } + } + + if (!matched) { + // is this signpost doesn't match any of the groups in + // config.js, add it automatically to the "__others__" group + if (item.type == 'sign') { + iconURL = overviewerConfig.CONST.image.signMarker; + } + var marker = new google.maps.Marker({position: converted, + 'position': overviewer.util.fromWorldToLatLng(item.x, + item.y, item.z), + 'map': overviewer.map, + 'title': jQuery.trim(item.msg), + 'icon': iconURL, + 'visible': false + }); + if (overviewer.collections.markers['__others__']) { + overviewer.collections.markers['__others__'].push(marker); + } else { + overviewer.collections.markers['__others__'] = [marker]; + } + if (item.type == 'sign') { + overviewer.util.createMarkerInfoWindow(marker, item); + } + } + } + } + }, + 'initializeRegions': function() { + for (i in overviewerConfig.objectGroups.regions) { + overviewer.collections.regions[overviewerConfig.objectGroups.regions[i].label] = []; + } + for (i in overviewer.collections.regionDatas) { + var regionData = overviewer.collections.regionDatas[i]; + for (j in regionData) { + var region = regionData[j]; + // pull all the points out of the regions file. + var converted = new google.maps.MVCArray(); + for (k in region.path) { + var point = region.path[k]; + converted.push(overviewer.util.fromWorldToLatLng( + point.x, point.y, point.z)); + + } + for (k in overviewerConfig.objectGroups.regions) { + var regionGroup = overviewerConfig.objectGroups.regions[k]; + var clickable = regionGroup.clickable; + var label = regionGroup.label; + + if(region.label) { + var name = region.label + } else { + var name = 'rawr'; + clickable = false; // if it doesn't have a name, we dont have to show it. + } + + if (region.closed) { + var shape = new google.maps.Polygon({ + 'name': name, + 'clickable': clickable, + 'geodesic': false, + 'map': null, + 'strokeColor': region.color, + 'strokeOpacity': region.opacity, + 'strokeWeight': overviewerConfig.CONST.regionStrokeWeight, + 'fillColor': region.color, + 'fillOpacity': region.opacity * 0.25, + 'zIndex': j, + 'paths': converted + }); + } else { + var shape = new google.maps.Polyline({ + 'name': name, + 'clickable': clickable, + 'geodesic': false, + 'map': null, + 'strokeColor': region.color, + 'strokeOpacity': region.opacity, + 'strokeWeight': overviewerConfig.CONST.regionStrokeWeight, + 'zIndex': j, + 'path': converted + }); + } + overviewer.collections.regions[label].push(shape); + + if (clickable) { + overviewer.util.createRegionInfoWindow(shape); + } + } + } + } + }, + 'debug': function(msg) { + if (overviewerConfig.map.debug) { + console.log(msg); + } + }, + 'parseQueryString': function() { + var results = {}; + var queryString = location.search.substring(1); + var pairs = queryString.split('&'); + for (i in pairs) { + var pos = pairs[i].indexOf('='); + var key = pairs[i].substring(0,pos).toLowerCase(); + var value = pairs[i].substring(pos+1).toLowerCase(); + overviewer.util.debug( 'Found GET paramter: ' + key + ' = ' + value); + results[key] = value; + } + return results; + }, + 'setViewUrl': function() { + var displayZoom = overviewer.map.getZoom(); + if (displayZoom == overviewerConfig.map.maxZoom) { + displayZoom = 'max'; + } else { + displayZoom -= overviewerConfig.map.maxZoom; + } + var point; + var point = overviewer.util.fromLatLngToWorld( + overviewer.map.getCenter().lat(), overviewer.map.getCenter().lng()); + var viewUrl = location.href.substring(0, location.href.lastIndexOf( + location.search)) + + '?x=' + Math.floor(point.x) + + '&y=' + Math.floor(point.y) + + '&z=' + Math.floor(point.z) + + '&zoom=' + displayZoom; + document.getElementById('link').innerHTML = viewUrl; + + }, + 'getDefaultMapTypeId': function() { + return overviewer.collections.mapTypeIds[0]; + }, + 'fromWorldToLatLng': function(x, z, y) { + // the width and height of all the highest-zoom tiles combined, + // inverted + var perPixel = 1.0 / (overviewerConfig.CONST.tileSize * + Math.pow(2, overviewerConfig.map.maxZoom)); + + // This information about where the center column is may change with + // a different drawing implementation -- check it again after any + // drawing overhauls! + + // point (0, 0, 127) is at (0.5, 0.0) of tile (tiles/2 - 1, tiles/2) + // so the Y coordinate is at 0.5, and the X is at 0.5 - + // ((tileSize / 2) / (tileSize * 2^maxZoom)) + // or equivalently, 0.5 - (1 / 2^(maxZoom + 1)) + var lng = 0.5 - (1.0 / Math.pow(2, overviewerConfig.map.maxZoom + 1)); + var lat = 0.5; + + // the following metrics mimic those in ChunkRenderer.chunk_render + // in "chunk.py" or, equivalently, chunk_render in src/iterate.c + + // each block on X axis adds 12px to x and subtracts 6px from y + lng += 12 * x * perPixel; + lat -= 6 * x * perPixel; + + // each block on Y axis adds 12px to x and adds 6px to y + lng += 12 * y * perPixel; + lat += 6 * y * perPixel; + + // each block down along Z adds 12px to y + lat += 12 * (128 - z) * perPixel; + + // add on 12 px to the X coordinate to center our point + lng += 12 * perPixel; + + return new google.maps.LatLng(lat, lng); + }, + 'fromLatLngToWorld': function(lat, lng) { + // Initialize world x/y/z object to be returned + var point = Array(); + point.x = 0; + point.y = 64; + point.z = 0; + + // the width and height of all the highest-zoom tiles combined, + // inverted + var perPixel = 1.0 / (overviewerConfig.CONST.tileSize * + Math.pow(2, overviewerConfig.map.maxZoom)); + + // Revert base positioning + // See equivalent code in fromWorldToLatLng() + lng -= 0.5 - (1.0 / Math.pow(2, overviewerConfig.map.maxZoom + 1)); + lat -= 0.5; + + // I'll admit, I plugged this into Wolfram Alpha: + // a = (x * 12 * r) + (z * 12 * r), b = (z * 6 * r) - (x * 6 * r) + // And I don't know the math behind solving for for X and Z given + // A (lng) and B (lat). But Wolfram Alpha did. :) I'd welcome + // suggestions for splitting this up into long form and documenting + // it. -RF + point.x = (lng - 2 * lat) / (24 * perPixel) + point.z = (lng + 2 * lat) / (24 * perPixel) + + // Adjust for the fact that we we can't figure out what Y is given + // only latitude and longitude, so assume Y=64. + point.x += 64 + 1; + point.z -= 64 + 2; + + return point; + }, + 'createMapControls': function() { + // viewstate link (little link to where you're looking at the map, + // normally bottom left) + var viewStateDiv = document.createElement('DIV'); + viewStateDiv.id='link'; + // add it to the map, bottom left. + map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(viewStateDiv); + + // compass rose, in the top right corner + var compassDiv = document.createElement('DIV'); + compassDiv.style.padding = '5px'; + var compassImg = document.createElement('IMG'); + compassImg.src = overviewerConfig.CONST.image.compass; + compassDiv.appendChild(compassImg); + compassDiv.index = 0; + // add it to the map, top right. + map.controls[google.maps.ControlPosition.TOP_RIGHT].push(compassDiv); + + // Spawn button + var homeControlDiv = document.createElement('DIV'); + var homeControl = new overviewer.classes.HomeControl(homeControlDiv); + homeControlDiv.id = 'customControl'; + homeControlDiv.index = 1; + overviewer.map.controls[google.maps.ControlPosition.TOP_RIGHT].push(homeControlDiv); + + // only need to create the control if there are items in the list. + // as defined in config.js + if (overviewerConfig.objectGroups.signs.length > 0) { + // signpost display control + var items = []; + for (i in overviewerConfig.objectGroups.signs) { + var signGroup = overviewerConfig.objectGroups.signs[i]; + var iconURL = signGroup.icon; + if(!iconURL) { + iconURL = overviewerConfig.CONST.image.defaultMarker; + } + items.push({ + 'label': signGroup.label, + 'checked': signGroup.checked, + 'icon': iconURL, + 'action': function(n, item, checked) { + jQuery.each(overviewer.collections.markers[item.label], + function(i,elem) { + elem.setVisible(checked); + } + ); + overviewer.util.debug('Adding sign item: ' + item.label); + } + }); + } + overviewer.util.createDropDown('Signposts', items); + } + + // if there are any regions data, lets show the option to hide/show them. + if (overviewerConfig.objectGroups.regions.length > 0) { + // region display control + var items = []; + for (i in overviewerConfig.objectGroups.regions) { + var regionGroup = overviewerConfig.objectGroups.regions[i]; + items.push({ + 'label': regionGroup.label, + 'checked': regionGroup.checked, + 'action': function(n, item, checked) { + jQuery.each(overviewer.collections.regions[item.label], + function(i,elem) { + // Thanks to LeastWeasel for this line! + elem.setMap(checked ? overviewer.map : null); + } + ); + } + }); + } + overviewer.util.createDropDown('Regions', items); + } + + if (overviewer.collections.overlays.length > 0) { + // overlay maps control + var items = []; + for (i in overviewer.collections.overlays) { + var overlay = overviewer.collections.overlays[i]; + items.push({ + 'label': overlay.name, + 'checked': false, + 'overlay': overlay, + 'action': function(i, item, checked) { + if (checked) { + overviewer.map.overlayMapTypes.push(item.overlay); + } else { + var idx_to_delete = -1; + overviewer.map.overlayMapTypes.forEach(function(e, j) { + if (e == item.overlay) { idx_to_delete = j; } + }); + if (idx_to_delete >= 0) { + overviewer.map.overlayMapTypes.removeAt(idx_to_delete); + } + } + } + }); + } + overviewer.util.createDropDown('Overlays', items); + } + }, + 'createDropDown': function(title, items) { + var control = document.createElement('DIV'); + // let's let a style sheet do most of the styling here + control.id = 'customControl'; + + var controlText = document.createElement('DIV'); + controlText.innerHTML = title; + + var controlBorder = document.createElement('DIV'); + controlBorder.id='top'; + control.appendChild(controlBorder); + controlBorder.appendChild(controlText); + + var dropdownDiv = document.createElement('DIV'); + dropdownDiv.id='dropDown'; + control.appendChild(dropdownDiv); + dropdownDiv.innerHTML=''; + + // add the functionality to toggle visibility of the items + $(controlText).click(function() { + $(dropdownDiv).toggle(); + }); + + // add that control box we've made back to the map. + overviewer.map.controls[google.maps.ControlPosition.TOP_RIGHT].push(control); + + for(i in items) { + // create the visible elements of the item + var item = items[i]; + overviewer.util.debug(item); + var itemDiv = document.createElement('div'); + var itemInput = document.createElement('input'); + itemInput.type='checkbox'; + + // give it a name + $(itemInput).data('label',item.label); + jQuery(itemInput).click((function(local_idx, local_item) { + return function(e) { + item.action(local_idx, local_item, e.target.checked); + }; + })(i, item)); + + // if its checked, its gotta do something, do that here. + if (item.checked) { + itemInput.checked = true; + item.action(i, item.label, item.checked); + } + dropdownDiv.appendChild(itemDiv); + itemDiv.appendChild(itemInput); + var textNode = document.createElement('text'); + if(item.icon) { + textNode.innerHTML = '' + item.label + '
'; + } else { + textNode.innerHTML = item.label + '
'; + } + + itemDiv.appendChild(textNode); + } + }, + 'createRegionInfoWindow': function(shape) { + var infowindow = new google.maps.InfoWindow(); + google.maps.event.addListener(shape, 'click', function(event, i) { + if (overviewer.collections.infoWindow) { + overviewer.collections.infoWindow.close(); + } + // Replace our Info Window's content and position + var contentString = 'Region: ' + shape.name + '
' + + 'Clicked Location:
' + event.latLng.lat() + ', ' + + event.latLng.lng() + '
'; + infowindow.setContent(contentString); + infowindow.setPosition(event.latLng); + infowindow.open(overviewer.map); + overviewer.collections.infoWindow = infowindow; + }); + }, + 'createMarkerInfoWindow': function(marker) { + var windowContent = '

' + marker.title.replace(/\n/g,'
') + '

'; + var infowindow = new google.maps.InfoWindow({ + 'content': windowContent + }); + google.maps.event.addListener(marker, 'click', function() { + if (overviewer.collections.infoWindow) { + overviewer.collections.infoWindow.close(); + } + infowindow.open(overviewer.map, marker); + overviewer.collections.infoWindow = infowindow; + }); + } + }, + 'classes': { + 'HomeControl': function(controlDiv) { + controlDiv.style.padding = '5px'; + // Set CSS for the control border + var control = document.createElement('DIV'); + control.id='top'; + control.title = 'Click to center the map on the Spawn'; + controlDiv.appendChild(control); + + // Set CSS for the control interior + var controlText = document.createElement('DIV'); + controlText.innerHTML = 'Spawn'; + controlText.id='button'; + control.appendChild(controlText); + + // Setup the click event listeners: simply set the map to map center + // as definned below + google.maps.event.addDomListener(control, 'click', function() { + overviewer.map.panTo(fromWorldToLatLng( + overviewerConfig.map.center[0], + overviewerConfig.map.center[1], + overviewerConfig.map.center[2])); + }); + }, + 'MapProjection' : function() { + this.inverseTileSize = 1.0 / overviewerConfig.CONST.tileSize; + }, + //Looks like this is only used for debugging + 'CoordMapType': function(tileSize) { + this.tileSize = tileSize; + } + }, + 'gmap': { + 'getTileUrlGenerator': function(path, pathBase, pathExt) { + return function(tile, zoom) { + var url = path; + var urlBase = ( pathBase ? pathBase : '' ); + if(tile.x < 0 || tile.x >= Math.pow(2, zoom) || + tile.y < 0 || tile.y >= Math.pow(2, zoom)) { + url += '/blank'; + } else if(zoom == 0) { + url += '/base'; + } else { + for(var z = zoom - 1; z >= 0; --z) { + var x = Math.floor(tile.x / Math.pow(2, z)) % 2; + var y = Math.floor(tile.y / Math.pow(2, z)) % 2; + url += '/' + (x + 2 * y); + } + } + url = url + '.' + pathExt; + if(overviewerConfig.map.cacheMinutes > 0) { + var d = new Date(); + url += '?c=' + Math.floor(d.getTime() / + (1000 * 60 * overviewerConfig.map.cacheMinutes)); + } + return(urlBase + url); + } + } + } +}; \ No newline at end of file diff --git a/web_assets/overviewerConfig.js b/web_assets/overviewerConfig.js new file mode 100644 index 0000000..a0e8f33 --- /dev/null +++ b/web_assets/overviewerConfig.js @@ -0,0 +1,38 @@ +var overviewerConfig = { + //These will probably never change + 'CONST': { + 'tileSize': 384, + 'image': { + 'defaultMarker': 'signpost.png', + 'signMarker': 'signpost_icon.png', + 'compass': 'compass.png', + 'spawnMarker': 'http://google-maps-icons.googlecode.com/files/home.png', + 'queryMarker': 'http://google-maps-icons.googlecode.com/files/regroup.png' + }, + 'mapDivId': 'mcmap', + 'regionStrokeWeight': 2 + }, + 'map': { + 'controls': { + 'navigation': true + }, + 'defaultZoom': 0, + 'minZoom': {minzoom}, + 'maxZoom': {maxzoom}, + 'center': {spawn_coords}, + 'cacheMinutes': 0, + 'debug': false, + }, + 'objectGroups': { + 'signs': [ + { + 'label': 'All', + 'match': function(sign) { + return true; + } + } + ], + 'regions': [] + }, + 'mapTypes': {maptypedata} +}; \ No newline at end of file From 37a7b28bc8104f4362852c8ce3fac59c03afe4ca Mon Sep 17 00:00:00 2001 From: Alex Headley Date: Sat, 23 Apr 2011 20:21:59 -0400 Subject: [PATCH 49/78] fixes from testing --- web_assets/overviewer.js | 70 ++++++++++++++++++---------------- web_assets/overviewerConfig.js | 12 +++++- 2 files changed, 48 insertions(+), 34 deletions(-) diff --git a/web_assets/overviewer.js b/web_assets/overviewer.js index 3b10189..4b0d986 100644 --- a/web_assets/overviewer.js +++ b/web_assets/overviewer.js @@ -7,6 +7,7 @@ var overviewer = { 'regions': {}, 'overlays': [], 'mapTypes': {}, + 'mapTypeIds': [], 'infoWindow': null }, 'util': { @@ -35,10 +36,10 @@ var overviewer = { var div = ownerDocument.createElement('DIV'); div.innerHTML = '(' + coord.x + ', ' + coord.y + ', ' + zoom + ')'; div.innerHTML += '
'; - div.innerHTML += overviewer.collections.mapTypes[0].getTileUrl(coord, zoom); + //div.innerHTML += overviewer.collections.mapTypes[0].getTileUrl(coord, zoom); div.style.width = this.tileSize.width + 'px'; div.style.height = this.tileSize.height + 'px'; - div.style.fontSize = '10'; + div.style.fontSize = '10px'; div.style.borderStyle = 'solid'; div.style.borderWidth = '1px'; div.style.borderColor = '#AAAAAA'; @@ -80,7 +81,7 @@ var overviewer = { } } }, - 'initilizeMap': function() { + 'initializeMap': function() { var defaultCenter = overviewer.util.fromWorldToLatLng( overviewerConfig.map.center[0], overviewerConfig.map.center[1], overviewerConfig.map.center[2]); @@ -142,7 +143,7 @@ var overviewer = { if (overviewerConfig.map.debug) { overviewer.map.overlayMapTypes.insertAt(0, - new CoordMapType(new google.maps.Size( + new overviewer.classes.CoordMapType(new google.maps.Size( overviewerConfig.CONST.tileSize, overviewerConfig.CONST.tileSize))); google.maps.event.addListener(overviewer.map, 'click', function(event) { @@ -150,8 +151,10 @@ var overviewer = { ', ' + event.latLng.lng() + ')'); var pnt = overviewer.map.getProjection().fromLatLngToPoint(event.latLng); overviewer.util.debug('point: ' + pnt); - var pxx = pnt.x * config.tileSize * Math.pow(2, config.maxZoom); - var pxy = pnt.y * config.tileSize * Math.pow(2, config.maxZoom); + var pxx = pnt.x * overviewerConfig.CONST.tileSize * + Math.pow(2, overviewerConfig.map.maxZoom); + var pxy = pnt.y * overviewerConfig.CONST.tileSize * + Math.pow(2, overviewerConfig.map.maxZoom); overviewer.util.debug('pixel: (' + pxx + ', ' + pxy + ')'); }); } @@ -186,9 +189,11 @@ var overviewer = { }, 'initializeMarkers': function() { //first, give all collections an empty array to work with - for (i in overviewerConfig.objectGroups.markers) { + for (i in overviewerConfig.objectGroups.signs) { + overviewer.util.debug('Found sign group: ' + + overviewerConfig.objectGroups.signs[i].label); overviewer.collections.markers[ - overviewerConfig.objectGroups.markers[i].label] = []; + overviewerConfig.objectGroups.signs[i].label] = []; } for (i in overviewer.collections.markerDatas) { var markerData = overviewer.collections.markerDatas[i]; @@ -236,7 +241,6 @@ var overviewer = { if (signGroup.icon) { iconURL = signGroup.icon; } - var converted = fromWorldToLatLng(item.x, item.y, item.z); var marker = new google.maps.Marker({ 'position': overviewer.util.fromWorldToLatLng(item.x, item.y, item.z), @@ -245,6 +249,7 @@ var overviewer = { 'icon': iconURL, 'visible': false }); + overviewer.util.debug(label); overviewer.collections.markers[label].push(marker); if (item.type == 'sign') { overviewer.util.createMarkerInfoWindow(marker); @@ -258,7 +263,7 @@ var overviewer = { if (item.type == 'sign') { iconURL = overviewerConfig.CONST.image.signMarker; } - var marker = new google.maps.Marker({position: converted, + var marker = new google.maps.Marker({ 'position': overviewer.util.fromWorldToLatLng(item.x, item.y, item.z), 'map': overviewer.map, @@ -457,7 +462,7 @@ var overviewer = { var viewStateDiv = document.createElement('DIV'); viewStateDiv.id='link'; // add it to the map, bottom left. - map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(viewStateDiv); + overviewer.map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(viewStateDiv); // compass rose, in the top right corner var compassDiv = document.createElement('DIV'); @@ -467,7 +472,7 @@ var overviewer = { compassDiv.appendChild(compassImg); compassDiv.index = 0; // add it to the map, top right. - map.controls[google.maps.ControlPosition.TOP_RIGHT].push(compassDiv); + overviewer.map.controls[google.maps.ControlPosition.TOP_RIGHT].push(compassDiv); // Spawn button var homeControlDiv = document.createElement('DIV'); @@ -493,7 +498,7 @@ var overviewer = { 'icon': iconURL, 'action': function(n, item, checked) { jQuery.each(overviewer.collections.markers[item.label], - function(i,elem) { + function(i, elem) { elem.setVisible(checked); } ); @@ -514,14 +519,13 @@ var overviewer = { 'label': regionGroup.label, 'checked': regionGroup.checked, 'action': function(n, item, checked) { - jQuery.each(overviewer.collections.regions[item.label], - function(i,elem) { - // Thanks to LeastWeasel for this line! - elem.setMap(checked ? overviewer.map : null); - } - ); - } - }); + jQuery.each(overviewer.collections.regions[item.label], + function(i,elem) { + // Thanks to LeastWeasel for this line! + elem.setMap(checked ? overviewer.map : null); + }); + } + }); } overviewer.util.createDropDown('Regions', items); } @@ -536,17 +540,19 @@ var overviewer = { 'checked': false, 'overlay': overlay, 'action': function(i, item, checked) { - if (checked) { - overviewer.map.overlayMapTypes.push(item.overlay); - } else { - var idx_to_delete = -1; - overviewer.map.overlayMapTypes.forEach(function(e, j) { - if (e == item.overlay) { idx_to_delete = j; } - }); - if (idx_to_delete >= 0) { - overviewer.map.overlayMapTypes.removeAt(idx_to_delete); + if (checked) { + overviewer.map.overlayMapTypes.push(item.overlay); + } else { + var idx_to_delete = -1; + overviewer.map.overlayMapTypes.forEach(function(e, j) { + if (e == item.overlay) { + idx_to_delete = j; } + }); + if (idx_to_delete >= 0) { + overviewer.map.overlayMapTypes.removeAt(idx_to_delete); } + } } }); } @@ -662,7 +668,7 @@ var overviewer = { // Setup the click event listeners: simply set the map to map center // as definned below google.maps.event.addDomListener(control, 'click', function() { - overviewer.map.panTo(fromWorldToLatLng( + overviewer.map.panTo(overviewer.util.fromWorldToLatLng( overviewerConfig.map.center[0], overviewerConfig.map.center[1], overviewerConfig.map.center[2])); @@ -703,4 +709,4 @@ var overviewer = { } } } -}; \ No newline at end of file +}; diff --git a/web_assets/overviewerConfig.js b/web_assets/overviewerConfig.js index a0e8f33..841841e 100644 --- a/web_assets/overviewerConfig.js +++ b/web_assets/overviewerConfig.js @@ -32,7 +32,15 @@ var overviewerConfig = { } } ], - 'regions': [] + 'regions': [ + { + 'label': 'All', + 'clickable':true, + 'match': function(region) { + return true; + } + } + ] }, 'mapTypes': {maptypedata} -}; \ No newline at end of file +}; From 1c92776e41d5923a798ae7fd2486f6e4b56ea02c Mon Sep 17 00:00:00 2001 From: aheadley Date: Sat, 23 Apr 2011 21:46:41 -0400 Subject: [PATCH 50/78] fixed minor bugs, added comments, made python aware of new files, removed old js files --- config.js | 78 ---- googlemap.py | 12 +- overviewerConfig.js | 138 +++++++ quadtree.py | 4 +- web_assets/functions.js | 702 --------------------------------- web_assets/overviewer.js | 173 +++++++- web_assets/overviewerConfig.js | 46 --- 7 files changed, 313 insertions(+), 840 deletions(-) delete mode 100644 config.js create mode 100644 overviewerConfig.js delete mode 100644 web_assets/functions.js delete mode 100644 web_assets/overviewerConfig.js diff --git a/config.js b/config.js deleted file mode 100644 index 839d724..0000000 --- a/config.js +++ /dev/null @@ -1,78 +0,0 @@ - - var config = { - tileSize: 384, - defaultZoom: 2, - minZoom: {minzoom}, - maxZoom: {maxzoom}, - // center on this point, in world coordinates, ex: - //center: [0,0,0], - center: {spawn_coords}, - cacheMinutes: 0, // Change this to have browsers automatically request new images every x minutes - debug: false - }; - - -/* signGroups -- A list of signpost groups. A signpost can fall into zero, one, or more than one - * group. See below for some examples. - * - * Required: - * label : string. Displayed in the drop down menu control. - * match : function. Applied to each marker (from markers.js). It is returns true if the marker - * Should be part of the group. - * - * Optional: - * checked : boolean. Set to true to have the group visible by default - * icon : string. Used to specify an icon url. - */ -var signGroups = [ -// {label: "'To'", checked: false, match: function(s) {return s.msg.match(/to/)}}, -// {label: "Storage", match: function(s) {return s.msg.match(/storage/i) || s.msg.match(/dirt/i) || s.msg.match(/sand/)}}, -// {label: "Below Sealevel", match: function(s) { return s.y<64;}}, -// {label: "Info", match: function(s) { return s.msg.match("\\[info\\]");}, icon:"http://google-maps-icons.googlecode.com/files/info.png"}, - {label: "All", match: function(s) {return true}}, -]; - -/* regionGroups -- A list of region groups. A region can fall into zero, one, or more than one - * group. See below for some examples. - * regions have been designed to work with the - * WorldGuard Overviewer Region importer at https://github.com/pironic/WG2OvR But your host must support php in order - * to run WG2OvR. You can also continue to use any other region format. - * - * Required: - * label : string. Displayed in the drop down menu control. - * clickable : boolean. Will determine if we should generate an experimental info window - * that shows details about the clicked region. - * NOTE: if a region (as definned in region.js) does not have a label, this will default to false. - * match : function. Applied to each region (from region.js). It returns true if the region - * Should be part of the group. - * - * Optional: - * checked : boolean. Set to true to have the group visible by default - */ -var regionGroups = [ - //{label: "All", clickable: false, checked: false, 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. - * Optional: - * base : string. Base of the url path for tile locations, useful for serving tiles from a different server than the js/html server. - * imgformat : string. File extension used for these tiles. Defaults to png. - * overlay : bool. If true, this tile set will be treated like an overlay - -var mapTypeData=[ - {'label': 'Unlit', 'path': 'tiles'}, -// {'label': 'Day', 'path': 'lighting/tiles'}, -// {'label': 'Night', 'path': 'night/tiles', 'imgformat': 'jpg'}, -// {'label': 'Spawn', 'path': 'spawn/tiles', 'base': 'http://example.cdn.amazon.com/'}, -// {'label': 'Overlay', 'path': 'overlay/tiles', 'overlay': true} -]; - */ - -var mapTypeData = {maptypedata}; - diff --git a/googlemap.py b/googlemap.py index 25b5c70..af56fbe 100644 --- a/googlemap.py +++ b/googlemap.py @@ -86,7 +86,7 @@ class MapGen(object): """Writes out config.js, marker.js, and region.js Copies web assets into the destdir""" zoomlevel = self.p - configpath = os.path.join(util.get_program_path(), "config.js") + configpath = os.path.join(util.get_program_path(), "overviewerConfig.js") config = open(configpath, 'r').read() config = config.replace( @@ -108,7 +108,7 @@ class MapGen(object): self.quadtrees) config = config.replace("{maptypedata}", json.dumps(maptypedata)) - with open(os.path.join(self.destdir, "config.js"), 'w') as output: + with open(os.path.join(self.destdir, "overviewerConfig.js"), 'w') as output: output.write(config) bgcolor = (int(self.bg_color[1:3],16), int(self.bg_color[3:5],16), int(self.bg_color[5:7],16), 0) @@ -151,13 +151,13 @@ class MapGen(object): # write out the default marker table with open(os.path.join(self.destdir, "markers.js"), 'w') as output: - output.write("var markerData=[\n") + output.write("overviewer.collections.markerDatas.push([\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") + output.write("]);\n") # save persistent data self.world.persistentData['POI'] = self.world.POI @@ -166,11 +166,11 @@ class MapGen(object): # 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('overviewer.collections.regionDatas.push([\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('];') + output.write(']);') diff --git a/overviewerConfig.js b/overviewerConfig.js new file mode 100644 index 0000000..1ceb336 --- /dev/null +++ b/overviewerConfig.js @@ -0,0 +1,138 @@ +var overviewerConfig = { + /** + * These are things that will probably not need to be changed by the user, + * but are there because otherwise changing them is a giant PITA. + */ + 'CONST': { + /** + * Height and width of the tiles in pixels (I think). + */ + 'tileSize': 384, + /** + * Various images used for markers and stuff. + */ + 'image': { + 'defaultMarker': 'signpost.png', + 'signMarker': 'signpost_icon.png', + 'compass': 'compass.png', + 'spawnMarker': 'http://google-maps-icons.googlecode.com/files/home.png', + 'queryMarker': 'http://google-maps-icons.googlecode.com/files/regroup.png' + }, + 'mapDivId': 'mcmap', + 'regionStrokeWeight': 2 + }, + /** + * General map settings. + */ + 'map': { + /** + * Control the visibility of various controls. + */ + 'controls': { + /** + * Navigation controls are the pan and zoom typically on the upper + * left. + */ + 'navigation': true + }, + /** + * The zoom level when the page is loaded without a specific zoom setting + */ + 'defaultZoom': 0, + /** + * This controls how far you can zoom out. + */ + 'minZoom': {minzoom}, + /** + * This controls how close you can zoom in. + */ + 'maxZoom': {maxzoom}, + /** + * Center on this point, in world coordinates. Should be an array, ex: + * [0,0,0] + */ + 'center': {spawn_coords}, + /** + * Set this to tell browsers how long they should cache tiles in minutes. + */ + 'cacheMinutes': 0, + /** + * Set to true to turn on debug mode, which adds a grid to the map along + * with co-ordinates and a bunch of console output. + */ + 'debug': false, + }, + /** + * Group definitions for objects that are partially selectable (signs and + * regions). + */ + 'objectGroups': { + /* signs -- A list of signpost groups. A signpost can fall into zero, + * one, or more than one group. See below for some examples. + * + * Required: + * label : string. Displayed in the drop down menu control. + * match : function. Applied to each marker (from markers.js). It + * is returns true if the marker should be part + * of the group. + * + * Optional: + * checked : boolean. Set to true to have the group visible by default + * icon : string. Used to specify an icon url. + */ + 'signs': [ + //{label: "'To'", checked: false, match: function(s) {return s.msg.match(/to/)}}, + //{label: "Storage", match: function(s) {return s.msg.match(/storage/i) || s.msg.match(/dirt/i) || s.msg.match(/sand/)}}, + //{label: "Below Sealevel", match: function(s) { return s.y<64;}}, + //{label: "Info", match: function(s) { return s.msg.match("\\[info\\]");}, icon:"http://google-maps-icons.googlecode.com/files/info.png"}, + {'label':'All', 'match':function(sign){return true;}} + ], + /* regions -- A list of region groups. A region can fall into zero, + * one, or more than one group. See below for some examples. + * Regions have been designed to work with the WorldGuard Overviewer + * Region importer at @link https://github.com/pironic/WG2OvR but your + * host must support php in order to run WG2OvR. You can also continue + * to use any other region format. + * + * Required: + * label : string. Displayed in the drop down menu control. + * clickable : boolean. Will determine if we should generate an + * experimental info window that shows details + * about the clicked region. + * NOTE: if a region (as defined in region.js) + * does not have a label, this will default to + * false. + * match : function. Applied to each region (from region.js). It + * returns true if the region should be part of + * the group. + * + * Optional: + * checked : boolean. Set to true to have the group visible by default + */ + 'regions': [ + //{'label':'All','clickable':true,'match':function(region){return true;}} + ] + }, + /* mapTypes -- 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. + * Optional: + * base : string. Base of the url path for tile locations, useful + * for serving tiles from a different server than + * the js/html server. + * imgformat : string. File extension used for these tiles. Defaults to png. + * overlay : bool. If true, this tile set will be treated like an overlay + * Example: + * 'mapTypes': [ + * {'label': 'Day', 'path': 'lighting/tiles'}, + * {'label': 'Night', 'path': 'night/tiles', 'imgformat': 'jpg'}, + * {'label': 'Spawn', 'path': 'spawn/tiles', 'base': 'http://example.cdn.amazon.com/'}, + * {'label': 'Overlay', 'path': 'overlay/tiles', 'overlay': true} + * ] + */ + 'mapTypes': {maptypedata} +}; \ No newline at end of file diff --git a/quadtree.py b/quadtree.py index 58fef1b..701aa27 100644 --- a/quadtree.py +++ b/quadtree.py @@ -115,10 +115,10 @@ class QuadtreeGen(object): returns -1 if it couldn't be detected, file not found, or nothing in config.js matched """ - indexfile = os.path.join(self.destdir, "config.js") + indexfile = os.path.join(self.destdir, "overviewerConfig.js") if not os.path.exists(indexfile): return -1 - matcher = re.compile(r"maxZoom:\s*(\d+)") + matcher = re.compile(r"maxZoom.*:\s*(\d+)") p = -1 for line in open(indexfile, "r"): res = matcher.search(line) diff --git a/web_assets/functions.js b/web_assets/functions.js deleted file mode 100644 index 847fba9..0000000 --- a/web_assets/functions.js +++ /dev/null @@ -1,702 +0,0 @@ -// var def -var map; // god of the overviewer... bow before the google api. -var markerCollection = {}; // holds groups of markers -var markersInit = false; // only have to load the markers once, this just makes sure we only do it once -var regionCollection = {}; // holds groups of regions -var regionsInit = false; // only have to load the regions once, this just makes sure we only do it once - -var prevInfoWindow = null; - -// add a popup info window to the marker and then the marker to the map. -// marker is the clickable image on the map with all data. -// item is just the same item in the markers.js -function prepareSignMarker(marker, item) { - var c = "

" + item.msg.replace(/\n/g,"
") + "

"; - var infowindow = new google.maps.InfoWindow({content: c - }); - google.maps.event.addListener(marker, 'click', function() { - if (prevInfoWindow) - prevInfoWindow.close() - infowindow.open(map,marker); - prevInfoWindow = infowindow - }); -} - -// reusable function for making drop down menus. -// title = string -// items = array -function createDropDown(title, items) { - var control = document.createElement("DIV"); - control.id = "customControl"; // let's let a style sheet do most of the styling here - - var controlText = document.createElement("DIV"); - controlText.innerHTML = title; - - var controlBorder = document.createElement("DIV"); - controlBorder.id="top"; - control.appendChild(controlBorder); - controlBorder.appendChild(controlText); - - var dropdownDiv = document.createElement("DIV"); - dropdownDiv.id="dropDown"; - control.appendChild(dropdownDiv); - dropdownDiv.innerHTML=""; - - // add the functionality to toggle visibility of the items - $(controlText).click(function() { - $(dropdownDiv).toggle(); - }); - - // add that control box we've made back to the map. - map.controls[google.maps.ControlPosition.TOP_RIGHT].push(control); - - for (idx in items) { - // create the visible elements of the item - var item = items[idx]; - //console.log(item); // debug - var d = document.createElement("div"); - var n = document.createElement("input"); - n.type="checkbox"; - - // give it a name - $(n).data("label",item.label); - jQuery(n).click((function(local_idx, local_item) { - return function(e) { - item.action(local_idx, local_item, e.target.checked); - }; - })(idx, item)); - - // if its checked, its gotta do something, do that here. - if (item.checked) { - n.checked = true; - item.action(idx, item.label, item.checked); - } - dropdownDiv.appendChild(d); - d.appendChild(n) - var textNode = document.createElement("text"); - if(item.icon) { - textNode.innerHTML = "" + item.label + "
"; - } else { - textNode.innerHTML = item.label + "
"; - } - - d.appendChild(textNode); - } -} - -function HomeControl(controlDiv, map) { - - controlDiv.style.padding = '5px'; - - // Set CSS for the control border - var control = document.createElement('DIV'); - control.id='top'; - control.title = 'Click to center the map on the Spawn'; - controlDiv.appendChild(control); - - // Set CSS for the control interior - var controlText = document.createElement('DIV'); - controlText.innerHTML = 'Spawn'; - controlText.id='button'; - control.appendChild(controlText); - - // Setup the click event listeners: simply set the map to map center as definned below - google.maps.event.addDomListener(control, 'click', function() { - map.panTo(fromWorldToLatLng(config.center[0], - config.center[1], - config.center[2])); - }); - -} - - -// need to define the controls including the compass and layer controls. top right! -// input variables are for chumps... and reusable functions. this is neither. -function drawMapControls() { - - // viewstate link (little link to where you're looking at the map, normally bottom left) - var viewStateDiv = document.createElement('DIV'); - viewStateDiv.id="link"; - // add it to the map, bottom left. - map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(viewStateDiv); - - // compass rose, in the top right corner - var compassDiv = document.createElement('DIV'); - compassDiv.style.padding = '5px'; - var compassImg = document.createElement('IMG'); - compassImg.src="compass.png"; - compassDiv.appendChild(compassImg); - compassDiv.index = 0; - // add it to the map, top right. - map.controls[google.maps.ControlPosition.TOP_RIGHT].push(compassDiv); - - // Spawn button - var homeControlDiv = document.createElement('DIV'); - var homeControl = new HomeControl(homeControlDiv, map); - homeControlDiv.id = "customControl"; - homeControlDiv.index = 1; - map.controls[google.maps.ControlPosition.TOP_RIGHT].push(homeControlDiv); - - - // only need to create the control if there are items in the list. as definned in config.js - if (signGroups.length > 0) { - // signpost display control - - var items = []; - for (idx in signGroups) { - var signGroup = signGroups[idx]; - var iconURL = signGroup.icon; - if (!iconURL) { iconURL = 'signpost.png'; } - items.push({ - "label": signGroup.label, - "checked": signGroup.checked, - "icon": iconURL, - "action": function(n, item, checked) { - jQuery.each(markerCollection[item.label], function(i,elem) { - elem.setVisible(checked); - }); - //alert(item.label); - } - }); - } - createDropDown("Signposts", items); - } - - // if there are any regions data, lets show the option to hide/show them. - if (regionGroups.length > 0) { - // region display control - - var items = []; - for (idx in regionGroups) { - var regionGroup = regionGroups[idx]; - items.push({ - "label": regionGroup.label, - "checked": regionGroup.checked, - "action": function(n, item, checked) { - jQuery.each(regionCollection[item.label], function(i,elem) { - elem.setMap(checked ? map : null); // Thanks to LeastWeasel for this line! - }); - } - }); - } - createDropDown("Regions", items); - } - - if (overlayMapTypes.length > 0) { - // overlay maps control - - var items = []; - for (idx in overlayMapTypes) { - var overlay = overlayMapTypes[idx]; - items.push({"label": overlay.name, "checked": false, "overlay": overlay, - "action": function(i, item, checked) { - if (checked) { - map.overlayMapTypes.push(item.overlay); - } else { - var idx_to_delete = -1; - map.overlayMapTypes.forEach(function(e, j) { - if (e == item.overlay) { idx_to_delete = j; } - }); - if (idx_to_delete >= 0) { - map.overlayMapTypes.removeAt(idx_to_delete); - } - } - }}); - } - createDropDown("Overlays", items); - } -} - -// will be recoded by pi, currently always displays all regions all the time. -// parse the data as definned in the regions.js -function initRegions() { - if (regionsInit) { return; } - if (typeof(regionData) == "undefined") { return; } // skip this if we have no region.js file - regionsInit = true; - - for (i in regionGroups) { - regionCollection[regionGroups[i].label] = []; - } - - for (i in regionData) { - var region = regionData[i]; - - // pull all the points out of the regions file. - var converted = new google.maps.MVCArray(); - var infoPoint = ""; - for (j in region.path) { - var point = region.path[j]; - converted.push(fromWorldToLatLng(point.x, point.y, point.z)); - - } - - for (idx in regionGroups) { - var regionGroup = regionGroups[idx]; - var testfunc = regionGroup.match; - var clickable = regionGroup.clickable - var label = regionGroup.label; - - if(region.label) { - var name = region.label - } else { - var name = 'rawr'; - clickable = false; // if it doesn't have a name, we dont have to show it. - } - - if (region.closed) { - var shape = new google.maps.Polygon({ - name: name, - clickable: clickable, - geodesic: false, - map: null, - strokeColor: region.color, - strokeOpacity: region.opacity, - strokeWeight: 2, - fillColor: region.color, - fillOpacity: region.opacity * 0.25, - zIndex: i, - paths: converted - }); - } else { - var shape = new google.maps.Polyline({ - name: name, - clickable: clickable, - geodesic: false, - map: null, - strokeColor: region.color, - strokeOpacity: region.opacity, - strokeWeight: 2, - zIndex: i, - path: converted - }); - } - regionCollection[label].push(shape); - - if (clickable) { - // add the region infowindow popup - infowindow = new google.maps.InfoWindow(); - google.maps.event.addListener(shape, 'click', function(e,i) { - - var contentString = "Region: "+this.name+"
"; - contentString += "Clicked Location:
" + e.latLng.lat() + "," + e.latLng.lng() + "
"; - - // Replace our Info Window's content and position - infowindow.setContent(contentString); - infowindow.setPosition(e.latLng); - - infowindow.open(map); - - }); - } - } - } -} - -// will initalize all the markers data as found in markers.js -// may need to be reviewed by agrif or someone else... little finicky right now. -function initMarkers() { - if (markersInit) { return; } // oh, we've already done this? nevermind, exit the function. - if (typeof(markerData) == "undefined") { return; } // no markers.js file, so skip this. - markersInit = true; // now that we've started, dont have to do it twice. - - // first, give all collections an empty array to work with - for (i in signGroups) { - markerCollection[signGroups[i].label] = []; - } - - - for (i in markerData) { - var item = markerData[i]; - - // a default: - var iconURL = ''; - if (item.type == 'spawn') { - // don't filter spawn, always display - - iconURL = 'http://google-maps-icons.googlecode.com/files/home.png'; - var converted = fromWorldToLatLng(item.x, item.y, item.z); - var marker = new google.maps.Marker({position: converted, - map: map, - title: jQuery.trim(item.msg), - icon: iconURL - }); - continue; - } - - if (item.type == 'querypos') { - // Set on page load if MC x/y/z coords are given in the query string - - iconURL = 'http://google-maps-icons.googlecode.com/files/regroup.png'; - var converted = fromWorldToLatLng(item.x, item.y, item.z); - var marker = new google.maps.Marker({position: converted, - map: map, - title: jQuery.trim(item.msg), - icon: iconURL - }); - - continue; - } - - var matched = false; - for (idx in signGroups) { - var signGroup = signGroups[idx]; - var testfunc = signGroup.match; - var label = signGroup.label; - - if (testfunc(item)) { - matched = true; - - // can add custom types of images for externally definned item types, like 'command' here. - if (item.type == 'sign') { iconURL = 'signpost_icon.png'; } - - //console.log(signGroup.icon); //debug - if (signGroup.icon) { iconURL = signGroup.icon; } - - var converted = fromWorldToLatLng(item.x, item.y, item.z); - var marker = new google.maps.Marker({position: converted, - map: map, - title: jQuery.trim(item.msg), - icon: iconURL, - visible: false - }); - - markerCollection[label].push(marker); - - if (item.type == 'sign') { - prepareSignMarker(marker, item); - } - } - } - - if (!matched) { - // is this signpost doesn't match any of the groups in config.js, add it automatically to the "__others__" group - if (item.type == 'sign') { iconURL = 'signpost_icon.png';} - - var converted = fromWorldToLatLng(item.x, item.y, item.z); - var marker = new google.maps.Marker({position: converted, - map: map, - title: jQuery.trim(item.msg), - icon: iconURL, - visible: false - }); - if (markerCollection["__others__"]) { - markerCollection["__others__"].push(marker); - } else { - markerCollection["__others__"] = [marker]; - } - - if (item.type == 'sign') { - prepareSignMarker(marker, item); - } - } - - - - } -} - -// update the link in the viewstate. -function makeLink() { - var displayZoom = map.getZoom(); - if (displayZoom == config.maxZoom) { - displayZoom = "max"; - } else { - displayZoom -= config.maxZoom; - } - var xyz; - var xyz = fromLatLngToWorld(map.getCenter().lat(), map.getCenter().lng()); - var a=location.href.substring(0,location.href.lastIndexOf(location.search)) - + "?x=" + Math.floor(xyz.x) - + "&y=" + Math.floor(xyz.y) - + "&z=" + Math.floor(xyz.z) - + "&zoom=" + displayZoom; - document.getElementById("link").innerHTML = a; -} - -// load the map up and add all the functions relevant stuff to the map. -function initialize() { - - var query = location.search.substring(1); - - var defaultCenter = fromWorldToLatLng(config.center[0], - config.center[1], - config.center[2]); - var lat = defaultCenter.lat(); - var lng = defaultCenter.lng(); - - var zoom = config.defaultZoom; - var hasquerypos = false; - var queryx = 0; - var queryy = 64; - var queryz = 0; - var mapcenter; - var pairs = query.split("&"); - for (var i=0; i 1) { - mapTyepControlToggle = true - } - var mapOptions = { - zoom: zoom, - center: mapcenter, - navigationControl: true, - scaleControl: false, - mapTypeControl: mapTyepControlToggle, - mapTypeControlOptions: { - mapTypeIds: mapTypeIds - }, - mapTypeId: mapTypeIdDefault, - streetViewControl: false, - }; - map = new google.maps.Map(document.getElementById('mcmap'), mapOptions); - - if(config.debug) { - map.overlayMapTypes.insertAt(0, new CoordMapType(new google.maps.Size(config.tileSize, config.tileSize))); - - google.maps.event.addListener(map, 'click', function(event) { - //console.log("latLng; " + event.latLng.lat() + ", " + event.latLng.lng()); - - var pnt = map.getProjection().fromLatLngToPoint(event.latLng); - //console.log("point: " + pnt); - - var pxx = pnt.x * config.tileSize * Math.pow(2, config.maxZoom); - var pxy = pnt.y * config.tileSize * Math.pow(2, config.maxZoom); - //console.log("pixel: " + pxx + ", " + pxy); - }); - } - - // Now attach the coordinate map type to the map's registry - for (idx in MCMapType) { - map.mapTypes.set('mcmap' + MCMapType[idx].name, MCMapType[idx]); - } - - // initialize the markers and regions - initMarkers(); - initRegions(); - drawMapControls(); - - //makeLink(); - - // Make the link again whenever the map changes - google.maps.event.addListener(map, 'zoom_changed', function() { - makeLink(); - }); - google.maps.event.addListener(map, 'center_changed', function() { - makeLink(); - }); - google.maps.event.addListener(map, 'maptypeid_changed', function() { - var newType = map.getMapTypeId(); - for(i in mapTypeData) { - if( 'mcmap' + mapTypeData[i].label == newType ) { - $('#mcmap').css('background-color', mapTypeData[i].bg_color); - break; - } - } - }); - // We can now set the map to use the 'coordinate' map type - map.setMapTypeId(mapTypeIdDefault); -} - - -// our custom projection maps Latitude to Y, and Longitude to X as normal, -// but it maps the range [0.0, 1.0] to [0, tileSize] in both directions -// so it is easier to position markers, etc. based on their position -// (find their position in the lowest-zoom image, and divide by tileSize) -function MCMapProjection() { - this.inverseTileSize = 1.0 / config.tileSize; -} - -MCMapProjection.prototype.fromLatLngToPoint = function(latLng) { - var x = latLng.lng() * config.tileSize; - var y = latLng.lat() * config.tileSize; - return new google.maps.Point(x, y); -}; - -MCMapProjection.prototype.fromPointToLatLng = function(point) { - var lng = point.x * this.inverseTileSize; - var lat = point.y * this.inverseTileSize; - return new google.maps.LatLng(lat, lng); -}; - -// helper to get map LatLng from world coordinates -// takes arguments in X, Y, Z order -// (arguments are *out of order*, because within the function we use -// the axes like the rest of Minecraft Overviewer -- with the Z and Y -// flipped from normal minecraft usage.) -function fromWorldToLatLng(x, z, y) -{ - // the width and height of all the highest-zoom tiles combined, inverted - var perPixel = 1.0 / (config.tileSize * Math.pow(2, config.maxZoom)); - - // This information about where the center column is may change with a different - // drawing implementation -- check it again after any drawing overhauls! - - // point (0, 0, 127) is at (0.5, 0.0) of tile (tiles/2 - 1, tiles/2) - // so the Y coordinate is at 0.5, and the X is at 0.5 - ((tileSize / 2) / (tileSize * 2^maxZoom)) - // or equivalently, 0.5 - (1 / 2^(maxZoom + 1)) - var lng = 0.5 - (1.0 / Math.pow(2, config.maxZoom + 1)); - var lat = 0.5; - - // the following metrics mimic those in ChunkRenderer.chunk_render in "chunk.py" - // or, equivalently, chunk_render in src/iterate.c - - // each block on X axis adds 12px to x and subtracts 6px from y - lng += 12 * x * perPixel; - lat -= 6 * x * perPixel; - - // each block on Y axis adds 12px to x and adds 6px to y - lng += 12 * y * perPixel; - lat += 6 * y * perPixel; - - // each block down along Z adds 12px to y - lat += 12 * (128 - z) * perPixel; - - // add on 12 px to the X coordinate to center our point - lng += 12 * perPixel; - - return new google.maps.LatLng(lat, lng); -} - -// NOTE: X, Y and Z in this function are Minecraft world definitions -// (that is, X is horizontal, Y is altitude and Z is vertical). -function fromLatLngToWorld(lat, lng) -{ - // Initialize world x/y/z object to be returned - var xyz = Array(); - xyz.x = 0; - xyz.y = 64; - xyz.z = 0; - - // the width and height of all the highest-zoom tiles combined, inverted - var perPixel = 1.0 / (config.tileSize * Math.pow(2, config.maxZoom)); - - // Revert base positioning - // See equivalent code in fromWorldToLatLng() - lng -= 0.5 - (1.0 / Math.pow(2, config.maxZoom + 1)); - lat -= 0.5; - - // I'll admit, I plugged this into Wolfram Alpha: - // a = (x * 12 * r) + (z * 12 * r), b = (z * 6 * r) - (x * 6 * r) - // And I don't know the math behind solving for for X and Z given - // A (lng) and B (lat). But Wolfram Alpha did. :) I'd welcome - // suggestions for splitting this up into long form and documenting - // it. -RF - xyz.x = (lng - 2 * lat) / (24 * perPixel) - xyz.z = (lng + 2 * lat) / (24 * perPixel) - - // Adjust for the fact that we we can't figure out what Y is given - // only latitude and longitude, so assume Y=64. - xyz.x += 64 + 1; - xyz.z -= 64 + 2; - - return xyz; -} - -function getTileUrlGenerator(path, path_base, path_ext) { - return function(tile, zoom) { - var url = path; - var url_base = ( path_base ? path_base : '' ); - if(tile.x < 0 || tile.x >= Math.pow(2, zoom) || tile.y < 0 || tile.y >= Math.pow(2, zoom)) { - url += '/blank'; - } else if(zoom == 0) { - url += '/base'; - } else { - for(var z = zoom - 1; z >= 0; --z) { - var x = Math.floor(tile.x / Math.pow(2, z)) % 2; - var y = Math.floor(tile.y / Math.pow(2, z)) % 2; - url += '/' + (x + 2 * y); - } - } - url = url + '.' + path_ext; - if(config.cacheMinutes > 0) { - var d = new Date(); - url += '?c=' + Math.floor(d.getTime() / (1000 * 60 * config.cacheMinutes)); - } - return(url_base + url); - } -} - -var MCMapOptions = new Array; -var MCMapType = new Array; -var mapTypeIdDefault = null; -var mapTypeIds = []; -var overlayMapTypes = []; -for (idx in mapTypeData) { - var view = mapTypeData[idx]; - var imgformat = view.imgformat ? view.imgformat : 'png'; - - MCMapOptions[view.label] = { - getTileUrl: getTileUrlGenerator(view.path, view.base, imgformat), - tileSize: new google.maps.Size(config.tileSize, config.tileSize), - maxZoom: config.maxZoom, - minZoom: config.minZoom, - isPng: !(imgformat.match(/^png$/i) == null) - }; - - MCMapType[view.label] = new google.maps.ImageMapType(MCMapOptions[view.label]); - MCMapType[view.label].name = view.label; - MCMapType[view.label].alt = "Minecraft " + view.label + " Map"; - MCMapType[view.label].projection = new MCMapProjection(); - - if (view.overlay) { - overlayMapTypes.push(MCMapType[view.label]); - } else { - if (mapTypeIdDefault == null) { - mapTypeIdDefault = 'mcmap' + view.label; - } - mapTypeIds.push('mcmap' + view.label); - } -} - -function CoordMapType() { -} - -function CoordMapType(tileSize) { - this.tileSize = tileSize; -} - -CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) { - var div = ownerDocument.createElement('DIV'); - div.innerHTML = "(" + coord.x + ", " + coord.y + ", " + zoom + ")"; - div.innerHTML += "
"; - div.innerHTML += MCMapOptions.getTileUrl(coord, zoom); - div.style.width = this.tileSize.width + 'px'; - div.style.height = this.tileSize.height + 'px'; - div.style.fontSize = '10'; - div.style.borderStyle = 'solid'; - div.style.borderWidth = '1px'; - div.style.borderColor = '#AAAAAA'; - return div; -}; diff --git a/web_assets/overviewer.js b/web_assets/overviewer.js index 4b0d986..a298bf0 100644 --- a/web_assets/overviewer.js +++ b/web_assets/overviewer.js @@ -1,16 +1,56 @@ var overviewer = { + /** + * This holds the map, probably the most important var in this file + */ 'map': null, + /** + * These are collections of data used in various places + */ 'collections': { + /** + * A list of lists of raw marker data objects, this will allow for an + * arbitrary number of marker data sources. This replaces the old + * markerData var from markers.js. Now you can add markers by including + * a file with: + * overviewer.collections.markerDatas.push([]); + */ 'markerDatas': [], + /** + * The actual Marker objects are stored here. + */ 'markers': {}, + /** + * Same as markerDatas, list of lists of raw region objects. + */ 'regionDatas': [], + /** + * The actual Region objects. + */ 'regions': {}, + /** + * Overlay mapTypes (like Spawn) will go in here. + */ 'overlays': [], + /** + * MapTypes that aren't overlays will end up in here. + */ 'mapTypes': {}, + /** + * The mapType names are in here. + */ 'mapTypeIds': [], + /** + * This is the current infoWindow object, we keep track of it so that + * there is only one open at a time. + */ 'infoWindow': null }, 'util': { + /** + * General initialization function, called when the page is loaded. + * Probably shouldn't need changing unless some very different kind of new + * feature gets added. + */ 'initialize': function() { overviewer.util.initializeClassPrototypes(); overviewer.util.initializeMapTypes(); @@ -19,6 +59,11 @@ var overviewer = { overviewer.util.initializeRegions(); overviewer.util.createMapControls(); }, + /** + * This adds some methods to these classes because Javascript is stupid + * and this seems like the best way to avoid re-creating the same methods + * on each object at object creation time. + */ 'initializeClassPrototypes': function() { overviewer.classes.MapProjection.prototype.fromLatLngToPoint = function(latLng) { var x = latLng.lng() * overviewerConfig.CONST.tileSize; @@ -34,9 +79,14 @@ var overviewer = { overviewer.classes.CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) { var div = ownerDocument.createElement('DIV'); - div.innerHTML = '(' + coord.x + ', ' + coord.y + ', ' + zoom + ')'; - div.innerHTML += '
'; + div.innerHTML = '(' + coord.x + ', ' + coord.y + ', ' + zoom + + ')' + '
'; + //TODO: figure out how to get the current mapType, I think this + //will add the maptile url to the grid thing once it works + //div.innerHTML += overviewer.collections.mapTypes[0].getTileUrl(coord, zoom); + + //this should probably just have a css class div.style.width = this.tileSize.width + 'px'; div.style.height = this.tileSize.height + 'px'; div.style.fontSize = '10px'; @@ -47,8 +97,8 @@ var overviewer = { }; }, /** - * I think this was old code that was replaced by stuff that is now - * in initializeMap() + * Setup the varous mapTypes before we actually create the map. This used + * to be a bunch of crap down at the bottom of functions.js */ 'initializeMapTypes': function() { var mapOptions = {}; @@ -81,6 +131,12 @@ var overviewer = { } } }, + /** + * This is where the magic happens. We setup the map with all it's + * options. The query string is also parsed here so we can know if + * we should be looking at a particular point on the map or just use + * the default view. + */ 'initializeMap': function() { var defaultCenter = overviewer.util.fromWorldToLatLng( overviewerConfig.map.center[0], overviewerConfig.map.center[1], @@ -103,7 +159,7 @@ var overviewer = { zoom = overviewerConfig.map.minZoom; } else { zoom = parseInt(queryParams.zoom); - if (zoom < 0 && zoom + overvierConfig.map.maxZoom >= 0) { + if (zoom < 0 && zoom + overviewerConfig.map.maxZoom >= 0) { //if zoom is negative, try to treat as "zoom out from max zoom" zoom += overviewerConfig.map.maxZoom; } else { @@ -187,6 +243,12 @@ var overviewer = { // We can now set the map to use the 'coordinate' map type overviewer.map.setMapTypeId(overviewer.util.getDefaultMapTypeId()); }, + /** + * Read through overviewer.collections.markerDatas and create Marker + * objects and stick them in overviewer.collections.markers . This + * should probably be done differently at some point so that we can + * support markers that change position more easily. + */ 'initializeMarkers': function() { //first, give all collections an empty array to work with for (i in overviewerConfig.objectGroups.signs) { @@ -283,6 +345,9 @@ var overviewer = { } } }, + /** + * Same as initializeMarkers() for the most part. + */ 'initializeRegions': function() { for (i in overviewerConfig.objectGroups.regions) { overviewer.collections.regions[overviewerConfig.objectGroups.regions[i].label] = []; @@ -347,11 +412,22 @@ var overviewer = { } } }, + /** + * Gee, I wonder what this does. + * + * @param string msg + */ 'debug': function(msg) { if (overviewerConfig.map.debug) { console.log(msg); } }, + /** + * Simple helper function to split the query string into key/value + * pairs. Doesn't do any type conversion but both are lowercase'd. + * + * @return Object + */ 'parseQueryString': function() { var results = {}; var queryString = location.search.substring(1); @@ -365,6 +441,10 @@ var overviewer = { } return results; }, + /** + * Set the link (at the bottom of the screen) to the current view. + * TODO: make this preserve the mapTypeId as well + */ 'setViewUrl': function() { var displayZoom = overviewer.map.getZoom(); if (displayZoom == overviewerConfig.map.maxZoom) { @@ -387,6 +467,18 @@ var overviewer = { 'getDefaultMapTypeId': function() { return overviewer.collections.mapTypeIds[0]; }, + /** + * helper to get map LatLng from world coordinates takes arguments in + * X, Y, Z order (arguments are *out of order*, because within the + * function we use the axes like the rest of Minecraft Overviewer -- + * with the Z and Y flipped from normal minecraft usage.) + * + * @param int x + * @param int z + * @param int y + * + * @return google.maps.LatLng + */ 'fromWorldToLatLng': function(x, z, y) { // the width and height of all the highest-zoom tiles combined, // inverted @@ -423,6 +515,16 @@ var overviewer = { return new google.maps.LatLng(lat, lng); }, + /** + * The opposite of fromWorldToLatLng + * NOTE: X, Y and Z in this function are Minecraft world definitions + * (that is, X is horizontal, Y is altitude and Z is vertical). + * + * @param float lat + * @param float lng + * + * @return Array + */ 'fromLatLngToWorld': function(lat, lng) { // Initialize world x/y/z object to be returned var point = Array(); @@ -456,6 +558,10 @@ var overviewer = { return point; }, + /** + * Create and draw the various map controls and other related things + * like the compass, current view link, etc. + */ 'createMapControls': function() { // viewstate link (little link to where you're looking at the map, // normally bottom left) @@ -559,6 +665,12 @@ var overviewer = { overviewer.util.createDropDown('Overlays', items); } }, + /** + * Reusable method for creating drop-down menus + * + * @param string title + * @param array items + */ 'createDropDown': function(title, items) { var control = document.createElement('DIV'); // let's let a style sheet do most of the styling here @@ -619,6 +731,13 @@ var overviewer = { itemDiv.appendChild(textNode); } }, + /** + * Create the pop-up infobox for when you click on a region, this can't + * be done in-line because of stupid Javascript scoping problems with + * closures or something. + * + * @param google.maps.Polygon|google.maps.Polyline shape + */ 'createRegionInfoWindow': function(shape) { var infowindow = new google.maps.InfoWindow(); google.maps.event.addListener(shape, 'click', function(event, i) { @@ -635,6 +754,11 @@ var overviewer = { overviewer.collections.infoWindow = infowindow; }); }, + /** + * Same as createRegionInfoWindow() + * + * @param google.maps.Marker marker + */ 'createMarkerInfoWindow': function(marker) { var windowContent = '

' + marker.title.replace(/\n/g,'
') + '

'; @@ -650,7 +774,16 @@ var overviewer = { }); } }, + /** + * The various classes needed in this file. + */ 'classes': { + /** + * This is the button that centers the map on spawn. Not sure why we + * need a separate class for this and not some of the other controls. + * + * @param documentElement controlDiv + */ 'HomeControl': function(controlDiv) { controlDiv.style.padding = '5px'; // Set CSS for the control border @@ -674,15 +807,43 @@ var overviewer = { overviewerConfig.map.center[2])); }); }, + /** + * Our custom projection maps Latitude to Y, and Longitude to X as + * normal, but it maps the range [0.0, 1.0] to [0, tileSize] in both + * directions so it is easier to position markers, etc. based on their + * position (find their position in the lowest-zoom image, and divide + * by tileSize) + */ 'MapProjection' : function() { this.inverseTileSize = 1.0 / overviewerConfig.CONST.tileSize; }, - //Looks like this is only used for debugging + /** + * This is a mapType used only for debugging, to draw a grid on the screen + * showing the tile co-ordinates and tile path. Currently the tile path + * part does not work. + * + * @param google.maps.Size tileSize + */ 'CoordMapType': function(tileSize) { this.tileSize = tileSize; } }, + /** + * Stuff that we give to the google maps code instead of using ourselves + * goes in here. + * + * Also, why do I keep writing these comments as if I'm multiple people? I + * should probably stop that. + */ 'gmap': { + /** + * Generate a function to get the path to a tile at a particular location + * and zoom level. + * + * @param string path + * @param string pathBase + * @param string pathExt + */ 'getTileUrlGenerator': function(path, pathBase, pathExt) { return function(tile, zoom) { var url = path; diff --git a/web_assets/overviewerConfig.js b/web_assets/overviewerConfig.js deleted file mode 100644 index 841841e..0000000 --- a/web_assets/overviewerConfig.js +++ /dev/null @@ -1,46 +0,0 @@ -var overviewerConfig = { - //These will probably never change - 'CONST': { - 'tileSize': 384, - 'image': { - 'defaultMarker': 'signpost.png', - 'signMarker': 'signpost_icon.png', - 'compass': 'compass.png', - 'spawnMarker': 'http://google-maps-icons.googlecode.com/files/home.png', - 'queryMarker': 'http://google-maps-icons.googlecode.com/files/regroup.png' - }, - 'mapDivId': 'mcmap', - 'regionStrokeWeight': 2 - }, - 'map': { - 'controls': { - 'navigation': true - }, - 'defaultZoom': 0, - 'minZoom': {minzoom}, - 'maxZoom': {maxzoom}, - 'center': {spawn_coords}, - 'cacheMinutes': 0, - 'debug': false, - }, - 'objectGroups': { - 'signs': [ - { - 'label': 'All', - 'match': function(sign) { - return true; - } - } - ], - 'regions': [ - { - 'label': 'All', - 'clickable':true, - 'match': function(region) { - return true; - } - } - ] - }, - 'mapTypes': {maptypedata} -}; From 219fa3e7a975a1887be5327e1c417f479f794158 Mon Sep 17 00:00:00 2001 From: Alex Headley Date: Sat, 23 Apr 2011 23:36:29 -0400 Subject: [PATCH 51/78] fixed remaining known bugs made zoom/pan controls independently toggle-able re-added markers.js and regions.js to index.html fixed adding marker from query string fixed initial bg_color setting --- overviewerConfig.js | 11 +++++---- web_assets/index.html | 2 ++ web_assets/overviewer.js | 49 +++++++++++++++++++++++++--------------- 3 files changed, 40 insertions(+), 22 deletions(-) diff --git a/overviewerConfig.js b/overviewerConfig.js index 1ceb336..8b34a0f 100644 --- a/overviewerConfig.js +++ b/overviewerConfig.js @@ -30,10 +30,13 @@ var overviewerConfig = { */ 'controls': { /** - * Navigation controls are the pan and zoom typically on the upper - * left. + * Pan control is the hand with the arrows around it in the upper left. */ - 'navigation': true + 'pan': true, + /** + * Zoom control is the zoom slider bar in the upper left. + */ + 'zoom': true }, /** * The zoom level when the page is loaded without a specific zoom setting @@ -135,4 +138,4 @@ var overviewerConfig = { * ] */ 'mapTypes': {maptypedata} -}; \ No newline at end of file +}; diff --git a/web_assets/index.html b/web_assets/index.html index 14c6666..b3cb596 100644 --- a/web_assets/index.html +++ b/web_assets/index.html @@ -7,6 +7,8 @@ + + diff --git a/web_assets/overviewer.js b/web_assets/overviewer.js index a298bf0..37b465b 100644 --- a/web_assets/overviewer.js +++ b/web_assets/overviewer.js @@ -172,27 +172,30 @@ var overviewer = { mapcenter = overviewer.util.fromWorldToLatLng(queryParams.x, queryParams.y, queryParams.z); // Add a market indicating the user-supplied position - overviewer.collections.markers.push({ + overviewer.collections.markerDatas.push([{ 'msg': 'Coordinates ' + queryParams.x + ', ' + queryParams.y + ', ' + queryParams.z, 'y': parseFloat(queryParams.y), 'x': parseFloat(queryParams.x), 'z': parseFloat(queryParams.z), - 'type': 'querypos'}); + 'type': 'querypos'}]); } else { mapcenter = new google.maps.LatLng(lat, lng); } var mapOptions = { - zoom: zoom, - center: mapcenter, - navigationControl: overviewerConfig.map.controls.navigation, - scaleControl: false, - mapTypeControl: overviewer.collections.mapTypeIds.length > 1, + zoom: zoom, + center: mapcenter, + panControl: overviewerConfig.map.controls.pan, + scaleControl: false, + mapTypeControl: overviewer.collections.mapTypeIds.length > 1, mapTypeControlOptions: { mapTypeIds: overviewer.collections.mapTypeIds }, - mapTypeId: overviewer.util.getDefaultMapTypeId(), - streetViewControl: false + mapTypeId: overviewer.util.getDefaultMapTypeId(), + streetViewControl: false, + zoomControl: overviewerConfig.map.controls.zoom, + backgroundColor: overviewer.util.getMapTypeBackgroundColor( + overviewer.util.getDefaultMapTypeId()) }; overviewer.map = new google.maps.Map(document.getElementById( overviewerConfig.CONST.mapDivId), mapOptions); @@ -230,15 +233,9 @@ var overviewer = { overviewer.util.setViewUrl(); }); google.maps.event.addListener(overviewer.map, 'maptypeid_changed', function() { - var newType = overviewer.map.getMapTypeId(); - for(i in overviewerConfig.mapTypes) { - if( overviewerConfig.CONST.mapDivId + - overviewerConfig.mapTypes[i].label == newType ) { - $('#'+overviewerConfig.CONST.mapDivId).css( - 'background-color', overviewerConfig.mapTypes[i].bg_color); - break; - } - } + $('#'+overviewerConfig.CONST.mapDivId).css( + 'background-color', overviewer.util.getMapTypeBackgroundColor( + overviewer.map.getMapTypeId())); }); // We can now set the map to use the 'coordinate' map type overviewer.map.setMapTypeId(overviewer.util.getDefaultMapTypeId()); @@ -412,6 +409,22 @@ var overviewer = { } } }, + /** + * Change the map's div's background color according to the mapType's bg_color setting + * + * @param string mapTypeId + * @return string + */ + 'getMapTypeBackgroundColor': function(mapTypeId) { + for(i in overviewerConfig.mapTypes) { + if( overviewerConfig.CONST.mapDivId + + overviewerConfig.mapTypes[i].label == mapTypeId ) { + overviewer.util.debug('Found background color for: ' + + overviewerConfig.mapTypes[i].bg_color); + return overviewerConfig.mapTypes[i].bg_color; + } + } + }, /** * Gee, I wonder what this does. * From 4d76e106e0c39d875594df95641ac473b73f4daa Mon Sep 17 00:00:00 2001 From: Alex Headley Date: Sun, 24 Apr 2011 00:37:37 -0400 Subject: [PATCH 52/78] added some more toggle-able controls --- overviewerConfig.js | 18 +++++++++++++++++- web_assets/overviewer.js | 27 +++++++++++++++++---------- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/overviewerConfig.js b/overviewerConfig.js index 8b34a0f..fd12c49 100644 --- a/overviewerConfig.js +++ b/overviewerConfig.js @@ -36,7 +36,23 @@ var overviewerConfig = { /** * Zoom control is the zoom slider bar in the upper left. */ - 'zoom': true + 'zoom': true, + /** + * Spawn control is the "Spawn" button that centers the map on spawn. + */ + 'spawn': true, + /** + * The compass in the upper right. + */ + 'compass': true, + /** + * The mapType control is the slider for selecting different map types. + */ + 'mapType': true, + /** + * The small box at the bottom that displays the link to the current map view. + */ + 'link': true }, /** * The zoom level when the page is loaded without a specific zoom setting diff --git a/web_assets/overviewer.js b/web_assets/overviewer.js index 37b465b..f927625 100644 --- a/web_assets/overviewer.js +++ b/web_assets/overviewer.js @@ -187,7 +187,8 @@ var overviewer = { center: mapcenter, panControl: overviewerConfig.map.controls.pan, scaleControl: false, - mapTypeControl: overviewer.collections.mapTypeIds.length > 1, + mapTypeControl: overviewerConfig.map.controls.mapType && + overviewer.collections.mapTypeIds.length > 1, mapTypeControlOptions: { mapTypeIds: overviewer.collections.mapTypeIds }, @@ -226,12 +227,6 @@ var overviewer = { } // Make the link again whenever the map changes - google.maps.event.addListener(overviewer.map, 'zoom_changed', function() { - overviewer.util.setViewUrl(); - }); - google.maps.event.addListener(overviewer.map, 'center_changed', function() { - overviewer.util.setViewUrl(); - }); google.maps.event.addListener(overviewer.map, 'maptypeid_changed', function() { $('#'+overviewerConfig.CONST.mapDivId).css( 'background-color', overviewer.util.getMapTypeBackgroundColor( @@ -581,7 +576,15 @@ var overviewer = { var viewStateDiv = document.createElement('DIV'); viewStateDiv.id='link'; // add it to the map, bottom left. - overviewer.map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(viewStateDiv); + if (overviewerConfig.map.controls.link) { + google.maps.event.addListener(overviewer.map, 'zoom_changed', function() { + overviewer.util.setViewUrl(); + }); + google.maps.event.addListener(overviewer.map, 'center_changed', function() { + overviewer.util.setViewUrl(); + }); + overviewer.map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(viewStateDiv); + } // compass rose, in the top right corner var compassDiv = document.createElement('DIV'); @@ -591,14 +594,18 @@ var overviewer = { compassDiv.appendChild(compassImg); compassDiv.index = 0; // add it to the map, top right. - overviewer.map.controls[google.maps.ControlPosition.TOP_RIGHT].push(compassDiv); + if (overviewerConfig.map.controls.compass) { + overviewer.map.controls[google.maps.ControlPosition.TOP_RIGHT].push(compassDiv); + } // Spawn button var homeControlDiv = document.createElement('DIV'); var homeControl = new overviewer.classes.HomeControl(homeControlDiv); homeControlDiv.id = 'customControl'; homeControlDiv.index = 1; - overviewer.map.controls[google.maps.ControlPosition.TOP_RIGHT].push(homeControlDiv); + if (overviewerConfig.map.controls.spawn) { + overviewer.map.controls[google.maps.ControlPosition.TOP_RIGHT].push(homeControlDiv); + } // only need to create the control if there are items in the list. // as defined in config.js From b44df77405b4883bc0a9b5be9ca33b60b7121564 Mon Sep 17 00:00:00 2001 From: aheadley Date: Mon, 25 Apr 2011 17:02:04 -0400 Subject: [PATCH 53/78] renamed style.css to be consistent with overviewer.js --- web_assets/index.html | 2 +- web_assets/{style.css => overviewer.css} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename web_assets/{style.css => overviewer.css} (100%) diff --git a/web_assets/index.html b/web_assets/index.html index b3cb596..3798f17 100644 --- a/web_assets/index.html +++ b/web_assets/index.html @@ -2,7 +2,7 @@ - + diff --git a/web_assets/style.css b/web_assets/overviewer.css similarity index 100% rename from web_assets/style.css rename to web_assets/overviewer.css From be720c5e0d786c8ff3bf681c5ef2553fadac3d28 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Thu, 28 Apr 2011 15:03:59 +0200 Subject: [PATCH 54/78] Use ANTIALIAS filter for resizing down images. Ajust the position of fences for the new filter. --- textures.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/textures.py b/textures.py index ac214b5..567942a 100644 --- a/textures.py +++ b/textures.py @@ -123,12 +123,12 @@ def transform_image(img, blockID=None): if blockID in (81,92): # cacti and cake # Resize to 15x15, since the cactus and the cake textures are a little smaller than the other textures - img = img.resize((15, 15), Image.BILINEAR) + img = img.resize((15, 15), Image.ANTIALIAS) else: # Resize to 17x17, since the diagonal is approximately 24 pixels, a nice # even number that can be split in half twice - img = img.resize((17, 17), Image.BILINEAR) + img = img.resize((17, 17), Image.ANTIALIAS) # Build the Affine transformation matrix for this perspective transform = numpy.matrix(numpy.identity(3)) @@ -168,7 +168,7 @@ def transform_image_side(img, blockID=None): img = n # Size of the cube side before shear - img = img.resize((12,12)) + img = img.resize((12,12), Image.ANTIALIAS) # Apply shear transform = numpy.matrix(numpy.identity(3)) @@ -184,7 +184,7 @@ def transform_image_slope(img, blockID=None): in the -y direction (reflect for +x direction). Used for minetracks""" # Take the same size as trasform_image_side - img = img.resize((12,12)) + img = img.resize((12,12), Image.ANTIALIAS) # Apply shear transform = numpy.matrix(numpy.identity(3)) @@ -1066,9 +1066,9 @@ def generate_special_texture(blockID, data): # Compose the fence big stick fence_big = Image.new("RGBA", (24,24), (38,92,255,0)) - composite.alpha_over(fence_big,fence_side, (4,4),fence_side) - composite.alpha_over(fence_big,fence_other_side, (8,4),fence_other_side) - composite.alpha_over(fence_big,fence_top, (-1,1),fence_top) + composite.alpha_over(fence_big,fence_side, (5,4),fence_side) + composite.alpha_over(fence_big,fence_other_side, (7,4),fence_other_side) + composite.alpha_over(fence_big,fence_top, (0,1),fence_top) # Now render the small sticks. # Create needed images From 00a3285555d7f759cb512fa0f23a31d268aaa76c Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Thu, 28 Apr 2011 11:10:06 -0400 Subject: [PATCH 55/78] Fix for py2exe --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 5eb8c23..497b5ac 100644 --- a/setup.py +++ b/setup.py @@ -28,7 +28,7 @@ setup_kwargs['cmdclass'] = {} if py2exe is not None: setup_kwargs['console'] = ['overviewer.py'] setup_kwargs['data_files'] = [('textures', ['textures/lava.png', 'textures/water.png', 'textures/fire.png']), - ('', ['config.js', 'COPYING.txt', 'README.rst']), + ('', ['overviewerConfig.js', 'COPYING.txt', 'README.rst']), ('web_assets', glob.glob('web_assets/*'))] setup_kwargs['zipfile'] = None if platform.system() == 'Windows' and '64bit' in platform.architecture(): From f20d81c39f0302a44e02a6f42f6eb0d13b9fcc18 Mon Sep 17 00:00:00 2001 From: Michael Writhe Date: Fri, 29 Apr 2011 19:24:07 -0400 Subject: [PATCH 56/78] Updating WG2OvR link --- overviewerConfig.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overviewerConfig.js b/overviewerConfig.js index fd12c49..acb4529 100644 --- a/overviewerConfig.js +++ b/overviewerConfig.js @@ -109,7 +109,7 @@ var overviewerConfig = { /* regions -- A list of region groups. A region can fall into zero, * one, or more than one group. See below for some examples. * Regions have been designed to work with the WorldGuard Overviewer - * Region importer at @link https://github.com/pironic/WG2OvR but your + * Region importer at @link http://goo.gl/dc0tV but your * host must support php in order to run WG2OvR. You can also continue * to use any other region format. * From 803104e19300c844809899e5dda3d3f38a8534b1 Mon Sep 17 00:00:00 2001 From: Michael Writhe Date: Sat, 30 Apr 2011 20:17:14 -0600 Subject: [PATCH 57/78] resolved 2 issues with signs and regions not working for 'checked' items. issue 347 and 349 --- web_assets/overviewer.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/web_assets/overviewer.js b/web_assets/overviewer.js index f927625..06c0f0e 100644 --- a/web_assets/overviewer.js +++ b/web_assets/overviewer.js @@ -623,12 +623,12 @@ var overviewer = { 'checked': signGroup.checked, 'icon': iconURL, 'action': function(n, item, checked) { - jQuery.each(overviewer.collections.markers[item.label], + jQuery.each(overviewer.collections.markers[item], function(i, elem) { elem.setVisible(checked); } ); - overviewer.util.debug('Adding sign item: ' + item.label); + overviewer.util.debug('Adding sign item: ' + item); } }); } @@ -645,11 +645,13 @@ var overviewer = { 'label': regionGroup.label, 'checked': regionGroup.checked, 'action': function(n, item, checked) { - jQuery.each(overviewer.collections.regions[item.label], + jQuery.each(overviewer.collections.regions[item], function(i,elem) { // Thanks to LeastWeasel for this line! elem.setMap(checked ? overviewer.map : null); }); + overviewer.util.debug('Adding region item: ' + item); + } }); } From d163e7c5271da50a9584fcbdcd3d179c49cc4c9d Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Thu, 28 Apr 2011 19:18:29 -0400 Subject: [PATCH 58/78] support for biome coloring on side grass (closes issue #341) --- src/overviewer.h | 2 +- src/rendermode-normal.c | 16 ++++------------ textures.py | 7 ++++--- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/overviewer.h b/src/overviewer.h index b18462a..55243a5 100644 --- a/src/overviewer.h +++ b/src/overviewer.h @@ -26,7 +26,7 @@ // increment this value if you've made a change to the c extesion // and want to force users to rebuild -#define OVERVIEWER_EXTENSION_VERSION 4 +#define OVERVIEWER_EXTENSION_VERSION 5 /* Python PIL, and numpy headers */ #include diff --git a/src/rendermode-normal.c b/src/rendermode-normal.c index 9f139a3..c656d2e 100644 --- a/src/rendermode-normal.c +++ b/src/rendermode-normal.c @@ -120,17 +120,8 @@ rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject * RenderModeNormal *self = (RenderModeNormal *)data; /* first, check to see if we should use biome-compatible src, mask */ - if (self->biome_data) { - switch (state->block) { - case 2: - src = mask = self->grass_texture; - break; - case 18: - src = mask = self->leaf_texture; - break; - default: - break; - }; + if (self->biome_data && state->block == 18) { + src = mask = self->leaf_texture; } /* draw the block! */ @@ -149,7 +140,8 @@ rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject * case 2: /* grass */ color = PySequence_GetItem(self->grasscolor, index); - facemask = self->facemask_top; + facemask = self->grass_texture; + alpha_over(state->img, self->grass_texture, self->grass_texture, state->imgx, state->imgy, 0, 0); break; case 18: /* leaves */ diff --git a/textures.py b/textures.py index 567942a..0f73932 100644 --- a/textures.py +++ b/textures.py @@ -432,8 +432,9 @@ def generate_special_texture(blockID, data): # all need to behandled here (and in chunkpy) if blockID == 2: # grass - top = tintTexture(terrain_images[0],(115,175,71)) - img = _build_block(top, terrain_images[3], 2) + img = _build_block(terrain_images[0], terrain_images[3], 2) + colored = tintTexture(biome_grass_texture, (115, 175, 71)) + composite.alpha_over(img, colored, (0, 0), colored) return (img.convert("RGB"), img.split()[3]) @@ -1179,7 +1180,7 @@ def tintTexture(im, c): return i # generate biome (still grayscale) leaf, grass textures -biome_grass_texture = _build_block(terrain_images[0], terrain_images[3], 2) +biome_grass_texture = _build_block(terrain_images[0], terrain_images[38], 2) biome_leaf_texture = _build_block(terrain_images[52], terrain_images[52], 18) From 9a537e76e2780450f67ee22b32e0b67343fa1b1d Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sat, 30 Apr 2011 23:06:44 -0400 Subject: [PATCH 59/78] some config file clarifications --- quadtree.py | 2 +- sample.settings.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/quadtree.py b/quadtree.py index 701aa27..6d5a567 100644 --- a/quadtree.py +++ b/quadtree.py @@ -91,7 +91,7 @@ class QuadtreeGen(object): yradius >= worldobj.maxrow and -yradius <= worldobj.minrow: break else: - raise ValueError("Your map is waaaay too big! Use the '-z' or '--zoom' options.") + raise ValueError("Your map is waaaay too big! Use the 'zoom' option in 'settings.py'.") self.p = p else: diff --git a/sample.settings.py b/sample.settings.py index ee0d050..2872506 100644 --- a/sample.settings.py +++ b/sample.settings.py @@ -2,8 +2,9 @@ # 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 not meant to be used directly, but instead it is supposed to +# provide examples of interesting things you can do with the settings file. Most +# of the time, a simple 'setting_name = value' will work. # 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 From a68079de848ff890ca87f60a8d4f76aa918064cc Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Sun, 1 May 2011 12:35:11 -0400 Subject: [PATCH 60/78] Fixed signpost regression from a09d7f3 a09d7f3 fixed issue #349, but introduced a new regression. This commit reverts a09d7f3, and fixes #349 in a different way --- web_assets/overviewer.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web_assets/overviewer.js b/web_assets/overviewer.js index 06c0f0e..6220a16 100644 --- a/web_assets/overviewer.js +++ b/web_assets/overviewer.js @@ -623,7 +623,7 @@ var overviewer = { 'checked': signGroup.checked, 'icon': iconURL, 'action': function(n, item, checked) { - jQuery.each(overviewer.collections.markers[item], + jQuery.each(overviewer.collections.markers[item.label], function(i, elem) { elem.setVisible(checked); } @@ -645,7 +645,7 @@ var overviewer = { 'label': regionGroup.label, 'checked': regionGroup.checked, 'action': function(n, item, checked) { - jQuery.each(overviewer.collections.regions[item], + jQuery.each(overviewer.collections.regions[item.label], function(i,elem) { // Thanks to LeastWeasel for this line! elem.setMap(checked ? overviewer.map : null); @@ -738,7 +738,7 @@ var overviewer = { // if its checked, its gotta do something, do that here. if (item.checked) { itemInput.checked = true; - item.action(i, item.label, item.checked); + item.action(i, item, item.checked); } dropdownDiv.appendChild(itemDiv); itemDiv.appendChild(itemInput); From 724bf114e7c15e5715eabaf76436916a74b2a4f3 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Sun, 1 May 2011 16:30:40 +0200 Subject: [PATCH 61/78] Fix new saplings. --- textures.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/textures.py b/textures.py index 0f73932..2f28b64 100644 --- a/textures.py +++ b/textures.py @@ -210,9 +210,8 @@ def _build_block(top, side, blockID=None): return img side = transform_image_side(side, blockID) - otherside = side.transpose(Image.FLIP_LEFT_RIGHT) - + # Darken the sides slightly. These methods also affect the alpha layer, # so save them first (we don't want to "darken" the alpha layer making # the block transparent) @@ -224,8 +223,6 @@ def _build_block(top, side, blockID=None): otherside.putalpha(othersidealpha) ## special case for non-block things - # TODO once torches are handled by generate_special_texture, remove - # them from this list if blockID in (37,38,6,39,40,83): ## flowers, sapling, mushrooms, reeds # # instead of pasting these blocks at the cube edges, place them in the middle: @@ -439,18 +436,25 @@ def generate_special_texture(blockID, data): if blockID == 6: # saplings - if data == 1: # spruce sapling + # The bottom two bits are used fo the sapling type, the top two + # bits are used as a grow-counter for the tree. + + if data & 0x3 == 0: # usual saplings + toptexture = terrain_images[15] + sidetexture = terrain_images[15] + + if data & 0x3 == 1: # spruce sapling toptexture = terrain_images[63] sidetexture = terrain_images[63] - if data == 2: # birch sapling + if data & 0x3 == 2: # birch sapling toptexture = terrain_images[79] sidetexture = terrain_images[79] - - else: # usual and future saplings + + if data & 0x3 == 3: # unused usual sapling toptexture = terrain_images[15] sidetexture = terrain_images[15] - + img = _build_block(toptexture, sidetexture, blockID) return (img.convert("RGB"),img.split()[3]) @@ -1257,7 +1261,7 @@ special_blocks = set([ 2, 6, 9, 17, 18, 23, 27, 28, 35, 43, 44, 50, 51, special_map = {} -special_map[6] = range(4) # saplings: usual, spruce, birch and future ones (rendered as usual saplings) +special_map[6] = range(16) # saplings: usual, spruce, birch and future ones (rendered as usual saplings) special_map[9] = range(32) # water: spring,flowing, waterfall, and others (unknown) ancildata values. special_map[17] = range(4) # wood: normal, birch and pine special_map[23] = range(6) # dispensers, orientation From 8b99db7bf6004dd2fcbbca701f03c85ac98b1346 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Sun, 1 May 2011 17:13:58 +0200 Subject: [PATCH 62/78] Add orientation for furnaces, dispensers, pumpkins, and jack-o-lanterns. --- textures.py | 73 +++++++++++++++++++++++------------------------------ 1 file changed, 32 insertions(+), 41 deletions(-) diff --git a/textures.py b/textures.py index 2f28b64..422ba8d 100644 --- a/textures.py +++ b/textures.py @@ -509,18 +509,6 @@ def generate_special_texture(blockID, data): t = tintTexture(terrain_images[52], (37, 118, 25)) img = _build_block(t, t, 18) return (img.convert("RGB"), img.split()[3]) - - if blockID == 23: # dispenser - top = transform_image(terrain_images[62]) - side1 = transform_image_side(terrain_images[46]) - side2 = transform_image_side(terrain_images[45]).transpose(Image.FLIP_LEFT_RIGHT) - - img = Image.new("RGBA", (24,24), (38,92,255,0)) - - composite.alpha_over(img, side1, (0,6), side1) - composite.alpha_over(img, side2, (12,6), side2) - composite.alpha_over(img, top, (0,0), top) - return (img.convert("RGB"), img.split()[3]) if blockID == 35: # wool @@ -853,29 +841,28 @@ def generate_special_texture(blockID, data): return (img.convert("RGB"), img.split()[3]) - if blockID == 61: #furnace - top = transform_image(terrain_images[62]) - side1 = transform_image_side(terrain_images[45]) - side2 = transform_image_side(terrain_images[44]).transpose(Image.FLIP_LEFT_RIGHT) + if blockID in (61, 62, 23): #furnace and burning furnace + top = terrain_images[62] + side = terrain_images[45] - img = Image.new("RGBA", (24,24), (38,92,255,0)) + if blockID == 61: + front = terrain_images[44] - composite.alpha_over(img, side1, (0,6), side1) - composite.alpha_over(img, side2, (12,6), side2) - composite.alpha_over(img, top, (0,0), top) - return (img.convert("RGB"), img.split()[3]) + elif blockID == 62: + front = terrain_images[45+16] + elif blockID == 23: + front = terrain_images[46] - if blockID == 62: # lit furnace - top = transform_image(terrain_images[62]) - side1 = transform_image_side(terrain_images[45]) - side2 = transform_image_side(terrain_images[45+16]).transpose(Image.FLIP_LEFT_RIGHT) + if data == 3: # pointing west + img = _build_full_block(top, None, None, side, front) + + elif data == 4: # pointing north + img = _build_full_block(top, None, None, front, side) + + else: # in any other direction the front can't be seen + img = _build_full_block(top, None, None, side, side) - img = Image.new("RGBA", (24,24), (38,92,255,0)) - - composite.alpha_over(img, side1, (0,6), side1) - composite.alpha_over(img, side2, (12,6), side2) - composite.alpha_over(img, top, (0,0), top) return (img.convert("RGB"), img.split()[3]) @@ -1135,16 +1122,20 @@ def generate_special_texture(blockID, data): if blockID in (86,91): # pumpkins, jack-o-lantern - top = transform_image(terrain_images[102]) + top = terrain_images[102] frontID = 119 if blockID == 86 else 120 - side1 = transform_image_side(terrain_images[frontID]) - side2 = transform_image_side(terrain_images[118]).transpose(Image.FLIP_LEFT_RIGHT) + front = terrain_images[frontID] + side = terrain_images[118] - img = Image.new("RGBA", (24,24), (38,92,255,0)) + if data == 0: # pointing west + img = _build_full_block(top, None, None, side, front) + + elif data == 1: # pointing north + img = _build_full_block(top, None, None, front, side) + + else: # in any other direction the front can't be seen + img = _build_full_block(top, None, None, side, side) - composite.alpha_over(img, side1, (0,6), side1) - composite.alpha_over(img, side2, (12,6), side2) - composite.alpha_over(img, top, (0,0), top) return (img.convert("RGB"), img.split()[3]) @@ -1276,8 +1267,8 @@ special_map[53] = range(4) # wooden stairs, orientation special_map[55] = range(128) # redstone wire, all the possible combinations special_map[58] = (0,) # crafting table special_map[59] = range(8) # crops, grow from 0 to 7 -special_map[61] = range(6) # furnace, orientation (not implemented) -special_map[62] = range(6) # burning furnace, orientation (not implemented) +special_map[61] = range(6) # furnace, orientation +special_map[62] = range(6) # burning furnace, orientation special_map[64] = range(16) # wooden door, open/close and orientation special_map[65] = (2,3,4,5) # ladder, orientation special_map[66] = range(10) # minecrart tracks, orientation, slope @@ -1286,8 +1277,8 @@ 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[76] = (1,2,3,4,5) # on redstone torch, orientation special_map[85] = range(17) # fences, all the possible combination -special_map[86] = range(5) # pumpkin, orientation (not implemented) -special_map[91] = range(5) # jack-o-lantern, orientation (not implemented) +special_map[86] = range(5) # pumpkin, orientation +special_map[91] = range(5) # jack-o-lantern, orientation special_map[92] = range(6) # cake! # grass and leaves are graysacle in terrain.png From d58da71f1d602c3b78a3aa00e20c900e7f96a9d9 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Sun, 1 May 2011 17:28:36 +0200 Subject: [PATCH 63/78] Fix bookshelve and jukebox tops. --- textures.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/textures.py b/textures.py index 422ba8d..ee439ea 100644 --- a/textures.py +++ b/textures.py @@ -348,13 +348,13 @@ def _build_blockimages(): # 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 34, -1, 52, 48, 49,160,144, -1,176, 74, -1, -1, -1, -1, -1, -1, # Cloths are left out, sandstone (it has top, side, and bottom wich is ignored here), note block # 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, 4, # Gold/iron blocks? Doublestep? TNT from above? # 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 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 -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 - 66, 69, 72, 73, 74, -1,102,103,104,105,-1, 102 # clay? + 66, 69, 72, 73, 75, -1,102,103,104,105,-1, 102 # clay? ] # NOTE: For non-block textures, the sideid is ignored, but can't be -1 From 24c1e0dfd5786cac68b78a67072ba1fe938a17ef Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Mon, 2 May 2011 00:06:40 +0200 Subject: [PATCH 64/78] Add single and double chests with orientation to the textures. Add some comments about textures using pseudo data. --- src/iterate.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++-- textures.py | 57 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 116 insertions(+), 9 deletions(-) diff --git a/src/iterate.c b/src/iterate.c index 71bd7e3..2c0f1da 100644 --- a/src/iterate.c +++ b/src/iterate.c @@ -207,9 +207,73 @@ generate_pseudo_data(RenderState *state, unsigned char ancilData) { if ((above_level_data & 0x08)) { /* draw top right going up redstonewire */ final_data = final_data | 0x10; } - return final_data; + return final_data; + + } else if (state-> block == 54) { /* chests */ + /* the top 2 bits are used to store the type of chest + * (single or double), the 2 bottom bits are used for + * orientation, look textures.py for more information. */ + + /* if placed alone chests always face west, return 0 to make a + * chest facing west */ + unsigned char chest_data = 0, air_data = 0, final_data = 0; + + /* search for chests */ + chest_data = check_adjacent_blocks(state, x, y, z, 54); + + /* search for air */ + air_data = check_adjacent_blocks(state, x, y, z, 0); + + if (chest_data == 1) { /* another chest in the east */ + final_data = final_data | 0x8; /* only can face to north or south */ + if ( (air_data & 0x2) == 2 ) { + final_data = final_data | 0x1; /* facing north */ + } else { + final_data = final_data | 0x3; /* facing south */ + } + + } else if (chest_data == 2) { /* in the north */ + final_data = final_data | 0x4; /* only can face to east or west */ + if ( !((air_data & 0x4) == 4) ) { /* 0 = west */ + final_data = final_data | 0x2; /* facing east */ + } + + } else if (chest_data == 4) { /*in the west */ + final_data = final_data | 0x4; + if ( (air_data & 0x2) == 2 ) { + final_data = final_data | 0x1; /* facing north */ + } else { + final_data = final_data | 0x3; /* facing south */ + } + + } else if (chest_data == 8) { /*in the south */ + final_data = final_data | 0x8; + if ( !((air_data & 0x4) == 4) ) { + final_data = final_data | 0x2; /* facing east */ + } + + } else if (chest_data == 0) { + /* Single chest, determine the orientation */ + if ( ((air_data & 0x8) == 0) && ((air_data & 0x2) == 2) ) { /* block in +x and no block in -x */ + final_data = final_data | 0x1; /* facing north */ + + } else if ( ((air_data & 0x2) == 0) && ((air_data & 0x8) == 8)) { + final_data = final_data | 0x3; + + } else if ( ((air_data & 0x4) == 0) && ((air_data & 0x1) == 1)) { + final_data = final_data | 0x2; + } /* else, facing west, value = 0 */ + + } else { + /* more than one adjacent chests! render as normal chest */ + return 0; + } + + return final_data; + } + return 0; } @@ -329,7 +393,7 @@ chunk_render(PyObject *self, PyObject *args) { PyObject *tmp; unsigned char ancilData = getArrayByte3D(blockdata_expanded, state.x, state.y, state.z); - if ((state.block == 85) || (state.block == 9) || (state.block == 55)) { + if ((state.block == 85) || (state.block == 9) || (state.block == 55) || (state.block == 54) ) { ancilData = generate_pseudo_data(&state, ancilData); } diff --git a/textures.py b/textures.py index ee439ea..2564a97 100644 --- a/textures.py +++ b/textures.py @@ -350,7 +350,7 @@ def _build_blockimages(): # 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, 4, # Gold/iron blocks? Doublestep? TNT from above? # 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 - 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 + 36, 37, -1, -1, 65, -1, -1, -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 -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 @@ -367,7 +367,7 @@ def _build_blockimages(): # 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, # 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 - 36, 37, -1, -1, 65, -1, 25,101, 98, 24, -1, -1, 86, -1, -1, -1, + 36, 37, -1, -1, 65, -1, -1,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 -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 @@ -740,6 +740,48 @@ def generate_special_texture(blockID, data): return (img.convert("RGB"), img.split()[3]) + if blockID == 54: # chests + # First to bits of the pseudo data store if it's a single chest + # or it's a double chest, first half or second half. + # The to last bits store the orientation. + + top = terrain_images[25] + side = terrain_images[26] + + if data & 12 == 0: # single chest + front = terrain_images[27] + back = terrain_images[26] + + elif data & 12 == 4: # double, first half + front = terrain_images[41] + back = terrain_images[57] + + elif data & 12 == 8: # double, second half + front = terrain_images[42] + back = terrain_images[58] + + else: # just in case + front = terrain_images[25] + side = terrain_images[25] + back = terrain_images[25] + + if data & 3 == 0: # facing west + img = _build_full_block(top, None, None, side, front) + + elif data & 3 == 1: # north + img = _build_full_block(top, None, None, front, side) + + elif data & 3 == 2: # east + img = _build_full_block(top, None, None, side, back) + + elif data & 3 == 3: # south + img = _build_full_block(top, None, None, back, side) + + else: + img = _build_full_block(top, None, None, back, side) + + return (img.convert("RGB"), img.split()[3]) + if blockID == 55: # redstone wire @@ -1244,8 +1286,8 @@ def getBiomeData(worlddir, chunkX, chunkY): # please, if possible, keep the ascending order of blockid value) special_blocks = set([ 2, 6, 9, 17, 18, 23, 27, 28, 35, 43, 44, 50, 51, - 53, 55, 58, 59, 61, 62, 64, 65, 66, 67, 71, 75, 76, - 85, 86, 91, 92]) + 53, 54, 55, 58, 59, 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 # possible values for ancillary data that it might have. @@ -1253,7 +1295,7 @@ special_blocks = set([ 2, 6, 9, 17, 18, 23, 27, 28, 35, 43, 44, 50, 51, special_map = {} special_map[6] = range(16) # saplings: usual, spruce, birch and future ones (rendered as usual saplings) -special_map[9] = range(32) # water: spring,flowing, waterfall, and others (unknown) ancildata values. +special_map[9] = range(32) # water: spring,flowing, waterfall, and others (unknown) ancildata values, uses pseudo data special_map[17] = range(4) # wood: normal, birch and pine special_map[23] = range(6) # dispensers, orientation special_map[27] = range(14) # powered rail, orientation/slope and powered/unpowered @@ -1264,7 +1306,8 @@ 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[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[54] = range(12) # chests, orientation and type (single or double), uses pseudo data +special_map[55] = range(128) # redstone wire, all the possible combinations, uses pseudo data special_map[58] = (0,) # crafting table special_map[59] = range(8) # crops, grow from 0 to 7 special_map[61] = range(6) # furnace, orientation @@ -1276,7 +1319,7 @@ special_map[67] = range(4) # cobblestone stairs, 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[76] = (1,2,3,4,5) # on redstone torch, orientation -special_map[85] = range(17) # fences, all the possible combination +special_map[85] = range(17) # fences, all the possible combination, uses pseudo data special_map[86] = range(5) # pumpkin, orientation special_map[91] = range(5) # jack-o-lantern, orientation special_map[92] = range(6) # cake! From c1e71f0fdad0ff20feeec1023f34bf456d7c5f9c Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sun, 1 May 2011 19:42:27 -0400 Subject: [PATCH 65/78] grass now has snowy sides when covered in snow --- src/iterate.c | 9 +++++++-- src/rendermode-normal.c | 4 +++- textures.py | 20 +++++++++++++------- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/iterate.c b/src/iterate.c index 2c0f1da..1828409 100644 --- a/src/iterate.c +++ b/src/iterate.c @@ -155,7 +155,12 @@ generate_pseudo_data(RenderState *state, unsigned char ancilData) { int x = state->x, y = state->y, z = state->z; unsigned char data = 0; - if (state->block == 9) { /* water */ + if (state->block == 2) { /* grass */ + /* return 0x10 if grass is covered in snow */ + if (z < 127 && getArrayByte3D(state->blocks, x, y, z+1) == 78) + return 0x10; + return ancilData; + } else if (state->block == 9) { /* water */ /* an aditional bit for top is added to the 4 bits of check_adjacent_blocks */ if ((ancilData == 0) || (ancilData >= 10)) { /* static water, only top, and unkown ancildata values */ data = 16; @@ -393,7 +398,7 @@ chunk_render(PyObject *self, PyObject *args) { PyObject *tmp; unsigned char ancilData = getArrayByte3D(blockdata_expanded, state.x, state.y, state.z); - if ((state.block == 85) || (state.block == 9) || (state.block == 55) || (state.block == 54) ) { + if ((state.block == 85) || (state.block == 9) || (state.block == 55) || (state.block == 54) || (state.block == 2)) { ancilData = generate_pseudo_data(&state, ancilData); } diff --git a/src/rendermode-normal.c b/src/rendermode-normal.c index c656d2e..be14a92 100644 --- a/src/rendermode-normal.c +++ b/src/rendermode-normal.c @@ -138,7 +138,9 @@ rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject * switch (state->block) { case 2: - /* grass */ + /* grass -- skip for snowgrass */ + if (state->z < 127 && getArrayByte3D(state->blocks, state->x, state->y, state->z+1) == 78) + break; color = PySequence_GetItem(self->grasscolor, index); facemask = self->grass_texture; alpha_over(state->img, self->grass_texture, self->grass_texture, state->imgx, state->imgy, 0, 0); diff --git a/textures.py b/textures.py index 2564a97..1b9e3a1 100644 --- a/textures.py +++ b/textures.py @@ -429,9 +429,14 @@ def generate_special_texture(blockID, data): # all need to behandled here (and in chunkpy) if blockID == 2: # grass - img = _build_block(terrain_images[0], terrain_images[3], 2) - colored = tintTexture(biome_grass_texture, (115, 175, 71)) - composite.alpha_over(img, colored, (0, 0), colored) + # data & 0x10 means SNOW sides + side_img = terrain_images[3] + if data & 0x10: + side_img = terrain_images[68] + img = _build_block(terrain_images[0], side_img, 2) + if not data & 0x10: + colored = tintTexture(biome_grass_texture, (115, 175, 71)) + composite.alpha_over(img, colored, (0, 0), colored) return (img.convert("RGB"), img.split()[3]) @@ -1327,10 +1332,11 @@ special_map[92] = range(6) # cake! # grass and leaves are graysacle in terrain.png # we treat them as special so we can manually tint them # it is unknown how the specific tint (biomes) is calculated -special_map[2] = range(11) # grass, grass has not ancildata but is used - # in the mod WildGrass, and this small fix - # shows the map as expected, and is harmless - # for normal maps +# also, 0x10 means SNOW sides +special_map[2] = range(11) + [0x10,] # grass, grass has not ancildata but is + # used in the mod WildGrass, and this + # small fix shows the map as expected, + # and is harmless for normal maps special_map[18] = range(16) # leaves, birch, normal or pine leaves (not implemented) From 4a82e749cadfc3a96b7202c77d708bb5de7d9050 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Mon, 2 May 2011 18:02:13 -0400 Subject: [PATCH 66/78] added imgquality config file option for setting JPG quality Original code by alexjurkiewicz, ported to new DTT code. This closes #83. --- overviewer.py | 5 +++-- quadtree.py | 10 +++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/overviewer.py b/overviewer.py index 115644f..c8e7500 100755 --- a/overviewer.py +++ b/overviewer.py @@ -96,7 +96,8 @@ 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("--rendermodes", dest="rendermode", help="Specifies the render types, separated by commas. Use --list-rendermodes to list them all.", type="choice", choices=avail_rendermodes, 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.", commandLineOnly=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.", configFileOnly=True ) + parser.add_option("--imgformat", dest="imgformat", help="The image output format to use. Currently supported: png(default), jpg.", configFileOnly=True ) + parser.add_option("--imgquality", dest="imgquality", default=95, help="Specify the quality of image output when using imgformat=\"jpg\".", type="int", configFileOnly=True) parser.add_option("--bg_color", dest="bg_color", help="Configures the background color for the GoogleMap output. Specify in #RRGGBB format", configFileOnly=True, type="string", default="#1A1A1A") 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%", configFileOnly=True) parser.add_option("--web-assets-hook", dest="web_assets_hook", help="If provided, run this function after the web assets have been copied, but before actual tile rendering begins. It should accept a QuadtreeGen object as its only argument.", action="store", metavar="SCRIPT", type="function", configFileOnly=True) @@ -220,7 +221,7 @@ def main(): # create the quadtrees # TODO chunklist q = [] - qtree_args = {'depth' : options.zoom, 'imgformat' : imgformat, 'optimizeimg' : optimizeimg, 'bgcolor':bgcolor} + qtree_args = {'depth' : options.zoom, 'imgformat' : imgformat, 'imgquality' : options.imgquality, 'optimizeimg' : optimizeimg, 'bgcolor' : bgcolor} for rendermode in options.rendermode: if rendermode == 'normal': qtree = quadtree.QuadtreeGen(w, destdir, rendermode=rendermode, tiledir='tiles', **qtree_args) diff --git a/quadtree.py b/quadtree.py index 6d5a567..688db93 100644 --- a/quadtree.py +++ b/quadtree.py @@ -49,7 +49,7 @@ def iterate_base4(d): return itertools.product(xrange(4), repeat=d) class QuadtreeGen(object): - def __init__(self, worldobj, destdir, bgcolor, depth=None, tiledir=None, imgformat=None, optimizeimg=None, rendermode="normal"): + def __init__(self, worldobj, destdir, bgcolor, depth=None, tiledir=None, imgformat=None, imgquality=95, optimizeimg=None, rendermode="normal"): """Generates a quadtree from the world given into the given dest directory @@ -61,6 +61,7 @@ class QuadtreeGen(object): """ assert(imgformat) self.imgformat = imgformat + self.imgquality = imgquality self.optimizeimg = optimizeimg self.bgcolor = bgcolor self.rendermode = rendermode @@ -336,7 +337,7 @@ class QuadtreeGen(object): # Save it if self.imgformat == 'jpg': - img.save(imgpath, quality=95, subsampling=0) + img.save(imgpath, quality=self.imgquality, subsampling=0) else: # png img.save(imgpath) @@ -463,7 +464,10 @@ class QuadtreeGen(object): pass # Save them - tileimg.save(imgpath) + if self.imgformat == 'jpg': + tileimg.save(imgpath, quality=self.imgquality, subsampling=0) + else: # png + tileimg.save(imgpath) if self.optimizeimg: optimize_image(imgpath, self.imgformat, self.optimizeimg) From 9f9ae1e1fe1c46e08c0867197255658f3adaaca7 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Tue, 3 May 2011 09:11:55 +0200 Subject: [PATCH 67/78] Fix diamond-ore textures. --- textures.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/textures.py b/textures.py index 1b9e3a1..8e764c8 100644 --- a/textures.py +++ b/textures.py @@ -350,7 +350,7 @@ def _build_blockimages(): # 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, 4, # Gold/iron blocks? Doublestep? TNT from above? # 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 - 36, 37, -1, -1, 65, -1, -1, -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, -1, -1, 50, 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 -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 @@ -367,7 +367,7 @@ def _build_blockimages(): # 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, # 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 - 36, 37, -1, -1, 65, -1, -1,101, 98, 24, -1, -1, 86, -1, -1, -1, + 36, 37, -1, -1, 65, -1, -1,101, 50, 24, -1, -1, 86, -1, -1, -1, # 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 -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 From 3c8d7e6442d3cf2bcf8736fa18beb007a3cd2d55 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Sun, 8 May 2011 02:10:19 +0200 Subject: [PATCH 68/78] Add portals to textures.py, needed changes in chunk.py and iterate.c and added beds to transparent blocks. --- chunk.py | 6 +++--- src/iterate.c | 4 +++- textures.py | 19 ++++++++++++++++++- textures/portal.png | Bin 0 -> 672 bytes 4 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 textures/portal.png diff --git a/chunk.py b/chunk.py index 59ccae0..f44b4db 100644 --- a/chunk.py +++ b/chunk.py @@ -114,9 +114,9 @@ def get_tileentity_data(level): return data # This set holds blocks ids that can be seen through, for occlusion calculations -transparent_blocks = set([ 0, 6, 8, 9, 18, 20, 27, 28, 37, 38, 39, 40, 44, 50, - 51, 52, 53, 55, 59, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 74, 75, 76, 77, 78, 79, 81, 83, 85, 92]) +transparent_blocks = set([ 0, 6, 8, 9, 18, 20, 26, 27, 28, 37, 38, 39, 40, 44, + 50, 51, 52, 53, 55, 59, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 74, 75, 76, 77, 78, 79, 81, 83, 85, 90, 92]) # 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, 21, 22, diff --git a/src/iterate.c b/src/iterate.c index 1828409..7fd3d3f 100644 --- a/src/iterate.c +++ b/src/iterate.c @@ -276,6 +276,8 @@ generate_pseudo_data(RenderState *state, unsigned char ancilData) { return final_data; + } else if (state->block == 90) { + return check_adjacent_blocks(state, x, y, z, state->block); } @@ -398,7 +400,7 @@ chunk_render(PyObject *self, PyObject *args) { PyObject *tmp; unsigned char ancilData = getArrayByte3D(blockdata_expanded, state.x, state.y, state.z); - if ((state.block == 85) || (state.block == 9) || (state.block == 55) || (state.block == 54) || (state.block == 2)) { + if ((state.block == 85) || (state.block == 9) || (state.block == 55) || (state.block == 54) || (state.block == 2) || (state.block == 90)) { ancilData = generate_pseudo_data(&state, ancilData); } diff --git a/textures.py b/textures.py index 8e764c8..28d44f0 100644 --- a/textures.py +++ b/textures.py @@ -1186,6 +1186,22 @@ def generate_special_texture(blockID, data): return (img.convert("RGB"), img.split()[3]) + if blockID == 90: # portal + portaltexture = _load_image("portal.png") + img = Image.new("RGBA", (24,24), (38,92,255,0)) + + side = transform_image_side(portaltexture) + otherside = side.transpose(Image.FLIP_TOP_BOTTOM) + + if data in (1,4): + composite.alpha_over(img, side, (5,4), side) + + if data in (2,8): + composite.alpha_over(img, otherside, (5,4), otherside) + + return (img.convert("RGB"), img.split()[3]) + + if blockID == 92: # cake! (without bites, at the moment) top = terrain_images[121] @@ -1292,7 +1308,7 @@ def getBiomeData(worlddir, chunkX, chunkY): special_blocks = set([ 2, 6, 9, 17, 18, 23, 27, 28, 35, 43, 44, 50, 51, 53, 54, 55, 58, 59, 61, 62, 64, 65, 66, 67, 71, 75, - 76, 85, 86, 91, 92]) + 76, 85, 86, 90, 91, 92]) # this is a map of special blockIDs to a list of all # possible values for ancillary data that it might have. @@ -1326,6 +1342,7 @@ 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[85] = range(17) # fences, all the possible combination, uses pseudo data special_map[86] = range(5) # pumpkin, orientation +special_map[90] = (1,2,4,8) # portal, in 2 orientations, 4 cases, uses pseudo data special_map[91] = range(5) # jack-o-lantern, orientation special_map[92] = range(6) # cake! diff --git a/textures/portal.png b/textures/portal.png new file mode 100644 index 0000000000000000000000000000000000000000..c6199204854714620b203859875747d5b13e2a14 GIT binary patch literal 672 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s77>k44ofy`glX=O&z`&N| z?e4-*$q>Xa_YJ$wGX@3*&H|6fVg?3oVGw3ym^DX&fq{X&#M9T6{WdGR2n$=e)hv*Z zWQl7;iF1B#Zfaf$gL6@8Vo7R>LV0FMhJw4NZ$Nk>pEv^p<8MzF#}JFtt&>j{-8K+# zkrxZP;~H6{I#vGU^e4@qX75}!$1BHEEPUdTLozCt!)~rT!)j6T{fmjgqubZt+qY#t zs$aU~$>+P%lzcPK+uF;^Pjpf!e?3WqM?68wRi4Y@{m)vP3;gMuEFPXNbD#PA#P$Wb zfd%n-c`j3GS~(OM8bz9vd^IPD>|O8Yb8N%OqEkBc>DAF|R{rigDX}HU=FR*cTW&Hi zW$RWMwb^*?(Dz9OD*|E}1Bhu=a7l zbq~dkLjuobe!n`haplL&`z23CbZ-<}J0)q38k_8g=RbEesAXTge%ZqP^7rc#lG`#5 zRsMhF;JI~Ag9y`OnS0f9zMsf;S7eEtGeMp6;DQzX_md7R3a+q;cCuz=PB#QEYHMp=lX^@0o^LxC;a&Ys@@(qPJ>N?LON66D z+U`7M_3~t4%AH%i-Qw7-r~jt?`LuPh!ILXyJ;xTzzx_=1WxQys;=*fJVvjFe$M}Og YRPXb*Ndex<3=9kmp00i_>zopr0C|NQQ~&?~ literal 0 HcmV?d00001 From a289ac2adcaa7d7afbacf898f9595d95e6bee0f0 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Sun, 8 May 2011 01:47:40 -0400 Subject: [PATCH 69/78] Better error reporting when the wrong number of arguments are used --- overviewer.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/overviewer.py b/overviewer.py index c8e7500..bd4ef7b 100755 --- a/overviewer.py +++ b/overviewer.py @@ -164,10 +164,18 @@ def main(): logging.error("Invalid world number") sys.exit(1) - if len(args) != 2: + if len(args) < 2: if options.delete: return delete_all(worlddir, None) - parser.error("Where do you want to save the tiles?") + logging.error("Where do you want to save the tiles?") + sys.exit(1) + elif len(args) > 2: + if options.delete: + return delete_all(worlddir, None) + parser.print_help() + logging.error("Sorry, you specified too many arguments") + sys.exit(1) + destdir = args[1] if options.display_config: From 3a18d81842e9427d506543201c4ebd7ef046f0d6 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Sun, 8 May 2011 10:11:13 +0200 Subject: [PATCH 70/78] Increase the portal texture transparency. --- textures/portal.png | Bin 672 -> 672 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/textures/portal.png b/textures/portal.png index c6199204854714620b203859875747d5b13e2a14..1f75ca3d3b211ae75907f5839202dfdbff9effe4 100644 GIT binary patch delta 555 zcmZ3$x`1_pIp=?d{|x^Z>|H*2qJshl2M4Ex->S`fCT1AcN9Nsj5OBG#vt&p2rWBPE zu0@k%G|Er)GO>5+o_wS=X|sX+q)hIz3IAsPT(N51x|w44_tpJ3^b!8At*Scz{Wg(I zuj+R{fBxtYVcHoz-6e4c!)1+M0S7A2zkl3VXEFIGXZ$wnQ#S7VSaZ9Zeis!hFM6Ww z!okR~L_j3dYvPg@wWak*Ms2>+g42Fl-@cvXd$-)@*n+8#68|4rewIxjBKzWG!zZ4H zY9o{OF3yVHmFU3bD0cjbXA^^3w&&v+wWW^|_p4u!dSGNH0)L$+-DE;lYmkv5Cx zH^SBXe0%5rJ?n8Ss%LA)Qjy0dhA$fI&mU(siR|7t@0jJRef!&FjD3X9)&CA>_geLo zb%}t)^AGnP?{SZ_=2ATIsKv(9<6etS@761|?G3Ddf{YE$8#4q-2(ist^;*olyIG}+ zV@ulHH1CYMd4dNrc)YxpOgLja=lH{Aoop7SyeG9D+4PBcb_I1UdvAD6DC=xqEK|V> ztz8e98&5{ny`6u-Yh(2EC969ew06}OKG4(e2-j|q-X!u!X#*G29~gmnp`s zeIOOJz%=xB(LA+P>-J8V5>>bQo>=ypVw>%}$D(c(pU==c{dDj0?nSdNEHZearyt;@ zB#`m?&hDdz*Yv(`e=>c&Y^&n(ZHXpqfA5&R_xQg`gNJkLvUgT|rMw5?cZYwz@JT1| S8v{231B0ilpUXO@geCy0?gXy@ delta 555 zcmZ3$x`1_pIcFt95X0Oz>^jdTIw)|ki?FbjTg{S~m|<9dvgo#ffQ!6X&>h#vBGsw# zC#OGY{xo~%vN>Kko?_t>j~tRwxg2(LOdbea3i=O?x=$PFxr&&zX}Qq#(z z$j~U#q~xnPNo4POzj~iz8%`FT(y33cj$X6!ci%~gEkQPK=Kt7olYuE)x5}u^#&d_h z_nPvMTyJw855*IYX4rTN97xg4l-a!A&*sf{mMG>Jw}^DfM1h30j{~lID0UnYcrNq% z)sc-WKW^SHc`~AVquAOhNpsZLWIsIrxuZcX`{MP>7Vek7U!RcNmU*bM{{Jfn&#ikJ zM3^4S+^e4R{Y19AB1`0)3F@3DXHQtVaoVo;0vj6Qv)GK+2W4LMTX_e6eC^d9G|G<8R&KKi|w%}r?ofNdNc5a zx|-K07(||4|5rFlv+VVx5>Y`9SMz$lJ5O0ZX0aAHPjiZ433F_ipRSfYbIsEmCQDX} z#yE3tS(X)j?y}3(t>Tk{PUl~}ozz>}_k7#I2=D55l4nzQ?)hF4SRx!H(st)5tCuGW zQ|{dA?H0#wJ^eTB&!?@64W3*v>p8Yy{_SV7FXKg96&GH+5_^2%I>sN|p?aUcO$zW< SX5eOEVDNPHb6Mw<&;$UNngTEY From e437a15abcc3c4f4448bcc22185831600523468d Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Sun, 8 May 2011 12:24:58 +0200 Subject: [PATCH 71/78] Add beds and some changes in _build_full_block to simplify the building of fractions of a block. --- textures.py | 93 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 84 insertions(+), 9 deletions(-) diff --git a/textures.py b/textures.py index 28d44f0..72fec24 100644 --- a/textures.py +++ b/textures.py @@ -273,9 +273,37 @@ def _build_full_block(top, side1, side2, side3, side4, bottom=None, blockID=None side3 is in the -x (bottom left, north) 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. + + If top is a tuple then first member is the top image and the second + member is an increment (integer) from 0 to 12. This increment will + used to crop the side images to look like a block and to paste all + the images increment pixels lower. Using increment = 6 will create + a half-block. + + NOTE: this method uses the top of the texture image (as done in + minecraft with beds) """ + + increment = 0 + if isinstance(top, tuple): + increment = top[1] + crop_height = int(increment * 16./12.) + top = top[0] + if side1 != None: + side1 = side1.copy() + ImageDraw.Draw(side1).rectangle((0, 16 - crop_height,16,16),outline=(0,0,0,0),fill=(0,0,0,0)) + if side2 != None: + side2 = side2.copy() + ImageDraw.Draw(side2).rectangle((0, 16 - crop_height,16,16),outline=(0,0,0,0),fill=(0,0,0,0)) + if side3 != None: + side3 = side3.copy() + ImageDraw.Draw(side3).rectangle((0, 16 - crop_height,16,16),outline=(0,0,0,0),fill=(0,0,0,0)) + if side4 != None: + side4 = side4.copy() + ImageDraw.Draw(side4).rectangle((0, 16 - crop_height,16,16),outline=(0,0,0,0),fill=(0,0,0,0)) + img = Image.new("RGBA", (24,24), (38,92,255,0)) # first back sides @@ -288,7 +316,7 @@ def _build_full_block(top, side1, side2, side3, side4, bottom=None, blockID=None side1 = ImageEnhance.Brightness(side1).enhance(0.9) side1.putalpha(sidealpha) - composite.alpha_over(img, side1, (0,0), side1) + composite.alpha_over(img, side1, (0,0 + increment), side1) if side2 != None : @@ -299,7 +327,7 @@ def _build_full_block(top, side1, side2, side3, side4, bottom=None, blockID=None side2 = ImageEnhance.Brightness(side2).enhance(0.8) side2.putalpha(sidealpha2) - composite.alpha_over(img, side2, (12,0), side2) + composite.alpha_over(img, side2, (12,0 + increment), side2) if bottom != None : bottom = transform_image(bottom, blockID) @@ -314,7 +342,7 @@ def _build_full_block(top, side1, side2, side3, side4, bottom=None, blockID=None side3 = ImageEnhance.Brightness(side3).enhance(0.9) side3.putalpha(sidealpha) - composite.alpha_over(img, side3, (0,6), side3) + composite.alpha_over(img, side3, (0,6 + increment), side3) if side4 != None : side4 = transform_image_side(side4, blockID) @@ -325,11 +353,11 @@ def _build_full_block(top, side1, side2, side3, side4, bottom=None, blockID=None side4 = ImageEnhance.Brightness(side4).enhance(0.8) side4.putalpha(sidealpha) - composite.alpha_over(img, side4, (12,6), side4) + composite.alpha_over(img, side4, (12,6 + increment), side4) if top != None : top = transform_image(top, blockID) - composite.alpha_over(img, top, (0,0), top) + composite.alpha_over(img, top, (0, increment), top) return img @@ -516,6 +544,52 @@ def generate_special_texture(blockID, data): return (img.convert("RGB"), img.split()[3]) + if blockID == 26: # bed + increment = 5 + left_face = None + right_face = None + if data & 0x8 == 0x8: # head of the bed + top = terrain_images[135] + if data & 0x00 == 0x00: # head pointing to West + top = top.copy().rotate(270) + left_face = terrain_images[151] + right_face = terrain_images[152] + if data & 0x01 == 0x01: # ... North + top = top.rotate(270) + left_face = terrain_images[152] + right_face = terrain_images[151] + if data & 0x02 == 0x02: # East + top = top.rotate(180) + left_face = terrain_images[151].transpose(Image.FLIP_LEFT_RIGHT) + right_face = None + if data & 0x03 == 0x03: # South + right_face = None + right_face = terrain_images[151].transpose(Image.FLIP_LEFT_RIGHT) + + else: # foot of the bed + top = terrain_images[134] + if data & 0x00 == 0x00: # head pointing to West + top = top.rotate(270) + left_face = terrain_images[150] + right_face = None + if data & 0x01 == 0x01: # ... North + top = top.rotate(270) + left_face = None + right_face = terrain_images[150] + if data & 0x02 == 0x02: # East + top = top.rotate(180) + left_face = terrain_images[150].transpose(Image.FLIP_LEFT_RIGHT) + right_face = terrain_images[149].transpose(Image.FLIP_LEFT_RIGHT) + if data & 0x03 == 0x03: # South + left_face = terrain_images[149] + right_face = terrain_images[150].transpose(Image.FLIP_LEFT_RIGHT) + + top = (top, increment) + img = _build_full_block(top, None, None, left_face, right_face) + + return (img.convert("RGB"), img.split()[3]) + + if blockID == 35: # wool if data == 0: # white top = side = terrain_images[64] @@ -1306,9 +1380,9 @@ def getBiomeData(worlddir, chunkX, chunkY): # (when adding new blocks here and in generate_special_textures, # please, if possible, keep the ascending order of blockid value) -special_blocks = set([ 2, 6, 9, 17, 18, 23, 27, 28, 35, 43, 44, 50, 51, - 53, 54, 55, 58, 59, 61, 62, 64, 65, 66, 67, 71, 75, - 76, 85, 86, 90, 91, 92]) +special_blocks = set([ 2, 6, 9, 17, 18, 26, 23, 27, 28, 35, 43, 44, 50, + 51, 53, 54, 55, 58, 59, 61, 62, 64, 65, 66, 67, 71, + 75, 76, 85, 86, 90, 91, 92]) # this is a map of special blockIDs to a list of all # possible values for ancillary data that it might have. @@ -1318,6 +1392,7 @@ special_map = {} special_map[6] = range(16) # saplings: usual, spruce, birch and future ones (rendered as usual saplings) special_map[9] = range(32) # water: spring,flowing, waterfall, and others (unknown) ancildata values, uses pseudo data special_map[17] = range(4) # wood: normal, birch and pine +special_map[26] = range(12) # bed, orientation special_map[23] = range(6) # dispensers, orientation special_map[27] = range(14) # powered rail, orientation/slope and powered/unpowered special_map[28] = range(6) # detector rail, orientation/slope From 808bfb7cfe42944df02adfe94f351d77f2ad41ba Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Sun, 8 May 2011 13:04:36 +0200 Subject: [PATCH 72/78] Add repeaters without torches, make needed changes in rendermode-normal for edge block lines. Delete some non used code in cake. --- src/rendermode-normal.c | 2 +- textures.py | 30 ++++++++++++++++++++++++++---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/rendermode-normal.c b/src/rendermode-normal.c index be14a92..b4118e3 100644 --- a/src/rendermode-normal.c +++ b/src/rendermode-normal.c @@ -177,7 +177,7 @@ rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject * int increment=0; if (state->block == 44) // half-step increment=6; - else if (state->block == 78) // snow + 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)) { diff --git a/textures.py b/textures.py index 72fec24..fced944 100644 --- a/textures.py +++ b/textures.py @@ -1296,10 +1296,30 @@ def generate_special_texture(blockID, data): composite.alpha_over(img, side, (2,12), side) composite.alpha_over(img, otherside, (10,12), otherside) composite.alpha_over(img, top, (0,8), top) + + return (img.convert("RGB"), img.split()[3]) + + + if blockID in (93, 94): # redstone repeaters, ON and OFF + + top = terrain_images[131] if blockID == 93 else terrain_images[147] + side = terrain_images[5] + increment = 9 + + if (data & 0x3) == 0: # pointing east + pass + + if (data & 0x3) == 1: # pointing south + top = top.rotate(270) + + if (data & 0x3) == 2: # pointing west + top = top.rotate(180) + + if (data & 0x3) == 3: # pointing north + top = top.rotate(90) + + img = _build_full_block( (top, increment), None, None, side, side) - #~ composite.alpha_over(img, side, (2,6), side) - #~ composite.alpha_over(img, otherside, (10,6), otherside) - #~ composite.alpha_over(img, top, (0,2), top) return (img.convert("RGB"), img.split()[3]) @@ -1382,7 +1402,7 @@ def getBiomeData(worlddir, chunkX, chunkY): special_blocks = set([ 2, 6, 9, 17, 18, 26, 23, 27, 28, 35, 43, 44, 50, 51, 53, 54, 55, 58, 59, 61, 62, 64, 65, 66, 67, 71, - 75, 76, 85, 86, 90, 91, 92]) + 75, 76, 85, 86, 90, 91, 92, 93, 94]) # this is a map of special blockIDs to a list of all # possible values for ancillary data that it might have. @@ -1420,6 +1440,8 @@ special_map[86] = range(5) # pumpkin, orientation special_map[90] = (1,2,4,8) # portal, in 2 orientations, 4 cases, uses pseudo data special_map[91] = range(5) # jack-o-lantern, orientation special_map[92] = range(6) # cake! +special_map[93] = range(16) # OFF redstone repeater, orientation and delay (delay not implemented) +special_map[94] = range(16) # ON redstone repeater, orientation and delay (delay not implemented) # grass and leaves are graysacle in terrain.png # we treat them as special so we can manually tint them From fc99f9f978420ac8bca6ff8b371047930d243283 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Sun, 8 May 2011 16:18:56 +0200 Subject: [PATCH 73/78] Add torches to the repeaters. --- textures.py | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/textures.py b/textures.py index fced944..764df40 100644 --- a/textures.py +++ b/textures.py @@ -1301,6 +1301,8 @@ def generate_special_texture(blockID, data): if blockID in (93, 94): # redstone repeaters, ON and OFF + # NOTE: this function uses the redstone torches generated above, + # this must run after the function of the torches. top = terrain_images[131] if blockID == 93 else terrain_images[147] side = terrain_images[5] @@ -1320,6 +1322,99 @@ def generate_special_texture(blockID, data): img = _build_full_block( (top, increment), None, None, side, side) + # paste redstone torches everywhere! + t = specialblockmap[(75,5)] if blockID == 93 else specialblockmap[(76,5)] + torch = t[0].copy() # textures are stored as tuples (RGB,A) + torch.putalpha(t[1]) + + # the torch is too tall for the repeater, crop the bottom. + ImageDraw.Draw(torch).rectangle((0,16,24,24),outline=(0,0,0,0),fill=(0,0,0,0)) + + # touch up the 3d effect with big rectangles, just in case, for other texture packs + ImageDraw.Draw(torch).rectangle((0,24,10,15),outline=(0,0,0,0),fill=(0,0,0,0)) + ImageDraw.Draw(torch).rectangle((12,15,24,24),outline=(0,0,0,0),fill=(0,0,0,0)) + + # torch positions for every redstone torch orientation. + # + # This is a horrible list of torch orientations. I tried to + # obtain these orientations by rotating the positions for one + # orientation, but pixel rounding is horrible and messes the + # torches. + + if (data & 0x3) == 0: # pointing east + if (data & 0xC) == 0: # one tick delay + moving_torch = (1,1) + static_torch = (-3,-1) + + elif (data & 0xC) == 4: # two ticks delay + moving_torch = (2,2) + static_torch = (-3,-1) + + elif (data & 0xC) == 8: # three ticks delay + moving_torch = (3,2) + static_torch = (-3,-1) + + elif (data & 0xC) == 12: # four ticks delay + moving_torch = (4,3) + static_torch = (-3,-1) + + elif (data & 0x3) == 1: # pointing south + if (data & 0xC) == 0: # one tick delay + moving_torch = (1,1) + static_torch = (5,-1) + + elif (data & 0xC) == 4: # two ticks delay + moving_torch = (2,0) + static_torch = (5,-1) + + elif (data & 0xC) == 8: # three ticks delay + moving_torch = (3,0) + static_torch = (5,-1) + + elif (data & 0xC) == 12: # four ticks delay + moving_torch = (4,-1) + static_torch = (5,-1) + + elif (data & 0x3) == 2: # pointing west + if (data & 0xC) == 0: # one tick delay + moving_torch = (1,1) + static_torch = (5,3) + + elif (data & 0xC) == 4: # two ticks delay + moving_torch = (0,0) + static_torch = (5,3) + + elif (data & 0xC) == 8: # three ticks delay + moving_torch = (-1,0) + static_torch = (5,3) + + elif (data & 0xC) == 12: # four ticks delay + moving_torch = (-2,-1) + static_torch = (5,3) + + elif (data & 0x3) == 3: # pointing north + if (data & 0xC) == 0: # one tick delay + moving_torch = (1,1) + static_torch = (-3,3) + + elif (data & 0xC) == 4: # two ticks delay + moving_torch = (2,0) + static_torch = (-3,3) + + elif (data & 0xC) == 8: # three ticks delay + moving_torch = (3,0) + static_torch = (-3,3) + + elif (data & 0xC) == 12: # four ticks delay + moving_torch = (4,-1) + static_torch = (-3,3) + + # this paste order it's ok for east and south orientation + # but it's wrong for north and west orientations. But using the + # default texture pack the torches are small enough to no overlap. + composite.alpha_over(img, torch, static_torch, torch) + composite.alpha_over(img, torch, moving_torch, torch) + return (img.convert("RGB"), img.split()[3]) From 86b891d9f2bba190d8c4f22ee214e4c48bfc8a92 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Sun, 8 May 2011 16:25:35 +0200 Subject: [PATCH 74/78] Fix the top texture for TNT. Remove non helpful comments or outdated comments. --- textures.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/textures.py b/textures.py index 764df40..543458a 100644 --- a/textures.py +++ b/textures.py @@ -374,13 +374,13 @@ def _build_blockimages(): # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 topids = [ -1, 1, 0, 2, 16, 4, -1, 17,205,205,237,237, 18, 19, 32, 33, # 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 - 34, -1, 52, 48, 49,160,144, -1,176, 74, -1, -1, -1, -1, -1, -1, # Cloths are left out, sandstone (it has top, side, and bottom wich is ignored here), note block + 34, -1, 52, 48, 49,160,144, -1,176, 74, -1, -1, -1, -1, -1, -1, # 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, 4, # Gold/iron blocks? Doublestep? TNT from above? + -1, -1, -1, -1, -1, 13, 12, 29, 28, 23, 22, -1, -1, 7, 9, 4, # 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 - 36, 37, -1, -1, 65, -1, -1, -1, 50, 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, -1, -1, 50, 24, -1, -1, 86, -1, -1, -1, # 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 - -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 + -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 66, 69, 72, 73, 75, -1,102,103,104,105,-1, 102 # clay? ] From 4297e49f203bb7cf26d0d2db04f6c222a1b332e3 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Sun, 8 May 2011 12:05:04 -0400 Subject: [PATCH 75/78] Add portal.png to data_files for py2exe --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 497b5ac..415e1a4 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ setup_kwargs['cmdclass'] = {} if py2exe is not None: 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', 'textures/portal.png']), ('', ['overviewerConfig.js', 'COPYING.txt', 'README.rst']), ('web_assets', glob.glob('web_assets/*'))] setup_kwargs['zipfile'] = None From ef8dd359ac68cdd34470363014d1586369d4bd7e Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Mon, 9 May 2011 01:58:42 +0200 Subject: [PATCH 76/78] Make cactus as is in game. Improve cake. Add web block, at the moment is rendered as a sprite. --- chunk.py | 6 +++--- textures.py | 32 ++++++++++++++------------------ 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/chunk.py b/chunk.py index f44b4db..894c767 100644 --- a/chunk.py +++ b/chunk.py @@ -114,9 +114,9 @@ def get_tileentity_data(level): return data # This set holds blocks ids that can be seen through, for occlusion calculations -transparent_blocks = set([ 0, 6, 8, 9, 18, 20, 26, 27, 28, 37, 38, 39, 40, 44, - 50, 51, 52, 53, 55, 59, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 74, 75, 76, 77, 78, 79, 81, 83, 85, 90, 92]) +transparent_blocks = set([ 0, 6, 8, 9, 18, 20, 26, 27, 28, 30, 37, 38, 39, 40, + 44, 50, 51, 52, 53, 55, 59, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 74, 75, 76, 77, 78, 79, 81, 83, 85, 90, 92]) # 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, 21, 22, diff --git a/textures.py b/textures.py index 543458a..b5fb86a 100644 --- a/textures.py +++ b/textures.py @@ -121,14 +121,9 @@ def transform_image(img, blockID=None): """ - if blockID in (81,92): # cacti and cake - # Resize to 15x15, since the cactus and the cake textures are a little smaller than the other textures - img = img.resize((15, 15), Image.ANTIALIAS) - - else: - # Resize to 17x17, since the diagonal is approximately 24 pixels, a nice - # even number that can be split in half twice - img = img.resize((17, 17), Image.ANTIALIAS) + # Resize to 17x17, since the diagonal is approximately 24 pixels, a nice + # even number that can be split in half twice + img = img.resize((17, 17), Image.ANTIALIAS) # Build the Affine transformation matrix for this perspective transform = numpy.matrix(numpy.identity(3)) @@ -223,7 +218,7 @@ def _build_block(top, side, blockID=None): otherside.putalpha(othersidealpha) ## special case for non-block things - if blockID in (37,38,6,39,40,83): ## flowers, sapling, mushrooms, reeds + if blockID in (37,38,6,39,40,83,30): ## flowers, sapling, mushrooms, reeds, web # # instead of pasting these blocks at the cube edges, place them in the middle: # and omit the top @@ -233,9 +228,9 @@ def _build_block(top, side, blockID=None): if blockID in (81,): # cacti! - composite.alpha_over(img, side, (2,6), side) - composite.alpha_over(img, otherside, (10,6), otherside) - composite.alpha_over(img, top, (0,2), top) + composite.alpha_over(img, side, (1,6), side) + composite.alpha_over(img, otherside, (11,6), otherside) + composite.alpha_over(img, top, (0,0), top) elif blockID in (44,): # half step # shift each texture down 6 pixels composite.alpha_over(img, side, (0,12), side) @@ -374,7 +369,7 @@ def _build_blockimages(): # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 topids = [ -1, 1, 0, 2, 16, 4, -1, 17,205,205,237,237, 18, 19, 32, 33, # 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 - 34, -1, 52, 48, 49,160,144, -1,176, 74, -1, -1, -1, -1, -1, -1, + 34, -1, 52, 48, 49,160,144, -1,176, 74, -1, -1, -1, -1, 11, -1, # 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, 9, 4, # 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 @@ -391,7 +386,7 @@ def _build_blockimages(): # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 sideids = [ -1, 1, 3, 2, 16, 4, -1, 17,205,205,237,237, 18, 19, 32, 33, # 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 - 34, -1, 52, 48, 49,160,144, -1,192, 74, -1, -1,- 1, -1, -1, -1, + 34, -1, 52, 48, 49,160,144, -1,192, 74, -1, -1,- 1, -1, 11, -1, # 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, # 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 @@ -399,7 +394,7 @@ def _build_blockimages(): # 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 -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 - 66, 69, 72, 73, 74,-1 ,118,103,104,105, -1, 118 + 66, 70, 72, 73, 74,-1 ,118,103,104,105, -1, 118 ] # This maps block id to the texture that goes on the side of the block @@ -1293,9 +1288,10 @@ def generate_special_texture(blockID, data): img = Image.new("RGBA", (24,24), (38,92,255,0)) - composite.alpha_over(img, side, (2,12), side) - composite.alpha_over(img, otherside, (10,12), otherside) - composite.alpha_over(img, top, (0,8), top) + composite.alpha_over(img, side, (1,12), side) + composite.alpha_over(img, otherside, (11,13), otherside) # workaround, fixes a hole + composite.alpha_over(img, otherside, (12,12), otherside) + composite.alpha_over(img, top, (0,6), top) return (img.convert("RGB"), img.split()[3]) From d735053febb1aa08749986e69fd3547328e49ca7 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Mon, 9 May 2011 02:15:31 +0200 Subject: [PATCH 77/78] Add repeaters to the list of transaprent blocks. Fixes problem in night rendermode showing repeaters as strange black block. --- chunk.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chunk.py b/chunk.py index 894c767..048b650 100644 --- a/chunk.py +++ b/chunk.py @@ -116,7 +116,8 @@ def get_tileentity_data(level): # This set holds blocks ids that can be seen through, for occlusion calculations transparent_blocks = set([ 0, 6, 8, 9, 18, 20, 26, 27, 28, 30, 37, 38, 39, 40, 44, 50, 51, 52, 53, 55, 59, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 74, 75, 76, 77, 78, 79, 81, 83, 85, 90, 92]) + 70, 71, 72, 74, 75, 76, 77, 78, 79, 81, 83, 85, 90, 92, + 93, 94]) # 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, 21, 22, From d92a0bc59cb3d768236336ccf9b35711d450cfbd Mon Sep 17 00:00:00 2001 From: Michael Writhe Date: Mon, 9 May 2011 09:37:09 -0600 Subject: [PATCH 78/78] allowed for opacity of fill/stroke to be definned independantly. will continue to support legacy declaration of opacity --- web_assets/overviewer.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/web_assets/overviewer.js b/web_assets/overviewer.js index 6220a16..eea2f7d 100644 --- a/web_assets/overviewer.js +++ b/web_assets/overviewer.js @@ -368,6 +368,14 @@ var overviewer = { clickable = false; // if it doesn't have a name, we dont have to show it. } + if(region.opacity) { + var strokeOpacity = region.opacity; + var fillOpacity = region.opacity * 0.25; + } else { + var strokeOpacity = region.strokeOpacity; + var fillOpacity = region.fillOpacity; + } + if (region.closed) { var shape = new google.maps.Polygon({ 'name': name, @@ -375,10 +383,10 @@ var overviewer = { 'geodesic': false, 'map': null, 'strokeColor': region.color, - 'strokeOpacity': region.opacity, + 'strokeOpacity': strokeOpacity, 'strokeWeight': overviewerConfig.CONST.regionStrokeWeight, 'fillColor': region.color, - 'fillOpacity': region.opacity * 0.25, + 'fillOpacity': fillOpacity, 'zIndex': j, 'paths': converted }); @@ -389,7 +397,7 @@ var overviewer = { 'geodesic': false, 'map': null, 'strokeColor': region.color, - 'strokeOpacity': region.opacity, + 'strokeOpacity': strokeOpacity, 'strokeWeight': overviewerConfig.CONST.regionStrokeWeight, 'zIndex': j, 'path': converted