diff --git a/overviewer_core/rendermodes.py b/overviewer_core/rendermodes.py
index 0c988d2..2a58255 100644
--- a/overviewer_core/rendermodes.py
+++ b/overviewer_core/rendermodes.py
@@ -30,15 +30,30 @@ class RenderPrimitive(object):
self.option_values[key] = val
class Base(RenderPrimitive):
- options = {
- "edge_opacity": "darkness of the edge lines, from 0.0 to 1.0 (default: 0.15)",
- "min_depth": "lowest level of blocks to render (default: 0)",
- "max_depth": "highest level of blocks to render (default: 127)",
- "height_fading": "darken or lighten blocks based on height (default: False)",
- "nether": "if True, remove the roof of the map. Useful on nether maps. (defualt: False)",
- }
name = "base"
+class Nether(RenderPrimitive):
+ name = "nether"
+
+class HeightFading(RenderPrimitive):
+ name = "height-fading"
+
+ black_color = Image.new("RGB", (24,24), (0,0,0))
+ white_color = Image.new("RGB", (24,24), (255,255,255))
+
+class Depth(RenderPrimitive):
+ name = "depth"
+ options = {
+ "min": "lowest level of blocks to render (default: 0)",
+ "max": "highest level of blocks to render (default: 127)",
+ }
+
+class EdgeLines(RenderPrimitive):
+ name = "edge-lines"
+ options = {
+ "opacity": "darkness of the edge lines, from 0.0 to 1.0 (default: 0.15)",
+ }
+
# Render 3 blending masks for lighting
# first is top (+Z), second is left (-X), third is right (+Y)
def generate_facemasks():
@@ -70,8 +85,6 @@ def generate_facemasks():
return (top, left, right)
facemasks = generate_facemasks()
-black_color = Image.new("RGB", (24,24), (0,0,0))
-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/overviewer_core/src/primitives/base.c b/overviewer_core/src/primitives/base.c
index 2ed70fc..4f13c47 100644
--- a/overviewer_core/src/primitives/base.c
+++ b/overviewer_core/src/primitives/base.c
@@ -26,49 +26,12 @@ typedef struct {
PyObject *grasscolor, *foliagecolor, *watercolor;
/* biome-compatible grass/leaf textures */
PyObject *grass_texture;
-
- /* black and white colors for height fading */
- PyObject *black_color, *white_color;
-
- float edge_opacity;
- unsigned int min_depth;
- unsigned int max_depth;
- int height_fading;
- int nether;
} PrimitiveBase;
static int
base_start(void *data, RenderState *state, PyObject *support) {
PrimitiveBase *self = (PrimitiveBase *)data;
- /* load up the given options, first */
-
- self->edge_opacity = 0.15;
- if (!render_mode_parse_option(support, "edge_opacity", "f", &(self->edge_opacity)))
- return 1;
-
- self->min_depth = 0;
- if (!render_mode_parse_option(support, "min_depth", "I", &(self->min_depth)))
- return 1;
-
- self->max_depth = 127;
- if (!render_mode_parse_option(support, "max_depth", "I", &(self->max_depth)))
- return 1;
-
- self->height_fading = 0;
- /* XXX skip height fading */
- /*if (!render_mode_parse_option(support, "height_fading", "i", &(self->height_fading)))
- return 1;*/
-
- self->nether = 0;
- if (!render_mode_parse_option(support, "nether", "i", &(self->nether)))
- return 1;
-
- /*if (self->height_fading) {
- self->black_color = PyObject_GetAttrString(state->chunk, "black_color");
- self->white_color = PyObject_GetAttrString(state->chunk, "white_color");
- }*/
-
/* biome-compliant grass mask (includes sides!) */
self->grass_texture = PyObject_GetAttrString(state->textures, "biome_grass_texture");
@@ -123,8 +86,6 @@ base_finish(void *data, RenderState *state) {
Py_XDECREF(self->grasscolor);
Py_XDECREF(self->watercolor);
Py_XDECREF(self->grass_texture);
- Py_XDECREF(self->black_color);
- Py_XDECREF(self->white_color);
}
static int
@@ -146,30 +107,6 @@ static int
base_hidden(void *data, RenderState *state, int x, int y, int z) {
PrimitiveBase *self = (PrimitiveBase *)data;
- if (z > self->max_depth || z < self->min_depth) {
- return 1;
- }
-
- if (self->nether)
- {
-
- /* hide all blocks above all air blocks */
- int below_air = 0;
-
- while (z < 128)
- {
- if (getArrayByte3D(state->blocks, x, y, z) == 0)
- {
- below_air = 1;
- break;
- }
- z++;
- }
-
- if (!below_air)
- return 1;
- }
-
return 0;
}
@@ -319,65 +256,6 @@ base_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObjec
if (facemask)
tint_with_mask(state->img, r, g, b, 255, facemask, state->imgx, state->imgy, 0, 0);
}
-
- if (self->height_fading) {
- /* do some height fading */
- PyObject *height_color = self->white_color;
- /* negative alpha => darkness, positive => light */
- float alpha = (1.0 / (1 + expf((70 - state->z) / 11.0))) * 0.6 - 0.55;
-
- if (alpha < 0.0) {
- alpha *= -1;
- height_color = self->black_color;
- }
-
- alpha_over_full(state->img, height_color, mask_light, alpha, state->imgx, state->imgy, 0, 0);
- }
-
-
- /* Draw some edge lines! */
- // draw.line(((imgx+12,imgy+increment), (imgx+22,imgy+5+increment)), fill=(0,0,0), width=1)
- if (state->block == 44 || state->block == 78 || !is_transparent(state->block)) {
- Imaging img_i = imaging_python_to_c(state->img);
- unsigned char ink[] = {0, 0, 0, 255 * self->edge_opacity};
-
- int increment=0;
- if (state->block == 44) // half-step
- increment=6;
- 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)) {
- unsigned char side_block = getArrayByte3D(state->up_right_blocks, 0, state->y, state->z);
- if (side_block != state->block && is_transparent(side_block)) {
- ImagingDrawLine(img_i, state->imgx+12, state->imgy+1+increment, state->imgx+22+1, state->imgy+5+1+increment, &ink, 1);
- ImagingDrawLine(img_i, state->imgx+12, state->imgy+increment, state->imgx+22+1, state->imgy+5+increment, &ink, 1);
- }
- } else if (state->x != 15) {
- unsigned char side_block = getArrayByte3D(state->blocks, state->x+1, state->y, state->z);
- if (side_block != state->block && is_transparent(side_block)) {
- ImagingDrawLine(img_i, state->imgx+12, state->imgy+1+increment, state->imgx+22+1, state->imgy+5+1+increment, &ink, 1);
- ImagingDrawLine(img_i, state->imgx+12, state->imgy+increment, state->imgx+22+1, state->imgy+5+increment, &ink, 1);
- }
- }
- // if y != 0 and blocks[x,y-1,z] == 0
-
- // chunk boundries are annoying
- if ((state->y == 0) && (state->up_left_blocks != Py_None)) {
- unsigned char side_block = getArrayByte3D(state->up_left_blocks, state->x, 15, state->z);
- if (side_block != state->block && is_transparent(side_block)) {
- ImagingDrawLine(img_i, state->imgx, state->imgy+6+1+increment, state->imgx+12+1, state->imgy+1+increment, &ink, 1);
- ImagingDrawLine(img_i, state->imgx, state->imgy+6+increment, state->imgx+12+1, state->imgy+increment, &ink, 1);
- }
- } else if (state->y != 0) {
- unsigned char side_block = getArrayByte3D(state->blocks, state->x, state->y-1, state->z);
- if (side_block != state->block && is_transparent(side_block)) {
- // draw.line(((imgx,imgy+6+increment), (imgx+12,imgy+increment)), fill=(0,0,0), width=1)
- ImagingDrawLine(img_i, state->imgx, state->imgy+6+1+increment, state->imgx+12+1, state->imgy+1+increment, &ink, 1);
- ImagingDrawLine(img_i, state->imgx, state->imgy+6+increment, state->imgx+12+1, state->imgy+increment, &ink, 1);
- }
- }
- }
}
RenderPrimitiveInterface primitive_base = {
diff --git a/overviewer_core/src/primitives/depth.c b/overviewer_core/src/primitives/depth.c
new file mode 100644
index 0000000..4a2899c
--- /dev/null
+++ b/overviewer_core/src/primitives/depth.c
@@ -0,0 +1,56 @@
+/*
+ * 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"
+
+typedef struct {
+ unsigned int min;
+ unsigned int max;
+} PrimitiveDepth;
+
+static int
+depth_start(void *data, RenderState *state, PyObject *support) {
+ PrimitiveDepth *self = (PrimitiveDepth *)data;
+
+ self->min = 0;
+ if (!render_mode_parse_option(support, "min", "I", &(self->min)))
+ return 1;
+
+ self->max = 127;
+ if (!render_mode_parse_option(support, "max", "I", &(self->max)))
+ return 1;
+
+ return 0;
+}
+
+static int
+depth_hidden(void *data, RenderState *state, int x, int y, int z) {
+ PrimitiveDepth *self = (PrimitiveDepth *)data;
+ if (z > self->max || z < self->min) {
+ return 1;
+ }
+ return 0;
+}
+
+RenderPrimitiveInterface primitive_depth = {
+ "depth", sizeof(PrimitiveDepth),
+ depth_start,
+ NULL,
+ NULL,
+ depth_hidden,
+ NULL,
+};
diff --git a/overviewer_core/src/primitives/edge-lines.c b/overviewer_core/src/primitives/edge-lines.c
new file mode 100644
index 0000000..54b7407
--- /dev/null
+++ b/overviewer_core/src/primitives/edge-lines.c
@@ -0,0 +1,90 @@
+/*
+ * 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"
+
+typedef struct {
+ float opacity;
+} PrimitiveEdgeLines;
+
+static int
+edge_lines_start(void *data, RenderState *state, PyObject *support) {
+ PrimitiveEdgeLines *self = (PrimitiveEdgeLines *)data;
+
+ self->opacity = 0.15;
+ if (!render_mode_parse_option(support, "opacity", "f", &(self->opacity)))
+ return 1;
+ return 0;
+}
+
+static void
+edge_lines_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
+ PrimitiveEdgeLines *self = (PrimitiveEdgeLines *)data;
+
+ /* Draw some edge lines! */
+ // draw.line(((imgx+12,imgy+increment), (imgx+22,imgy+5+increment)), fill=(0,0,0), width=1)
+ if (state->block == 44 || state->block == 78 || !is_transparent(state->block)) {
+ Imaging img_i = imaging_python_to_c(state->img);
+ unsigned char ink[] = {0, 0, 0, 255 * self->opacity};
+
+ int increment=0;
+ if (state->block == 44) // half-step
+ increment=6;
+ 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)) {
+ unsigned char side_block = getArrayByte3D(state->up_right_blocks, 0, state->y, state->z);
+ if (side_block != state->block && is_transparent(side_block)) {
+ ImagingDrawLine(img_i, state->imgx+12, state->imgy+1+increment, state->imgx+22+1, state->imgy+5+1+increment, &ink, 1);
+ ImagingDrawLine(img_i, state->imgx+12, state->imgy+increment, state->imgx+22+1, state->imgy+5+increment, &ink, 1);
+ }
+ } else if (state->x != 15) {
+ unsigned char side_block = getArrayByte3D(state->blocks, state->x+1, state->y, state->z);
+ if (side_block != state->block && is_transparent(side_block)) {
+ ImagingDrawLine(img_i, state->imgx+12, state->imgy+1+increment, state->imgx+22+1, state->imgy+5+1+increment, &ink, 1);
+ ImagingDrawLine(img_i, state->imgx+12, state->imgy+increment, state->imgx+22+1, state->imgy+5+increment, &ink, 1);
+ }
+ }
+ // if y != 0 and blocks[x,y-1,z] == 0
+
+ // chunk boundries are annoying
+ if ((state->y == 0) && (state->up_left_blocks != Py_None)) {
+ unsigned char side_block = getArrayByte3D(state->up_left_blocks, state->x, 15, state->z);
+ if (side_block != state->block && is_transparent(side_block)) {
+ ImagingDrawLine(img_i, state->imgx, state->imgy+6+1+increment, state->imgx+12+1, state->imgy+1+increment, &ink, 1);
+ ImagingDrawLine(img_i, state->imgx, state->imgy+6+increment, state->imgx+12+1, state->imgy+increment, &ink, 1);
+ }
+ } else if (state->y != 0) {
+ unsigned char side_block = getArrayByte3D(state->blocks, state->x, state->y-1, state->z);
+ if (side_block != state->block && is_transparent(side_block)) {
+ // draw.line(((imgx,imgy+6+increment), (imgx+12,imgy+increment)), fill=(0,0,0), width=1)
+ ImagingDrawLine(img_i, state->imgx, state->imgy+6+1+increment, state->imgx+12+1, state->imgy+1+increment, &ink, 1);
+ ImagingDrawLine(img_i, state->imgx, state->imgy+6+increment, state->imgx+12+1, state->imgy+increment, &ink, 1);
+ }
+ }
+ }
+}
+
+RenderPrimitiveInterface primitive_edge_lines = {
+ "edge-lines", sizeof(PrimitiveEdgeLines),
+ edge_lines_start,
+ NULL,
+ NULL,
+ NULL,
+ edge_lines_draw,
+};
diff --git a/overviewer_core/src/primitives/height-fading.c b/overviewer_core/src/primitives/height-fading.c
new file mode 100644
index 0000000..589111e
--- /dev/null
+++ b/overviewer_core/src/primitives/height-fading.c
@@ -0,0 +1,68 @@
+/*
+ * 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"
+
+typedef struct {
+ PyObject *black_color;
+ PyObject *white_color;
+} PrimitiveHeightFading;
+
+static int
+height_fading_start(void *data, RenderState *state, PyObject *support) {
+ PrimitiveHeightFading *self = (PrimitiveHeightFading *)data;
+
+ self->black_color = PyObject_GetAttrString(support, "black_color");
+ self->white_color = PyObject_GetAttrString(support, "white_color");
+
+ return 0;
+}
+
+static void
+height_fading_finish(void *data, RenderState *state) {
+ PrimitiveHeightFading *self = (PrimitiveHeightFading *)data;
+
+ Py_DECREF(self->black_color);
+ Py_DECREF(self->white_color);
+}
+
+static void
+height_fading_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
+ PrimitiveHeightFading *self = (PrimitiveHeightFading *)data;
+
+ /* do some height fading */
+ PyObject *height_color = self->white_color;
+
+ /* negative alpha => darkness, positive => light */
+ float alpha = (1.0 / (1 + expf((70 - state->z) / 11.0))) * 0.6 - 0.55;
+
+ if (alpha < 0.0) {
+ alpha *= -1;
+ height_color = self->black_color;
+ }
+
+ alpha_over_full(state->img, height_color, mask_light, alpha, state->imgx, state->imgy, 0, 0);
+}
+
+RenderPrimitiveInterface primitive_height_fading = {
+ "height-fading", sizeof(PrimitiveHeightFading),
+ height_fading_start,
+ height_fading_finish,
+ NULL,
+ NULL,
+ height_fading_draw,
+};
diff --git a/overviewer_core/src/primitives/nether.c b/overviewer_core/src/primitives/nether.c
new file mode 100644
index 0000000..3844d1c
--- /dev/null
+++ b/overviewer_core/src/primitives/nether.c
@@ -0,0 +1,42 @@
+/*
+ * 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
+nether_hidden(void *data, RenderState *state, int x, int y, int z) {
+ /* hide all blocks above all air blocks */
+ while (z < 128)
+ {
+ if (getArrayByte3D(state->blocks, x, y, z) == 0)
+ {
+ return 0;
+ break;
+ }
+ z++;
+ }
+ return 1;
+}
+
+RenderPrimitiveInterface primitive_nether = {
+ "nether", 0,
+ NULL,
+ NULL,
+ NULL,
+ nether_hidden,
+ NULL,
+};
diff --git a/overviewer_core/src/rendermodes.c b/overviewer_core/src/rendermodes.c
index fe69983..3e75073 100644
--- a/overviewer_core/src/rendermodes.c
+++ b/overviewer_core/src/rendermodes.c
@@ -20,12 +20,20 @@
#include
extern RenderPrimitiveInterface primitive_base;
+extern RenderPrimitiveInterface primitive_nether;
+extern RenderPrimitiveInterface primitive_height_fading;
+extern RenderPrimitiveInterface primitive_depth;
+extern RenderPrimitiveInterface primitive_edge_lines;
/* list of all render primitives, ending in NULL
all of these will be available to the user, so DON'T include primitives
that are only useful as a base for other primitives. */
static RenderPrimitiveInterface *render_primitives[] = {
&primitive_base,
+ &primitive_nether,
+ &primitive_height_fading,
+ &primitive_depth,
+ &primitive_edge_lines,
//&rendermode_lighting,
//&rendermode_smooth_lighting,
//&rendermode_cave,
@@ -59,25 +67,29 @@ RenderPrimitive *render_primitive_create(PyObject *prim, RenderState *state) {
Py_DECREF(pyname);
if (iface == NULL)
- return NULL;
+ return (RenderPrimitive *)PyErr_Format(PyExc_RuntimeError, "invalid primitive name: %s", name);
ret = calloc(1, sizeof(RenderPrimitive));
if (ret == NULL) {
return (RenderPrimitive *)PyErr_Format(PyExc_RuntimeError, "Failed to alloc a render primitive");
}
- ret->primitive = calloc(1, iface->data_size);
- if (ret->primitive == NULL) {
- free(ret);
- return (RenderPrimitive *)PyErr_Format(PyExc_RuntimeError, "Failed to alloc render primitive data");
+ if (iface->data_size > 0) {
+ ret->primitive = calloc(1, iface->data_size);
+ if (ret->primitive == NULL) {
+ free(ret);
+ return (RenderPrimitive *)PyErr_Format(PyExc_RuntimeError, "Failed to alloc render primitive data");
+ }
}
ret->iface = iface;
- if (iface->start(ret->primitive, state, prim)) {
- free(ret->primitive);
- free(ret);
- return NULL;
+ if (iface->start) {
+ if (iface->start(ret->primitive, state, prim)) {
+ free(ret->primitive);
+ free(ret);
+ return NULL;
+ }
}
return ret;
@@ -120,8 +132,12 @@ void render_mode_destroy(RenderMode *self) {
/* we may be destroying a half-constructed mode, so we need this
check */
if (prim) {
- prim->iface->finish(prim->primitive, self->state);
- free(prim->primitive);
+ if (prim->iface->finish) {
+ prim->iface->finish(prim->primitive, self->state);
+ }
+ if (prim->primitive) {
+ free(prim->primitive);
+ }
free(prim);
}
}
@@ -134,7 +150,10 @@ int render_mode_occluded(RenderMode *self, int x, int y, int z) {
int occluded = 0;
for (i = 0; i < self->num_primitives; i++) {
RenderPrimitive *prim = self->primitives[i];
- occluded |= prim->iface->occluded(prim->primitive, self->state, x, y, z);
+ if (prim->iface->occluded) {
+ occluded |= prim->iface->occluded(prim->primitive, self->state, x, y, z);
+ }
+
if (occluded)
return occluded;
}
@@ -146,7 +165,10 @@ int render_mode_hidden(RenderMode *self, int x, int y, int z) {
int hidden = 0;
for (i = 0; i < self->num_primitives; i++) {
RenderPrimitive *prim = self->primitives[i];
- hidden |= prim->iface->hidden(prim->primitive, self->state, x, y, z);
+ if (prim->iface->hidden) {
+ hidden |= prim->iface->hidden(prim->primitive, self->state, x, y, z);
+ }
+
if (hidden)
return hidden;
}
@@ -157,7 +179,9 @@ void render_mode_draw(RenderMode *self, PyObject *img, PyObject *mask, PyObject
unsigned int i;
for (i = 0; i < self->num_primitives; i++) {
RenderPrimitive *prim = self->primitives[i];
- prim->iface->draw(prim->primitive, self->state, img, mask, mask_light);
+ if (prim->iface->draw) {
+ prim->iface->draw(prim->primitive, self->state, img, mask, mask_light);
+ }
}
}
diff --git a/setup.py b/setup.py
index ef01ea4..3c82fc2 100755
--- a/setup.py
+++ b/setup.py
@@ -151,7 +151,7 @@ except Exception:
# used to figure out what files to compile
#render_modes = ['normal', 'lighting', 'smooth-lighting', 'cave']
#render_modes += ['overlay', 'spawn', 'mineral']
-primitives = ['base',]
+primitives = ['base', 'nether', 'height-fading', 'depth', 'edge-lines']
c_overviewer_files = ['main.c', 'composite.c', 'iterate.c', 'endian.c', 'rendermodes.c']
c_overviewer_files += map(lambda mode: 'primitives/%s.c' % (mode,), primitives)