Merge branch 'overlays' into dtt-c-render
Conflicts: quadtree.py web_assets/functions.js
This commit is contained in:
4
chunk.py
4
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
|
# 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,
|
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,
|
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
|
# This set holds block ids that are fluid blocks
|
||||||
fluid_blocks = set([8,9,10,11])
|
fluid_blocks = set([8,9,10,11])
|
||||||
@@ -463,7 +463,7 @@ def generate_facemasks():
|
|||||||
return (top, left, right)
|
return (top, left, right)
|
||||||
facemasks = generate_facemasks()
|
facemasks = generate_facemasks()
|
||||||
black_color = Image.new("RGB", (24,24), (0,0,0))
|
black_color = Image.new("RGB", (24,24), (0,0,0))
|
||||||
red_color = Image.new("RGB", (24,24), (229,36,38))
|
white_color = Image.new("RGB", (24,24), (255,255,255))
|
||||||
|
|
||||||
# Render 128 different color images for color coded depth blending in cave mode
|
# Render 128 different color images for color coded depth blending in cave mode
|
||||||
def generate_depthcolors():
|
def generate_depthcolors():
|
||||||
|
|||||||
35
config.js
35
config.js
@@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
var config = {
|
var config = {
|
||||||
fileExt: '{imgformat}',
|
|
||||||
tileSize: 384,
|
tileSize: 384,
|
||||||
defaultZoom: 2,
|
defaultZoom: 2,
|
||||||
maxZoom: {maxzoom},
|
maxZoom: {maxzoom},
|
||||||
@@ -33,21 +32,45 @@ var signGroups = [
|
|||||||
{label: "All", match: function(s) {return true}},
|
{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
|
/* 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
|
* listed. When more than one are provided, controls to switch between them are provided, with
|
||||||
* the first one being the default.
|
* the first one being the default.
|
||||||
*
|
*
|
||||||
* Required:
|
* Required:
|
||||||
* label : string. Displayed on the control.
|
* label : string. Displayed on the control.
|
||||||
* path : string. Location of the rendered tiles.
|
* path : string. Location of the rendered tiles.
|
||||||
* Optional:
|
* Optional:
|
||||||
* base : string. Base of the url path for tile locations, useful for serving tiles from a different server than the js/html server.
|
* base : string. Base of the url path for tile locations, useful for serving tiles from a different server than the js/html server.
|
||||||
|
* 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=[
|
var mapTypeData=[
|
||||||
{'label': 'Unlit', 'path': 'tiles'},
|
{'label': 'Unlit', 'path': 'tiles'},
|
||||||
// {'label': 'Day', 'path': 'lighting/tiles'},
|
// {'label': 'Day', 'path': 'lighting/tiles'},
|
||||||
// {'label': 'Night', 'path': 'night/tiles'},
|
// {'label': 'Night', 'path': 'night/tiles', 'imgformat': 'jpg'},
|
||||||
// {'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}
|
||||||
];
|
];
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
16
googlemap.py
16
googlemap.py
@@ -23,6 +23,7 @@ from time import strftime, gmtime
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
import util
|
import util
|
||||||
|
from c_overviewer import get_render_mode_inheritance
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This module has routines related to generating a Google Maps-based
|
This module has routines related to generating a Google Maps-based
|
||||||
@@ -73,12 +74,11 @@ class MapGen(object):
|
|||||||
raise ValueError("there must be at least one quadtree to work on")
|
raise ValueError("there must be at least one quadtree to work on")
|
||||||
|
|
||||||
self.destdir = quadtrees[0].destdir
|
self.destdir = quadtrees[0].destdir
|
||||||
self.imgformat = quadtrees[0].imgformat
|
|
||||||
self.world = quadtrees[0].world
|
self.world = quadtrees[0].world
|
||||||
self.p = quadtrees[0].p
|
self.p = quadtrees[0].p
|
||||||
for i in quadtrees:
|
for i in quadtrees:
|
||||||
if i.destdir != self.destdir or i.imgformat != self.imgformat or i.world != self.world:
|
if i.destdir != self.destdir or i.world != self.world:
|
||||||
raise ValueError("all the given quadtrees must have the same destdir")
|
raise ValueError("all the given quadtrees must have the same destdir and world")
|
||||||
|
|
||||||
self.quadtrees = quadtrees
|
self.quadtrees = quadtrees
|
||||||
|
|
||||||
@@ -86,14 +86,11 @@ class MapGen(object):
|
|||||||
"""Writes out config.js, marker.js, and region.js
|
"""Writes out config.js, marker.js, and region.js
|
||||||
Copies web assets into the destdir"""
|
Copies web assets into the destdir"""
|
||||||
zoomlevel = self.p
|
zoomlevel = self.p
|
||||||
imgformat = self.imgformat
|
|
||||||
configpath = os.path.join(util.get_program_path(), "config.js")
|
configpath = os.path.join(util.get_program_path(), "config.js")
|
||||||
|
|
||||||
config = open(configpath, 'r').read()
|
config = open(configpath, 'r').read()
|
||||||
config = config.replace(
|
config = config.replace(
|
||||||
"{maxzoom}", str(zoomlevel))
|
"{maxzoom}", str(zoomlevel))
|
||||||
config = config.replace(
|
|
||||||
"{imgformat}", str(imgformat))
|
|
||||||
|
|
||||||
config = config.replace("{spawn_coords}",
|
config = config.replace("{spawn_coords}",
|
||||||
json.dumps(list(self.world.spawn)))
|
json.dumps(list(self.world.spawn)))
|
||||||
@@ -102,7 +99,10 @@ class MapGen(object):
|
|||||||
|
|
||||||
# create generated map type data, from given quadtrees
|
# create generated map type data, from given quadtrees
|
||||||
maptypedata = map(lambda q: {'label' : q.rendermode.capitalize(),
|
maptypedata = map(lambda q: {'label' : q.rendermode.capitalize(),
|
||||||
'path' : q.tiledir}, self.quadtrees)
|
'path' : q.tiledir,
|
||||||
|
'overlay' : 'overlay' in get_render_mode_inheritance(q.rendermode),
|
||||||
|
'imgformat' : q.imgformat},
|
||||||
|
self.quadtrees)
|
||||||
config = config.replace("{maptypedata}", json.dumps(maptypedata))
|
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, "config.js"), 'w') as output:
|
||||||
@@ -114,7 +114,7 @@ class MapGen(object):
|
|||||||
for quadtree in self.quadtrees:
|
for quadtree in self.quadtrees:
|
||||||
tileDir = os.path.join(self.destdir, quadtree.tiledir)
|
tileDir = os.path.join(self.destdir, quadtree.tiledir)
|
||||||
if not os.path.exists(tileDir): os.mkdir(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:
|
# copy web assets into destdir:
|
||||||
mirror_dir(os.path.join(util.get_program_path(), "web_assets"), self.destdir)
|
mirror_dir(os.path.join(util.get_program_path(), "web_assets"), self.destdir)
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ from PIL import Image
|
|||||||
|
|
||||||
import nbt
|
import nbt
|
||||||
import chunk
|
import chunk
|
||||||
|
from c_overviewer import get_render_mode_inheritance
|
||||||
from optimizeimages import optimize_image
|
from optimizeimages import optimize_image
|
||||||
import composite
|
import composite
|
||||||
|
|
||||||
@@ -62,11 +63,11 @@ class QuadtreeGen(object):
|
|||||||
self.imgformat = imgformat
|
self.imgformat = imgformat
|
||||||
self.optimizeimg = optimizeimg
|
self.optimizeimg = optimizeimg
|
||||||
self.bgcolor = bgcolor
|
self.bgcolor = bgcolor
|
||||||
|
|
||||||
self.lighting = rendermode in ("lighting", "night", "spawn")
|
|
||||||
self.night = rendermode in ("night", "spawn")
|
|
||||||
self.spawn = rendermode in ("spawn",)
|
|
||||||
self.rendermode = rendermode
|
self.rendermode = rendermode
|
||||||
|
|
||||||
|
# force png renderformat if we're using an overlay mode
|
||||||
|
if 'overlay' in get_render_mode_inheritance(rendermode):
|
||||||
|
self.imgformat = "png"
|
||||||
|
|
||||||
# Make the destination dir
|
# Make the destination dir
|
||||||
if not os.path.exists(destdir):
|
if not os.path.exists(destdir):
|
||||||
|
|||||||
8
setup.py
8
setup.py
@@ -54,10 +54,14 @@ try:
|
|||||||
except:
|
except:
|
||||||
pil_include = []
|
pil_include = []
|
||||||
|
|
||||||
c_overviewer_files = ['src/main.c', 'src/composite.c', 'src/iterate.c', 'src/endian.c']
|
# used to figure out what files to compile
|
||||||
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']
|
render_modes = ['normal', 'overlay', 'lighting', 'night', 'spawn', 'cave']
|
||||||
|
|
||||||
|
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/Draw.c']
|
c_overviewer_files += ['src/Draw.c']
|
||||||
c_overviewer_includes = ['src/overviewer.h', 'src/rendermodes.h']
|
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=[]))
|
setup_kwargs['ext_modules'].append(Extension('c_overviewer', c_overviewer_files, include_dirs=['.', numpy_include] + pil_include, depends=c_overviewer_includes, extra_link_args=[]))
|
||||||
|
|
||||||
# tell build_ext to build the extension in-place
|
# tell build_ext to build the extension in-place
|
||||||
|
|||||||
@@ -273,7 +273,8 @@ alpha_over_wrap(PyObject *self, PyObject *args)
|
|||||||
* also, it multiplies instead of doing an over operation
|
* also, it multiplies instead of doing an over operation
|
||||||
*/
|
*/
|
||||||
PyObject *
|
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) {
|
PyObject *mask, int dx, int dy, int xsize, int ysize) {
|
||||||
/* libImaging handles */
|
/* libImaging handles */
|
||||||
Imaging imDest, imMask;
|
Imaging imDest, imMask;
|
||||||
@@ -332,9 +333,11 @@ tint_with_mask(PyObject *dest, unsigned char sr, unsigned char sg, unsigned char
|
|||||||
out++;
|
out++;
|
||||||
*out = MULDIV255(*out, sb, tmp1);
|
*out = MULDIV255(*out, sb, tmp1);
|
||||||
out++;
|
out++;
|
||||||
|
*out = MULDIV255(*out, sa, tmp1);
|
||||||
|
out++;
|
||||||
} else if (*inmask == 0) {
|
} else if (*inmask == 0) {
|
||||||
/* do nothing -- source is fully transparent */
|
/* do nothing -- source is fully transparent */
|
||||||
out += 3;
|
out += 4;
|
||||||
} else {
|
} else {
|
||||||
/* general case */
|
/* general case */
|
||||||
|
|
||||||
@@ -345,9 +348,10 @@ tint_with_mask(PyObject *dest, unsigned char sr, unsigned char sg, unsigned char
|
|||||||
out++;
|
out++;
|
||||||
*out = MULDIV255(*out, (255 - *inmask) + MULDIV255(sb, *inmask, tmp1), tmp2);
|
*out = MULDIV255(*out, (255 - *inmask) + MULDIV255(sb, *inmask, tmp1), tmp2);
|
||||||
out++;
|
out++;
|
||||||
|
*out = MULDIV255(*out, (255 - *inmask) + MULDIV255(sa, *inmask, tmp1), tmp2);
|
||||||
|
out++;
|
||||||
}
|
}
|
||||||
|
|
||||||
out++;
|
|
||||||
inmask += mask_stride;
|
inmask += mask_stride;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
src/main.c
10
src/main.c
@@ -25,14 +25,24 @@ PyObject *get_extension_version(PyObject *self, PyObject *args) {
|
|||||||
static PyMethodDef COverviewerMethods[] = {
|
static PyMethodDef COverviewerMethods[] = {
|
||||||
{"alpha_over", alpha_over_wrap, METH_VARARGS,
|
{"alpha_over", alpha_over_wrap, METH_VARARGS,
|
||||||
"alpha over composite function"},
|
"alpha over composite function"},
|
||||||
|
|
||||||
{"render_loop", chunk_render, METH_VARARGS,
|
{"render_loop", chunk_render, METH_VARARGS,
|
||||||
"Renders stuffs"},
|
"Renders stuffs"},
|
||||||
|
|
||||||
{"get_render_modes", get_render_modes, METH_VARARGS,
|
{"get_render_modes", get_render_modes, METH_VARARGS,
|
||||||
"returns available render modes"},
|
"returns available render modes"},
|
||||||
{"get_render_mode_info", get_render_mode_info, METH_VARARGS,
|
{"get_render_mode_info", get_render_mode_info, METH_VARARGS,
|
||||||
"returns info for a particular render mode"},
|
"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,
|
{"extension_version", get_extension_version, METH_VARARGS,
|
||||||
"Returns the extension version"},
|
"Returns the extension version"},
|
||||||
|
|
||||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,8 @@ PyObject *alpha_over(PyObject *dest, PyObject *src, PyObject *mask,
|
|||||||
PyObject *alpha_over_full(PyObject *dest, PyObject *src, PyObject *mask, float overall_alpha,
|
PyObject *alpha_over_full(PyObject *dest, PyObject *src, PyObject *mask, float overall_alpha,
|
||||||
int dx, int dy, int xsize, int ysize);
|
int dx, int dy, int xsize, int ysize);
|
||||||
PyObject *alpha_over_wrap(PyObject *self, PyObject *args);
|
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);
|
PyObject *mask, int dx, int dy, int xsize, int ysize);
|
||||||
|
|
||||||
/* in iterate.c */
|
/* in iterate.c */
|
||||||
|
|||||||
@@ -219,12 +219,13 @@ rendermode_cave_draw(void *data, RenderState *state, PyObject *src, PyObject *ma
|
|||||||
g = PyInt_AsLong(PyList_GetItem(self->depth_colors, 1 + z*3));
|
g = PyInt_AsLong(PyList_GetItem(self->depth_colors, 1 + z*3));
|
||||||
b = PyInt_AsLong(PyList_GetItem(self->depth_colors, 2 + 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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderModeInterface rendermode_cave = {
|
RenderModeInterface rendermode_cave = {
|
||||||
"cave", "render only caves in normal mode",
|
"cave", "render only caves in normal mode",
|
||||||
|
&rendermode_normal,
|
||||||
sizeof(RenderModeCave),
|
sizeof(RenderModeCave),
|
||||||
rendermode_cave_start,
|
rendermode_cave_start,
|
||||||
rendermode_cave_finish,
|
rendermode_cave_finish,
|
||||||
|
|||||||
@@ -229,6 +229,7 @@ rendermode_lighting_draw(void *data, RenderState *state, PyObject *src, PyObject
|
|||||||
|
|
||||||
RenderModeInterface rendermode_lighting = {
|
RenderModeInterface rendermode_lighting = {
|
||||||
"lighting", "draw shadows from the lighting data",
|
"lighting", "draw shadows from the lighting data",
|
||||||
|
&rendermode_normal,
|
||||||
sizeof(RenderModeLighting),
|
sizeof(RenderModeLighting),
|
||||||
rendermode_lighting_start,
|
rendermode_lighting_start,
|
||||||
rendermode_lighting_finish,
|
rendermode_lighting_finish,
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ rendermode_night_draw(void *data, RenderState *state, PyObject *src, PyObject *m
|
|||||||
|
|
||||||
RenderModeInterface rendermode_night = {
|
RenderModeInterface rendermode_night = {
|
||||||
"night", "like \"lighting\", except at night",
|
"night", "like \"lighting\", except at night",
|
||||||
|
&rendermode_lighting,
|
||||||
sizeof(RenderModeNight),
|
sizeof(RenderModeNight),
|
||||||
rendermode_night_start,
|
rendermode_night_start,
|
||||||
rendermode_night_finish,
|
rendermode_night_finish,
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject *
|
|||||||
b = PyInt_AsLong(PyTuple_GET_ITEM(color, 2));
|
b = PyInt_AsLong(PyTuple_GET_ITEM(color, 2));
|
||||||
Py_DECREF(color);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,6 +221,7 @@ rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject *
|
|||||||
|
|
||||||
RenderModeInterface rendermode_normal = {
|
RenderModeInterface rendermode_normal = {
|
||||||
"normal", "nothing special, just render the blocks",
|
"normal", "nothing special, just render the blocks",
|
||||||
|
NULL,
|
||||||
sizeof(RenderModeNormal),
|
sizeof(RenderModeNormal),
|
||||||
rendermode_normal_start,
|
rendermode_normal_start,
|
||||||
rendermode_normal_finish,
|
rendermode_normal_finish,
|
||||||
|
|||||||
137
src/rendermode-overlay.c
Normal file
137
src/rendermode-overlay.c
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Minecraft Overviewer.
|
||||||
|
*
|
||||||
|
* Minecraft Overviewer is free software: you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as published
|
||||||
|
* by the Free Software Foundation, either version 3 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* Minecraft Overviewer is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||||
|
* Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with the Overviewer. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "overviewer.h"
|
||||||
|
|
||||||
|
static 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;
|
||||||
|
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");
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rendermode_overlay_finish(void *data, RenderState *state) {
|
||||||
|
RenderModeOverlay *self = (RenderModeOverlay *)data;
|
||||||
|
|
||||||
|
Py_DECREF(self->facemask_top);
|
||||||
|
Py_DECREF(self->white_color);
|
||||||
|
Py_DECREF(self->solid_blocks);
|
||||||
|
Py_DECREF(self->fluid_blocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
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 */
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* get our color info */
|
||||||
|
self->get_color(data, state, &r, &g, &b, &a);
|
||||||
|
|
||||||
|
/* do the overlay */
|
||||||
|
if (a > 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderModeInterface rendermode_overlay = {
|
||||||
|
"overlay", "base rendermode for informational overlays",
|
||||||
|
NULL,
|
||||||
|
sizeof(RenderModeOverlay),
|
||||||
|
rendermode_overlay_start,
|
||||||
|
rendermode_overlay_finish,
|
||||||
|
rendermode_overlay_occluded,
|
||||||
|
rendermode_overlay_draw,
|
||||||
|
};
|
||||||
@@ -18,21 +18,66 @@
|
|||||||
#include "overviewer.h"
|
#include "overviewer.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
int z_light = z + 1;
|
||||||
|
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;
|
||||||
|
|
||||||
|
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, MIN(127, 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 */
|
||||||
|
*a = 240;
|
||||||
|
} else if (MAX(blocklight, skylight - 11) <= 7) {
|
||||||
|
/* hostile mobs spawn at night */
|
||||||
|
*a = 150;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
rendermode_spawn_start(void *data, RenderState *state) {
|
rendermode_spawn_start(void *data, RenderState *state) {
|
||||||
RenderModeSpawn* self;
|
RenderModeSpawn* self;
|
||||||
|
|
||||||
/* first, chain up */
|
/* first, chain up */
|
||||||
int ret = rendermode_night.start(data, state);
|
int ret = rendermode_overlay.start(data, state);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* now do custom initializations */
|
/* now do custom initializations */
|
||||||
self = (RenderModeSpawn *)data;
|
self = (RenderModeSpawn *)data;
|
||||||
self->solid_blocks = PyObject_GetAttrString(state->chunk, "solid_blocks");
|
|
||||||
self->nospawn_blocks = PyObject_GetAttrString(state->chunk, "nospawn_blocks");
|
self->nospawn_blocks = PyObject_GetAttrString(state->chunk, "nospawn_blocks");
|
||||||
self->fluid_blocks = PyObject_GetAttrString(state->chunk, "fluid_blocks");
|
self->blocklight = PyObject_GetAttrString(state->self, "blocklight");
|
||||||
self->red_color = PyObject_GetAttrString(state->chunk, "red_color");
|
self->skylight = PyObject_GetAttrString(state->self, "skylight");
|
||||||
|
|
||||||
|
/* setup custom color */
|
||||||
|
self->parent.get_color = get_color;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -40,85 +85,31 @@ rendermode_spawn_start(void *data, RenderState *state) {
|
|||||||
static void
|
static void
|
||||||
rendermode_spawn_finish(void *data, RenderState *state) {
|
rendermode_spawn_finish(void *data, RenderState *state) {
|
||||||
/* first free all *our* stuff */
|
/* 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->nospawn_blocks);
|
||||||
Py_DECREF(self->fluid_blocks);
|
Py_DECREF(self->blocklight);
|
||||||
|
Py_DECREF(self->skylight);
|
||||||
|
|
||||||
/* now, chain up */
|
/* now, chain up */
|
||||||
rendermode_night.finish(data, state);
|
rendermode_overlay.finish(data, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
rendermode_spawn_occluded(void *data, RenderState *state) {
|
rendermode_spawn_occluded(void *data, RenderState *state) {
|
||||||
/* no special occlusion here */
|
/* no special occlusion here */
|
||||||
return rendermode_night.occluded(data, state);
|
return rendermode_overlay.occluded(data, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rendermode_spawn_draw(void *data, RenderState *state, PyObject *src, PyObject *mask) {
|
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 */
|
/* draw normally */
|
||||||
rendermode_night.draw(data, state, src, mask);
|
rendermode_overlay.draw(data, state, src, mask);
|
||||||
|
|
||||||
/* reset black_color, if needed */
|
|
||||||
if (old_black_color != NULL) {
|
|
||||||
lighting->black_color = old_black_color;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderModeInterface rendermode_spawn = {
|
RenderModeInterface rendermode_spawn = {
|
||||||
"spawn", "draws red where monsters can spawn at night",
|
"spawn", "draws a red overlay where monsters can spawn at night",
|
||||||
|
&rendermode_overlay,
|
||||||
sizeof(RenderModeSpawn),
|
sizeof(RenderModeSpawn),
|
||||||
rendermode_spawn_start,
|
rendermode_spawn_start,
|
||||||
rendermode_spawn_finish,
|
rendermode_spawn_finish,
|
||||||
|
|||||||
@@ -98,5 +98,87 @@ PyObject *get_render_mode_info(PyObject *self, PyObject *args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Py_DECREF(info);
|
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;
|
||||||
|
RenderModeInterface *iface = NULL;
|
||||||
|
if (!PyArg_ParseTuple(args, "s", &rendermode))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
parents = PyList_New(0);
|
||||||
|
if (!parents)
|
||||||
|
return 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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,12 +38,15 @@
|
|||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
|
|
||||||
/* rendermode interface */
|
/* rendermode interface */
|
||||||
typedef struct {
|
typedef struct _RenderModeInterface RenderModeInterface;
|
||||||
|
struct _RenderModeInterface {
|
||||||
/* the name of this mode */
|
/* the name of this mode */
|
||||||
const char* name;
|
const char* name;
|
||||||
/* the short description of this render mode */
|
/* the short description of this render mode */
|
||||||
const char* description;
|
const char* description;
|
||||||
|
|
||||||
|
/* the rendermode this is derived from, or NULL */
|
||||||
|
RenderModeInterface *parent;
|
||||||
/* the size of the local storage for this rendermode */
|
/* the size of the local storage for this rendermode */
|
||||||
unsigned int data_size;
|
unsigned int data_size;
|
||||||
|
|
||||||
@@ -54,13 +57,16 @@ typedef struct {
|
|||||||
int (*occluded)(void *, RenderState *);
|
int (*occluded)(void *, RenderState *);
|
||||||
/* last two arguments are img and mask, from texture lookup */
|
/* last two arguments are img and mask, from texture lookup */
|
||||||
void (*draw)(void *, RenderState *, PyObject *, PyObject *);
|
void (*draw)(void *, RenderState *, PyObject *, PyObject *);
|
||||||
} RenderModeInterface;
|
};
|
||||||
|
|
||||||
/* figures out the render mode to use from the given ChunkRenderer */
|
/* figures out the render mode to use from the given ChunkRenderer */
|
||||||
RenderModeInterface *get_render_mode(RenderState *state);
|
RenderModeInterface *get_render_mode(RenderState *state);
|
||||||
/* python bindings */
|
/* python bindings */
|
||||||
PyObject *get_render_modes(PyObject *self, PyObject *args);
|
PyObject *get_render_modes(PyObject *self, PyObject *args);
|
||||||
PyObject *get_render_mode_info(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 */
|
/* individual rendermode interface declarations follow */
|
||||||
|
|
||||||
@@ -79,6 +85,20 @@ typedef struct {
|
|||||||
} RenderModeNormal;
|
} RenderModeNormal;
|
||||||
extern RenderModeInterface rendermode_normal;
|
extern RenderModeInterface rendermode_normal;
|
||||||
|
|
||||||
|
/* OVERLAY */
|
||||||
|
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;
|
||||||
|
/* 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;
|
||||||
|
|
||||||
/* LIGHTING */
|
/* LIGHTING */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* inherits from normal render mode */
|
/* inherits from normal render mode */
|
||||||
@@ -109,13 +129,12 @@ extern RenderModeInterface rendermode_night;
|
|||||||
|
|
||||||
/* SPAWN */
|
/* SPAWN */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* inherits from night */
|
/* inherits from overlay */
|
||||||
RenderModeNight parent;
|
RenderModeOverlay parent;
|
||||||
|
|
||||||
/* used to figure out which blocks are spawnable */
|
/* used to figure out which blocks are spawnable */
|
||||||
PyObject *solid_blocks, *nospawn_blocks, *fluid_blocks;
|
PyObject *nospawn_blocks;
|
||||||
/* replacement for black_color */
|
PyObject *skylight, *blocklight;
|
||||||
PyObject *red_color;
|
|
||||||
} RenderModeSpawn;
|
} RenderModeSpawn;
|
||||||
extern RenderModeInterface rendermode_spawn;
|
extern RenderModeInterface rendermode_spawn;
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
|
// var def
|
||||||
|
var map; // god of the overviewer... bow before the google api.
|
||||||
var markerCollection = {}; // holds groups of markers
|
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 map;
|
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 markersInit = false;
|
|
||||||
var regionsInit = false;
|
|
||||||
|
|
||||||
var prevInfoWindow = null;
|
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) {
|
function prepareSignMarker(marker, item) {
|
||||||
|
|
||||||
var c = "<div class=\"infoWindow\"><img src=\"signpost.png\" /><p>" + item.msg.replace(/\n/g,"<br/>") + "</p></div>";
|
var c = "<div class=\"infoWindow\"><img src=\"signpost.png\" /><p>" + item.msg.replace(/\n/g,"<br/>") + "</p></div>";
|
||||||
var infowindow = new google.maps.InfoWindow({content: c
|
var infowindow = new google.maps.InfoWindow({content: c
|
||||||
});
|
});
|
||||||
@@ -17,154 +19,289 @@ function prepareSignMarker(marker, item) {
|
|||||||
prevInfoWindow.close()
|
prevInfoWindow.close()
|
||||||
infowindow.open(map,marker);
|
infowindow.open(map,marker);
|
||||||
prevInfoWindow = infowindow
|
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
|
||||||
|
|
||||||
function drawMapControls() {
|
var controlText = document.createElement("DIV");
|
||||||
|
controlText.innerHTML = title;
|
||||||
// viewstate link
|
|
||||||
var viewStateDiv = document.createElement('DIV');
|
|
||||||
|
|
||||||
//<div id="link" style="border:1px solid black;background-color:white;color:black;position:absolute;top:5px;right:5px"></div>
|
|
||||||
|
|
||||||
viewStateDiv.id="link";
|
|
||||||
|
|
||||||
|
|
||||||
map.controls[google.maps.ControlPosition.BOTTOM_RIGHT].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;
|
|
||||||
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(compassDiv);
|
|
||||||
|
|
||||||
|
|
||||||
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");
|
var controlBorder = document.createElement("DIV");
|
||||||
controlBorder.id="top";
|
controlBorder.id="top";
|
||||||
signControl.appendChild(controlBorder);
|
control.appendChild(controlBorder);
|
||||||
|
|
||||||
var controlText = document.createElement("DIV");
|
|
||||||
|
|
||||||
controlBorder.appendChild(controlText);
|
controlBorder.appendChild(controlText);
|
||||||
|
|
||||||
controlText.innerHTML = "Signposts";
|
|
||||||
|
|
||||||
var dropdownDiv = document.createElement("DIV");
|
var dropdownDiv = document.createElement("DIV");
|
||||||
|
|
||||||
|
|
||||||
$(controlText).click(function() {
|
|
||||||
$(dropdownDiv).toggle();
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
dropdownDiv.id="dropDown";
|
dropdownDiv.id="dropDown";
|
||||||
signControl.appendChild(dropdownDiv);
|
control.appendChild(dropdownDiv);
|
||||||
dropdownDiv.innerHTML="";
|
dropdownDiv.innerHTML="";
|
||||||
|
|
||||||
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(signControl);
|
// 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 hasSignGroup = false;
|
var item = items[idx];
|
||||||
for (idx in signGroups) {
|
//console.log(item); // debug
|
||||||
var item = signGroups[idx];
|
|
||||||
//console.log(item);
|
|
||||||
label = item.label;
|
|
||||||
hasSignGroup = true;
|
|
||||||
var d = document.createElement("div");
|
var d = document.createElement("div");
|
||||||
var n = document.createElement("input");
|
var n = document.createElement("input");
|
||||||
n.type="checkbox";
|
n.type="checkbox";
|
||||||
|
|
||||||
$(n).data("label",label);
|
// give it a name
|
||||||
jQuery(n).click(function(e) {
|
$(n).data("label",item.label);
|
||||||
var t = $(e.target);
|
jQuery(n).click((function(local_idx, local_item) {
|
||||||
jQuery.each(markerCollection[t.data("label")], function(i,elem) {elem.setVisible(e.target.checked);});
|
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) {
|
if (item.checked) {
|
||||||
n.checked = true;
|
n.checked = true;
|
||||||
jQuery.each(markerCollection[label], function(i,elem) {elem.setVisible(n.checked);});
|
item.action(idx, item.label, item.checked);
|
||||||
}
|
}
|
||||||
dropdownDiv.appendChild(d);
|
dropdownDiv.appendChild(d);
|
||||||
d.appendChild(n)
|
d.appendChild(n)
|
||||||
var textNode = document.createElement("text");
|
var textNode = document.createElement("text");
|
||||||
textNode.innerHTML = label + "<br/>";
|
if(item.icon) {
|
||||||
|
textNode.innerHTML = "<img width='15' height='15' src='"+item.icon+"'>" + item.label + "<br/>";
|
||||||
|
} else {
|
||||||
|
textNode.innerHTML = item.label + "<br/>";
|
||||||
|
}
|
||||||
|
|
||||||
d.appendChild(textNode);
|
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() {
|
function initRegions() {
|
||||||
if (regionsInit) { return; }
|
if (regionsInit) { return; }
|
||||||
|
|
||||||
regionsInit = true;
|
regionsInit = true;
|
||||||
|
|
||||||
|
for (i in regionGroups) {
|
||||||
|
regionCollection[regionGroups[i].label] = [];
|
||||||
|
}
|
||||||
|
|
||||||
for (i in regionData) {
|
for (i in regionData) {
|
||||||
var region = regionData[i];
|
var region = regionData[i];
|
||||||
|
|
||||||
|
// pull all the points out of the regions file.
|
||||||
var converted = new google.maps.MVCArray();
|
var converted = new google.maps.MVCArray();
|
||||||
|
var infoPoint = "";
|
||||||
for (j in region.path) {
|
for (j in region.path) {
|
||||||
var point = region.path[j];
|
var point = region.path[j];
|
||||||
converted.push(fromWorldToLatLng(point.x, point.y, point.z));
|
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) {
|
if (region.closed) {
|
||||||
new google.maps.Polygon({clickable: false,
|
var shape = new google.maps.Polygon({
|
||||||
geodesic: false,
|
name: name,
|
||||||
map: map,
|
clickable: clickable,
|
||||||
strokeColor: region.color,
|
geodesic: false,
|
||||||
strokeOpacity: region.opacity,
|
map: null,
|
||||||
strokeWeight: 2,
|
strokeColor: region.color,
|
||||||
fillColor: region.color,
|
strokeOpacity: region.opacity,
|
||||||
fillOpacity: region.opacity * 0.25,
|
strokeWeight: 2,
|
||||||
zIndex: i,
|
fillColor: region.color,
|
||||||
paths: converted
|
fillOpacity: region.opacity * 0.25,
|
||||||
|
zIndex: i,
|
||||||
|
paths: converted
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
new google.maps.Polyline({clickable: false,
|
var shape = new google.maps.Polyline({
|
||||||
geodesic: false,
|
name: name,
|
||||||
map: map,
|
clickable: clickable,
|
||||||
strokeColor: region.color,
|
geodesic: false,
|
||||||
strokeOpacity: region.opacity,
|
map: null,
|
||||||
strokeWeight: 2,
|
strokeColor: region.color,
|
||||||
zIndex: i,
|
strokeOpacity: region.opacity,
|
||||||
path: converted
|
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 = "<b>Region: "+this.name+"</b><br />";
|
||||||
|
contentString += "Clicked Location: <br />" + e.latLng.lat() + "," + e.latLng.lng() + "<br />";
|
||||||
|
|
||||||
|
// 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() {
|
function initMarkers() {
|
||||||
if (markersInit) { return; }
|
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.
|
||||||
markersInit = true;
|
|
||||||
|
|
||||||
// first, give all collections an empty array to work with
|
// first, give all collections an empty array to work with
|
||||||
for (i in signGroups) {
|
for (i in signGroups) {
|
||||||
markerCollection[signGroups[i].label] = [];
|
markerCollection[signGroups[i].label] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (i in markerData) {
|
for (i in markerData) {
|
||||||
var item = markerData[i];
|
var item = markerData[i];
|
||||||
@@ -180,8 +317,7 @@ function initMarkers() {
|
|||||||
map: map,
|
map: map,
|
||||||
title: jQuery.trim(item.msg),
|
title: jQuery.trim(item.msg),
|
||||||
icon: iconURL
|
icon: iconURL
|
||||||
});
|
});
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,11 +344,11 @@ function initMarkers() {
|
|||||||
if (testfunc(item)) {
|
if (testfunc(item)) {
|
||||||
matched = true;
|
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);
|
//console.log(signGroup.icon); //debug
|
||||||
if (signGroup.icon) { iconURL = signGroup.icon;
|
if (signGroup.icon) { iconURL = signGroup.icon; }
|
||||||
}
|
|
||||||
|
|
||||||
var converted = fromWorldToLatLng(item.x, item.y, item.z);
|
var converted = fromWorldToLatLng(item.x, item.y, item.z);
|
||||||
var marker = new google.maps.Marker({position: converted,
|
var marker = new google.maps.Marker({position: converted,
|
||||||
@@ -220,19 +356,16 @@ function initMarkers() {
|
|||||||
title: jQuery.trim(item.msg),
|
title: jQuery.trim(item.msg),
|
||||||
icon: iconURL,
|
icon: iconURL,
|
||||||
visible: false
|
visible: false
|
||||||
});
|
});
|
||||||
|
|
||||||
markerCollection[label].push(marker);
|
markerCollection[label].push(marker);
|
||||||
|
|
||||||
if (item.type == 'sign') {
|
if (item.type == 'sign') {
|
||||||
prepareSignMarker(marker, item);
|
prepareSignMarker(marker, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!matched) {
|
if (!matched) {
|
||||||
// is this signpost doesn't match any of the groups in config.js, add it automatically to the "__others__" group
|
// 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';}
|
if (item.type == 'sign') { iconURL = 'signpost_icon.png';}
|
||||||
@@ -254,12 +387,13 @@ function initMarkers() {
|
|||||||
prepareSignMarker(marker, item);
|
prepareSignMarker(marker, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update the link in the viewstate.
|
||||||
function makeLink() {
|
function makeLink() {
|
||||||
var displayZoom = map.getZoom();
|
var displayZoom = map.getZoom();
|
||||||
if (displayZoom == config.maxZoom) {
|
if (displayZoom == config.maxZoom) {
|
||||||
@@ -277,6 +411,7 @@ function makeLink() {
|
|||||||
document.getElementById("link").innerHTML = a;
|
document.getElementById("link").innerHTML = a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// load the map up and add all the functions relevant stuff to the map.
|
||||||
function initialize() {
|
function initialize() {
|
||||||
|
|
||||||
var query = location.search.substring(1);
|
var query = location.search.substring(1);
|
||||||
@@ -365,7 +500,7 @@ function initialize() {
|
|||||||
for (idx in MCMapType) {
|
for (idx in MCMapType) {
|
||||||
map.mapTypes.set('mcmap' + MCMapType[idx].name, MCMapType[idx]);
|
map.mapTypes.set('mcmap' + MCMapType[idx].name, MCMapType[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We can now set the map to use the 'coordinate' map type
|
// We can now set the map to use the 'coordinate' map type
|
||||||
map.setMapTypeId(mapTypeIdDefault);
|
map.setMapTypeId(mapTypeIdDefault);
|
||||||
|
|
||||||
@@ -387,69 +522,69 @@ function initialize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// our custom projection maps Latitude to Y, and Longitude to X as normal,
|
// 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
|
// 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
|
// so it is easier to position markers, etc. based on their position
|
||||||
// (find their position in the lowest-zoom image, and divide by tileSize)
|
// (find their position in the lowest-zoom image, and divide by tileSize)
|
||||||
function MCMapProjection() {
|
function MCMapProjection() {
|
||||||
this.inverseTileSize = 1.0 / config.tileSize;
|
this.inverseTileSize = 1.0 / config.tileSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
MCMapProjection.prototype.fromLatLngToPoint = function(latLng) {
|
MCMapProjection.prototype.fromLatLngToPoint = function(latLng) {
|
||||||
var x = latLng.lng() * config.tileSize;
|
var x = latLng.lng() * config.tileSize;
|
||||||
var y = latLng.lat() * config.tileSize;
|
var y = latLng.lat() * config.tileSize;
|
||||||
return new google.maps.Point(x, y);
|
return new google.maps.Point(x, y);
|
||||||
};
|
};
|
||||||
|
|
||||||
MCMapProjection.prototype.fromPointToLatLng = function(point) {
|
MCMapProjection.prototype.fromPointToLatLng = function(point) {
|
||||||
var lng = point.x * this.inverseTileSize;
|
var lng = point.x * this.inverseTileSize;
|
||||||
var lat = point.y * this.inverseTileSize;
|
var lat = point.y * this.inverseTileSize;
|
||||||
return new google.maps.LatLng(lat, lng);
|
return new google.maps.LatLng(lat, lng);
|
||||||
};
|
};
|
||||||
|
|
||||||
// helper to get map LatLng from world coordinates
|
// helper to get map LatLng from world coordinates
|
||||||
// takes arguments in X, Y, Z order
|
// takes arguments in X, Y, Z order
|
||||||
// (arguments are *out of order*, because within the function we use
|
// (arguments are *out of order*, because within the function we use
|
||||||
// the axes like the rest of Minecraft Overviewer -- with the Z and Y
|
// the axes like the rest of Minecraft Overviewer -- with the Z and Y
|
||||||
// flipped from normal minecraft usage.)
|
// flipped from normal minecraft usage.)
|
||||||
function fromWorldToLatLng(x, z, y)
|
function fromWorldToLatLng(x, z, y)
|
||||||
{
|
{
|
||||||
// the width and height of all the highest-zoom tiles combined, inverted
|
// the width and height of all the highest-zoom tiles combined, inverted
|
||||||
var perPixel = 1.0 / (config.tileSize * Math.pow(2, config.maxZoom));
|
var perPixel = 1.0 / (config.tileSize * Math.pow(2, config.maxZoom));
|
||||||
|
|
||||||
// This information about where the center column is may change with a different
|
// This information about where the center column is may change with a different
|
||||||
// drawing implementation -- check it again after any drawing overhauls!
|
// 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)
|
// 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))
|
// 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))
|
// or equivalently, 0.5 - (1 / 2^(maxZoom + 1))
|
||||||
var lng = 0.5 - (1.0 / Math.pow(2, config.maxZoom + 1));
|
var lng = 0.5 - (1.0 / Math.pow(2, config.maxZoom + 1));
|
||||||
var lat = 0.5;
|
var lat = 0.5;
|
||||||
|
|
||||||
// the following metrics mimic those in ChunkRenderer.chunk_render in "chunk.py"
|
// the following metrics mimic those in ChunkRenderer.chunk_render in "chunk.py"
|
||||||
// or, equivalently, chunk_render in src/iterate.c
|
// or, equivalently, chunk_render in src/iterate.c
|
||||||
|
|
||||||
// each block on X axis adds 12px to x and subtracts 6px from y
|
// each block on X axis adds 12px to x and subtracts 6px from y
|
||||||
lng += 12 * x * perPixel;
|
lng += 12 * x * perPixel;
|
||||||
lat -= 6 * x * perPixel;
|
lat -= 6 * x * perPixel;
|
||||||
|
|
||||||
// each block on Y axis adds 12px to x and adds 6px to y
|
// each block on Y axis adds 12px to x and adds 6px to y
|
||||||
lng += 12 * y * perPixel;
|
lng += 12 * y * perPixel;
|
||||||
lat += 6 * y * perPixel;
|
lat += 6 * y * perPixel;
|
||||||
|
|
||||||
// each block down along Z adds 12px to y
|
// each block down along Z adds 12px to y
|
||||||
lat += 12 * (128 - z) * perPixel;
|
lat += 12 * (128 - z) * perPixel;
|
||||||
|
|
||||||
// add on 12 px to the X coordinate to center our point
|
// add on 12 px to the X coordinate to center our point
|
||||||
lng += 12 * perPixel;
|
lng += 12 * perPixel;
|
||||||
|
|
||||||
return new google.maps.LatLng(lat, lng);
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: X, Y and Z in this function are Minecraft world definitions
|
return new google.maps.LatLng(lat, lng);
|
||||||
// (that is, X is horizontal, Y is altitude and Z is vertical).
|
}
|
||||||
function fromLatLngToWorld(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
|
// Initialize world x/y/z object to be returned
|
||||||
var xyz = Array();
|
var xyz = Array();
|
||||||
xyz.x = 0;
|
xyz.x = 0;
|
||||||
@@ -477,67 +612,74 @@ function initialize() {
|
|||||||
// only latitude and longitude, so assume Y=64.
|
// only latitude and longitude, so assume Y=64.
|
||||||
xyz.x += 64 + 1;
|
xyz.x += 64 + 1;
|
||||||
xyz.z -= 64 + 2;
|
xyz.z -= 64 + 2;
|
||||||
|
|
||||||
return xyz;
|
return xyz;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTileUrlGenerator(path, path_base) {
|
function getTileUrlGenerator(path, path_base, path_ext) {
|
||||||
return function(tile, zoom) {
|
return function(tile, zoom) {
|
||||||
var url = path;
|
var url = path;
|
||||||
var url_base = ( path_base ? path_base : '' );
|
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)) {
|
if(tile.x < 0 || tile.x >= Math.pow(2, zoom) || tile.y < 0 || tile.y >= Math.pow(2, zoom)) {
|
||||||
url += '/blank';
|
url += '/blank';
|
||||||
} else if(zoom == 0) {
|
} else if(zoom == 0) {
|
||||||
url += '/base';
|
url += '/base';
|
||||||
} else {
|
} else {
|
||||||
for(var z = zoom - 1; z >= 0; --z) {
|
for(var z = zoom - 1; z >= 0; --z) {
|
||||||
var x = Math.floor(tile.x / Math.pow(2, z)) % 2;
|
var x = Math.floor(tile.x / Math.pow(2, z)) % 2;
|
||||||
var y = Math.floor(tile.y / Math.pow(2, z)) % 2;
|
var y = Math.floor(tile.y / Math.pow(2, z)) % 2;
|
||||||
url += '/' + (x + 2 * y);
|
url += '/' + (x + 2 * y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
url = url + '.' + path_ext;
|
||||||
url = url + '.' + config.fileExt;
|
if(config.cacheMinutes > 0) {
|
||||||
if(config.cacheMinutes > 0) {
|
var d = new Date();
|
||||||
var d = new Date();
|
url += '?c=' + Math.floor(d.getTime() / (1000 * 60 * config.cacheMinutes));
|
||||||
url += '?c=' + Math.floor(d.getTime() / (1000 * 60 * config.cacheMinutes));
|
}
|
||||||
}
|
return(url_base + url);
|
||||||
return(url_base + url);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var MCMapOptions = new Array;
|
var MCMapOptions = new Array;
|
||||||
var MCMapType = new Array;
|
var MCMapType = new Array;
|
||||||
var mapTypeIdDefault = null;
|
var mapTypeIdDefault = null;
|
||||||
var mapTypeIds = [];
|
var mapTypeIds = [];
|
||||||
|
var overlayMapTypes = [];
|
||||||
for (idx in mapTypeData) {
|
for (idx in mapTypeData) {
|
||||||
var view = mapTypeData[idx];
|
var view = mapTypeData[idx];
|
||||||
|
var imgformat = view.imgformat ? view.imgformat : 'png';
|
||||||
|
|
||||||
MCMapOptions[view.label] = {
|
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),
|
tileSize: new google.maps.Size(config.tileSize, config.tileSize),
|
||||||
maxZoom: config.maxZoom,
|
maxZoom: config.maxZoom,
|
||||||
minZoom: 0,
|
minZoom: 0,
|
||||||
isPng: !(config.fileExt.match(/^png$/i) == null)
|
isPng: !(imgformat.match(/^png$/i) == null)
|
||||||
};
|
};
|
||||||
|
|
||||||
MCMapType[view.label] = new google.maps.ImageMapType(MCMapOptions[view.label]);
|
MCMapType[view.label] = new google.maps.ImageMapType(MCMapOptions[view.label]);
|
||||||
MCMapType[view.label].name = view.label;
|
MCMapType[view.label].name = view.label;
|
||||||
MCMapType[view.label].alt = "Minecraft " + view.label + " Map";
|
MCMapType[view.label].alt = "Minecraft " + view.label + " Map";
|
||||||
MCMapType[view.label].projection = new MCMapProjection();
|
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() {
|
function CoordMapType() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function CoordMapType(tileSize) {
|
function CoordMapType(tileSize) {
|
||||||
this.tileSize = tileSize;
|
this.tileSize = tileSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) {
|
CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) {
|
||||||
var div = ownerDocument.createElement('DIV');
|
var div = ownerDocument.createElement('DIV');
|
||||||
div.innerHTML = "(" + coord.x + ", " + coord.y + ", " + zoom + ")";
|
div.innerHTML = "(" + coord.x + ", " + coord.y + ", " + zoom + ")";
|
||||||
div.innerHTML += "<br />";
|
div.innerHTML += "<br />";
|
||||||
@@ -549,4 +691,4 @@ for (idx in mapTypeData) {
|
|||||||
div.style.borderWidth = '1px';
|
div.style.borderWidth = '1px';
|
||||||
div.style.borderColor = '#AAAAAA';
|
div.style.borderColor = '#AAAAAA';
|
||||||
return div;
|
return div;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,13 +17,13 @@ body { height: 100%; margin: 0px; padding: 0px ; background-color: #000; }
|
|||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
#signControl {
|
#customControl {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
height: 15px;
|
height: 15px;
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
#signControl > div#top {
|
#customControl > div#top {
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border: 2px solid #000;
|
border: 2px solid #000;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -33,7 +33,14 @@ body { height: 100%; margin: 0px; padding: 0px ; background-color: #000; }
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
#signControl > div#dropDown {
|
#customControl > div#dropDown {
|
||||||
|
border: 1px solid #000;
|
||||||
|
font-size: 12px;
|
||||||
|
background-color: #fff;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#customControl > div#button {
|
||||||
border: 1px solid #000;
|
border: 1px solid #000;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
|
|||||||
Reference in New Issue
Block a user