0

broke out nether, heightfading, depth, and edgelines from base primitive

This commit is contained in:
Aaron Griffith
2012-01-08 00:03:31 -05:00
parent e3610f8ac5
commit a682b8a689
8 changed files with 317 additions and 146 deletions

View File

@@ -30,15 +30,30 @@ class RenderPrimitive(object):
self.option_values[key] = val self.option_values[key] = val
class Base(RenderPrimitive): 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" 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 # Render 3 blending masks for lighting
# first is top (+Z), second is left (-X), third is right (+Y) # first is top (+Z), second is left (-X), third is right (+Y)
def generate_facemasks(): def generate_facemasks():
@@ -70,8 +85,6 @@ 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))
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():

View File

@@ -26,49 +26,12 @@ typedef struct {
PyObject *grasscolor, *foliagecolor, *watercolor; PyObject *grasscolor, *foliagecolor, *watercolor;
/* biome-compatible grass/leaf textures */ /* biome-compatible grass/leaf textures */
PyObject *grass_texture; 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; } PrimitiveBase;
static int static int
base_start(void *data, RenderState *state, PyObject *support) { base_start(void *data, RenderState *state, PyObject *support) {
PrimitiveBase *self = (PrimitiveBase *)data; 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!) */ /* biome-compliant grass mask (includes sides!) */
self->grass_texture = PyObject_GetAttrString(state->textures, "biome_grass_texture"); 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->grasscolor);
Py_XDECREF(self->watercolor); Py_XDECREF(self->watercolor);
Py_XDECREF(self->grass_texture); Py_XDECREF(self->grass_texture);
Py_XDECREF(self->black_color);
Py_XDECREF(self->white_color);
} }
static int static int
@@ -146,30 +107,6 @@ static int
base_hidden(void *data, RenderState *state, int x, int y, int z) { base_hidden(void *data, RenderState *state, int x, int y, int z) {
PrimitiveBase *self = (PrimitiveBase *)data; 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; return 0;
} }
@@ -319,65 +256,6 @@ base_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObjec
if (facemask) if (facemask)
tint_with_mask(state->img, r, g, b, 255, facemask, state->imgx, state->imgy, 0, 0); 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 = { RenderPrimitiveInterface primitive_base = {

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#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,
};

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#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,
};

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#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,
};

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#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,
};

View File

@@ -20,12 +20,20 @@
#include <stdarg.h> #include <stdarg.h>
extern RenderPrimitiveInterface primitive_base; 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 /* list of all render primitives, ending in NULL
all of these will be available to the user, so DON'T include primitives all of these will be available to the user, so DON'T include primitives
that are only useful as a base for other primitives. */ that are only useful as a base for other primitives. */
static RenderPrimitiveInterface *render_primitives[] = { static RenderPrimitiveInterface *render_primitives[] = {
&primitive_base, &primitive_base,
&primitive_nether,
&primitive_height_fading,
&primitive_depth,
&primitive_edge_lines,
//&rendermode_lighting, //&rendermode_lighting,
//&rendermode_smooth_lighting, //&rendermode_smooth_lighting,
//&rendermode_cave, //&rendermode_cave,
@@ -59,25 +67,29 @@ RenderPrimitive *render_primitive_create(PyObject *prim, RenderState *state) {
Py_DECREF(pyname); Py_DECREF(pyname);
if (iface == NULL) if (iface == NULL)
return NULL; return (RenderPrimitive *)PyErr_Format(PyExc_RuntimeError, "invalid primitive name: %s", name);
ret = calloc(1, sizeof(RenderPrimitive)); ret = calloc(1, sizeof(RenderPrimitive));
if (ret == NULL) { if (ret == NULL) {
return (RenderPrimitive *)PyErr_Format(PyExc_RuntimeError, "Failed to alloc a render primitive"); return (RenderPrimitive *)PyErr_Format(PyExc_RuntimeError, "Failed to alloc a render primitive");
} }
ret->primitive = calloc(1, iface->data_size); if (iface->data_size > 0) {
if (ret->primitive == NULL) { ret->primitive = calloc(1, iface->data_size);
free(ret); if (ret->primitive == NULL) {
return (RenderPrimitive *)PyErr_Format(PyExc_RuntimeError, "Failed to alloc render primitive data"); free(ret);
return (RenderPrimitive *)PyErr_Format(PyExc_RuntimeError, "Failed to alloc render primitive data");
}
} }
ret->iface = iface; ret->iface = iface;
if (iface->start(ret->primitive, state, prim)) { if (iface->start) {
free(ret->primitive); if (iface->start(ret->primitive, state, prim)) {
free(ret); free(ret->primitive);
return NULL; free(ret);
return NULL;
}
} }
return ret; return ret;
@@ -120,8 +132,12 @@ void render_mode_destroy(RenderMode *self) {
/* we may be destroying a half-constructed mode, so we need this /* we may be destroying a half-constructed mode, so we need this
check */ check */
if (prim) { if (prim) {
prim->iface->finish(prim->primitive, self->state); if (prim->iface->finish) {
free(prim->primitive); prim->iface->finish(prim->primitive, self->state);
}
if (prim->primitive) {
free(prim->primitive);
}
free(prim); free(prim);
} }
} }
@@ -134,7 +150,10 @@ int render_mode_occluded(RenderMode *self, int x, int y, int z) {
int occluded = 0; int occluded = 0;
for (i = 0; i < self->num_primitives; i++) { for (i = 0; i < self->num_primitives; i++) {
RenderPrimitive *prim = self->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) if (occluded)
return occluded; return occluded;
} }
@@ -146,7 +165,10 @@ int render_mode_hidden(RenderMode *self, int x, int y, int z) {
int hidden = 0; int hidden = 0;
for (i = 0; i < self->num_primitives; i++) { for (i = 0; i < self->num_primitives; i++) {
RenderPrimitive *prim = self->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) if (hidden)
return hidden; return hidden;
} }
@@ -157,7 +179,9 @@ void render_mode_draw(RenderMode *self, PyObject *img, PyObject *mask, PyObject
unsigned int i; unsigned int i;
for (i = 0; i < self->num_primitives; i++) { for (i = 0; i < self->num_primitives; i++) {
RenderPrimitive *prim = self->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);
}
} }
} }

View File

@@ -151,7 +151,7 @@ except Exception:
# used to figure out what files to compile # used to figure out what files to compile
#render_modes = ['normal', 'lighting', 'smooth-lighting', 'cave'] #render_modes = ['normal', 'lighting', 'smooth-lighting', 'cave']
#render_modes += ['overlay', 'spawn', 'mineral'] #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 = ['main.c', 'composite.c', 'iterate.c', 'endian.c', 'rendermodes.c']
c_overviewer_files += map(lambda mode: 'primitives/%s.c' % (mode,), primitives) c_overviewer_files += map(lambda mode: 'primitives/%s.c' % (mode,), primitives)