Skip to content

Commit

Permalink
Merge remote-tracking branch 'enaut/structure_overlay'
Browse files Browse the repository at this point in the history
  • Loading branch information
agrif committed Feb 1, 2015
2 parents 9336ff7 + 086820a commit bad4261
Show file tree
Hide file tree
Showing 3 changed files with 281 additions and 0 deletions.
26 changes: 26 additions & 0 deletions docs/config.rst
Expand Up @@ -1127,6 +1127,32 @@ MineralOverlay

MineralOverlay(minerals=[(64,(255,255,0)), (13,(127,0,127))])

StructureOverlay
Color the map according to patterns of blocks. With this rail overlays
or overlays for other small structures can be realized. It can also be
a MineralOverlay with alpha support.

This Overlay colors according to a patterns that are specified as
multiple tuples of the form ``(relx, rely, relz, blockid)``. So
by specifying ``(0, -1, 0, 4)`` the block below the current one has to
be a cobblestone.

One color is then specified as
``((relblockid1, relblockid2, ...), (r, g, b, a))`` where the
``relblockid*`` are relative coordinates and the blockid as specified
above. The ``relblockid*`` must match all at the same time for the
color to apply.

Example::

MineralOverlay(minerals=[(((0, 0, 0, 66), (0, -1, 0, 4)), (255, 0, 0, 255)),
(((0, 0, 0, 27), (0, -1, 0, 4)), (0, 255, 0, 255))])

In this example all rails(66) on top of cobblestone are rendered in
pure red. And all powerrails(27) are rendered in green.

If ``minerals`` is not provided, a default rail coloring is used.

BiomeOverlay
Color the map according to the biome at that point. Either use on
top of other modes or on top of ClearBase to create a pure overlay.
Expand Down
13 changes: 13 additions & 0 deletions overviewer_core/rendermodes.py
Expand Up @@ -205,6 +205,19 @@ class SpawnOverlay(Overlay):
class SlimeOverlay(Overlay):
name = "overlay-slime"


class StructureOverlay(Overlay):
name = "overlay-structure"
options = {
'structures': ('a list of ((((relx, rely, relz), blockid), ...), (r, g, b, a)) tuples for coloring minerals',
[(((0, 0, 0, 66), (0, -1, 0, 4)), (255, 0, 0, 255)),
(((0, 0, 0, 27), (0, -1, 0, 4)), (0, 255, 0, 255)),
(((0, 0, 0, 28), (0, -1, 0, 4)), (255, 255, 0, 255)),
(((0, 0, 0, 157), (0, -1, 0, 4)), (255, 100, 0, 255)),
]),
}


class MineralOverlay(Overlay):
name = "overlay-mineral"
options = {
Expand Down
242 changes: 242 additions & 0 deletions overviewer_core/src/primitives/overlay-structure.c
@@ -0,0 +1,242 @@
/*
* 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 "overlay.h"

typedef enum { false, true } bool;

typedef struct {
/* inherits from overlay */
RenderPrimitiveOverlay parent;
void *structures;
int numcolors;
} RenderPrimitiveStructure;

struct Condition{
int relx, rely, relz;
unsigned char block;
};

struct Color {
int numconds;
struct Condition *conditions;
unsigned char r, g, b, a;
};

static void get_color(void *data,
RenderState *state,
unsigned char *r,
unsigned char *g,
unsigned char *b,
unsigned char *a) {
/**
* Calculate the color at the current position and store the values to r,g,b,a.
**/
RenderPrimitiveStructure *self = (RenderPrimitiveStructure *)data;
int x = state->x, z = state->z, y_max, y, col, cond;
struct Color *structures = (struct Color *)(self->structures);
struct Condition * c = NULL;
bool all = true;
y_max = state->y + 1;

/**
* Check for every color in every y level if all its Conditions are met.
* If all conditions are met for one y level set r,b,g,a accordingly.
**/
// iterate over all the colors
for ( col = 0; col < self->numcolors; col++) {
// iterate over all y levels
for (y = state->chunky * -16; y <= y_max; y++) {
// iterate over all the conditions
for (cond = 0; cond < structures[col].numconds; cond++) {
all = true;
c = (struct Condition *)&structures[col].conditions[cond];
// check if the condition does apply and break from the conditions loop if not.
if(!(c->block == get_data(state, BLOCKS, x+c->relx, y+c->rely, z+c->relz))) {
all = false;
break;
}
}
if (all){
// set the color
*r = structures[col].r;
*g = structures[col].g;
*b = structures[col].b;
*a = structures[col].a;
return;
}
}
}
return;
}

static int overlay_structure_start(void *data, RenderState *state, PyObject *support) {
/**
* Initializing the search for structures by parsing the arguments and storing them into
* appropriate structures. If no arguments are passed create and use default values.
**/
PyObject *opt;
RenderPrimitiveStructure* self;

/* first, chain up */
int ret = primitive_overlay.start(data, state, support);
if (ret != 0)
return ret;

/* now do custom initializations */
self = (RenderPrimitiveStructure *)data;

// opt is a borrowed reference. do not deref
// store the structures python object into opt.
if (!render_mode_parse_option(support, "structures", "O", &(opt)))
return 1;

/**
* Check if a sane option was passed.
**/
if (opt && opt != Py_None) {
struct Color *structures = NULL;
struct Condition *cond = NULL;
Py_ssize_t structures_size = 0, i, cond_size = 0, n = 0;
bool cont = true;

opt = PySequence_Fast(opt, "expected a sequence");
if (!opt) {
PyErr_SetString(PyExc_TypeError, "'structures' must be a a sequence");
return 1;
}

structures_size = PySequence_Fast_GET_SIZE(opt);
// Getting space on the heap and do not forget to set self->numcolors.
structures = self->structures = calloc(structures_size, sizeof(struct Color));
self->numcolors = structures_size;
if (structures == NULL) {
PyErr_SetString(PyExc_MemoryError, "failed to allocate memory");
return 1;
}

/**
* Try to parse the definitions of conditions and colors.
**/
if (cont) {
for (i = 0; i < structures_size; i++) {
PyObject *structure = PyList_GET_ITEM(opt, i);
// condspy holding the conditions tuple of variable length (python object)
PyObject *condspy;
// colorpy holding the 4 tuple with r g b a values of the color
PyObject *colorpy;

// getting the condspy and colorpy out of the structures.
if (!PyArg_ParseTuple(structure, "OO", &condspy, &colorpy)) {
// Exception set automatically
free(structures);
self->structures = NULL;
return 1;
}

// Parse colorpy into a c-struct.
if (!PyArg_ParseTuple( colorpy, "bbbb",
&structures[i].r,
&structures[i].g,
&structures[i].b,
&structures[i].a)) {
free(structures);
self->structures = NULL;
return 1;
}

// Convert condspy to a fast sequence
condspy = PySequence_Fast(condspy, "Failed to parse conditions");
if(condspy == NULL) {
free(structures);
self->structures = NULL;
return 1;
}

// get the number of conditions.
structures[i].numconds = PySequence_Fast_GET_SIZE(condspy);
// reserve enough memory for the conditions.
cond = calloc(structures[i].numconds, sizeof(struct Condition));
structures[i].conditions = cond;

if (structures[i].conditions == NULL) {
PyErr_SetString(PyExc_MemoryError, "failed to allocate memory");
free(structures);
self->structures = NULL;
return 1;
}

// iterate over all the conditions and read them.
for (n = 0; n < structures[i].numconds; n++) {
PyObject *ccond = PySequence_Fast_GET_ITEM(condspy, n);
if(!PyArg_ParseTuple( ccond, "iiib",
&cond[n].relx,
&cond[n].rely,
&cond[n].relz,
&cond[n].block)){
int x = 0;
for(x = 0; x < structures_size; x++){
free(structures[x].conditions);
}
free(structures);
self->structures = NULL;
return 1;
}
}
}
}
}

/* setup custom color */
self->parent.get_color = get_color;

return 0;
}

static void overlay_structure_finish(void *data, RenderState *state) {
/* first free all *our* stuff */
RenderPrimitiveStructure* self = (RenderPrimitiveStructure *)data;
int i = 0;

if(self->structures) {
// freeing the nested structure
struct Color * m = self->structures;
for(i = 0; i < self->numcolors; i++){
if(m[i].conditions)
free(m[i].conditions);
}
}

if (self->structures) {
free(self->structures);
self->structures = NULL;
}

/* now, chain up */
primitive_overlay.finish(data, state);
}

RenderPrimitiveInterface primitive_overlay_structure = {
"overlay-structure",
sizeof(RenderPrimitiveStructure),
overlay_structure_start,
overlay_structure_finish,
NULL,
NULL,
overlay_draw,
};

0 comments on commit bad4261

Please sign in to comment.