diff --git a/chunk.py b/chunk.py index ab5d41f..2086485 100644 --- a/chunk.py +++ b/chunk.py @@ -545,7 +545,10 @@ class ChunkRenderer(object): if not img: img = Image.new("RGBA", (384, 1728), (38,92,255,0)) - c_overviewer.render_loop(self, img, xoff, yoff, blockData_expanded) + if self.world.lighting: + c_overviewer.render_loop_lighting(self, img, xoff, yoff, blockData_expanded) + else: + c_overviewer.render_loop(self, img, xoff, yoff, blockData_expanded) for entity in tileEntities: if entity['id'] == 'Sign': diff --git a/gmap.py b/gmap.py index 57edb0c..92bff15 100755 --- a/gmap.py +++ b/gmap.py @@ -140,7 +140,7 @@ def main(): logging.info("Notice: Not using biome data for tinting") # First do world-level preprocessing - w = world.World(worlddir, useBiomeData=useBiomeData) + w = world.World(worlddir, useBiomeData=useBiomeData, lighting=options.lighting) w.go(options.procs) # Now generate the tiles diff --git a/src/.composite.c.swp b/src/.composite.c.swp new file mode 100644 index 0000000..a7256a6 Binary files /dev/null and b/src/.composite.c.swp differ diff --git a/src/.iterate.c.swp b/src/.iterate.c.swp new file mode 100644 index 0000000..1c5c2d3 Binary files /dev/null and b/src/.iterate.c.swp differ diff --git a/src/composite.c b/src/composite.c index 4b58403..7946faf 100644 --- a/src/composite.c +++ b/src/composite.c @@ -58,6 +58,36 @@ imaging_python_to_c(PyObject *obj) return image; } +/** + * img should be an Image object, type 'L' + * factor should be between 0 and 1, inclusive + */ +PyObject *brightness(PyObject *img, double factor) { + Imaging imDest; + + imDest = imaging_python_to_c(img); + assert(imDest); + + int x, y; + + int xsize = imDest->xsize; + int ysize = imDest->ysize; + + for (y = 0; y < ysize; y++) { + UINT8 *out = (UINT8 *)imDest->image[y]; + //UINT8 *outmask = (UINT8 *)imDest->image[y] + 3; + + for (x = 0; x < xsize; x++) { + //printf("old out: %d\n", *out); + *out *= factor; + //printf("new out: %d\n", *out); + out++; + } + } + return NULL; + +} + /* the alpha_over function, in a form that can be called from C */ /* if xsize, ysize are negative, they are instead set to the size of the image in src */ /* returns NULL on error, dest on success. You do NOT need to decref the return! */ diff --git a/src/iterate.c b/src/iterate.c index 031864c..61e2ff1 100644 --- a/src/iterate.c +++ b/src/iterate.c @@ -45,6 +45,249 @@ texture_alpha_over(PyObject *dest, PyObject *t, int imgx, int imgy) return alpha_over(dest, src, mask, imgx, imgy, 0, 0); } +PyObject* +chunk_render_lighting(PyObject *self, PyObject *args) { + + PyObject *chunk; + PyObject *blockdata_expanded; + int xoff, yoff; + PyObject *img; + + PyObject *imgsize, *imgsize0_py, *imgsize1_py; + int imgsize0, imgsize1; + + PyObject *blocks_py; + + PyObject *textures, *blockmap, *special_blocks, *specialblockmap, *chunk_mod, *transparent_blocks; + + int imgx, imgy; + int x, y, z; + + if (!PyArg_ParseTuple(args, "OOiiO", &chunk, &img, &xoff, &yoff, &blockdata_expanded)) + return Py_BuildValue("i", "-1"); + + /* tuple */ + imgsize = PyObject_GetAttrString(img, "size"); + + imgsize0_py = PySequence_GetItem(imgsize, 0); + imgsize1_py = PySequence_GetItem(imgsize, 1); + Py_DECREF(imgsize); + + imgsize0 = PyInt_AsLong(imgsize0_py); + imgsize1 = PyInt_AsLong(imgsize1_py); + Py_DECREF(imgsize0_py); + Py_DECREF(imgsize1_py); + + + /* get the block data directly from numpy: */ + blocks_py = PyObject_GetAttrString(chunk, "blocks"); + + /* + PyObject *left_blocks = PyObject_GetAttrString(chunk, "left_blocks"); + PyObject *right_blocks = PyObject_GetAttrString(chunk, "right_blocks"); + */ + + textures = PyImport_ImportModule("textures"); + chunk_mod = PyImport_ImportModule("chunk"); + + /* TODO can these be global static? these don't change during program execution */ + blockmap = PyObject_GetAttrString(textures, "blockmap"); + special_blocks = PyObject_GetAttrString(textures, "special_blocks"); + specialblockmap = PyObject_GetAttrString(textures, "specialblockmap"); + transparent_blocks = PyObject_GetAttrString(chunk_mod, "transparent_blocks"); + if (transparent_blocks == NULL) { + PyErr_SetString(PyExc_ValueError, + "transparent_blocks is NULL"); + return NULL; + } + PyObject *black_color = PyObject_GetAttrString(chunk_mod, "black_color"); + PyObject *facemasks_py = PyObject_GetAttrString(chunk_mod, "facemasks"); + PyObject *facemasks[3]; + //assert(PyTuple_Check(facemasks_py)); + facemasks[0] = PyTuple_GetItem(facemasks_py, 0); + facemasks[1] = PyTuple_GetItem(facemasks_py, 1); + facemasks[2] = PyTuple_GetItem(facemasks_py, 2); + + + Py_DECREF(textures); + Py_DECREF(chunk_mod); + + + + for (x = 15; x > -1; x--) { + for (y = 0; y < 16; y++) { + imgx = xoff + x*12 + y*12; + /* 128*12 -- offset for z direction, 15*6 -- offset for x */ + imgy = yoff - x*6 + y*6 + 128*12 + 15*6; + for (z = 0; z < 128; z++) { + unsigned char block; + PyObject *blockid; + + imgy -= 12; + + if ((imgx >= imgsize0 + 24) || (imgx <= -24)) { + continue; + } + if ((imgy >= imgsize1 + 24) || (imgy <= -24)) { + continue; + } + + /* get blockid + note the order: x, z, y */ + block = getBlock(blocks_py, x, y, z); + if (block == 0) { + continue; + } + + /* TODO figure out how to DECREF this easily, instead of at + every continue */ + blockid = PyInt_FromLong(block); + + + if ( (x != 0) && (y != 15) && (z != 127) && + !isTransparent(transparent_blocks, getBlock(blocks_py, x-1, y, z)) && + !isTransparent(transparent_blocks, getBlock(blocks_py, x, y, z+1)) && + !isTransparent(transparent_blocks, getBlock(blocks_py, x, y+1, z))) { + continue; + } + + //# top face + //black_coeff, face_occlude = self.get_lighting_coefficient(x, y, z + 1) + + + PyObject *t = NULL; + if (!PySequence_Contains(special_blocks, blockid)) { + /* t = textures.blockmap[blockid] */ + PyObject *t = PyList_GetItem(blockmap, block); + /* PyList_GetItem returns borrowed ref */ + + /* note that this version of alpha_over has a different signature than the + version in _composite.c */ + texture_alpha_over(img, t, imgx, imgy ); + } else { + PyObject *tmp; + + /* this should be a pointer to a unsigned char */ + void* ancilData_p = PyArray_GETPTR3(blockdata_expanded, x, y, z); + unsigned char ancilData = *((unsigned char*)ancilData_p); + if (block == 85) { + /* fence. skip the generate_pseudo_ancildata for now */ + continue; + } + + tmp = PyTuple_New(2); + + Py_INCREF(blockid); /* because SetItem steals */ + PyTuple_SetItem(tmp, 0, blockid); + PyTuple_SetItem(tmp, 1, PyInt_FromLong(ancilData)); + + /* this is a borrowed reference. no need to decref */ + t = PyDict_GetItem(specialblockmap, tmp); + Py_DECREF(tmp); + + } + if ((t != NULL) && (t != Py_None)) + texture_alpha_over(img, t, imgx, imgy ); + + { + // returns new references + PyObject* light_tup = PyObject_CallMethod(chunk, "get_lighting_coefficient", "iii", x, y, z+1); + PyObject *black_coeff_py = PySequence_GetItem(light_tup, 0); + double black_coeff = PyFloat_AsDouble(black_coeff_py); + Py_DECREF(black_coeff_py); + + PyObject *face_occlude_py = PySequence_GetItem(light_tup, 1); + int face_occlude = PyInt_AsLong(face_occlude_py); + Py_DECREF(face_occlude_py); + + + if (!face_occlude) { + //#composite.alpha_over(img, over_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[0]).enhance(black_coeff)) + + PyObject *mask = PyObject_CallMethod(facemasks[0], "copy", NULL); // new ref + //printf("black_coeff: %f\n", black_coeff); + brightness(mask, black_coeff); + //printf("done with brightness\n"); + alpha_over(img, black_color, mask, imgx, imgy, 0, 0); + //printf("done with alpha_over\n"); + Py_DECREF(mask); + + } + } + + + { + // returns new references + PyObject* light_tup = PyObject_CallMethod(chunk, "get_lighting_coefficient", "iii", x-1, y, z); + PyObject *black_coeff_py = PySequence_GetItem(light_tup, 0); + double black_coeff = PyFloat_AsDouble(black_coeff_py); + Py_DECREF(black_coeff_py); + + PyObject *face_occlude_py = PySequence_GetItem(light_tup, 1); + int face_occlude = PyInt_AsLong(face_occlude_py); + Py_DECREF(face_occlude_py); + + + if (!face_occlude) { + //#composite.alpha_over(img, over_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[0]).enhance(black_coeff)) + /* for now, we are lazy and call Image.blend to change the brightness of facemask + * TODO find some faster way? + */ + + PyObject *mask = PyObject_CallMethod(facemasks[1], "copy", NULL); // new ref + //printf("black_coeff: %f\n", black_coeff); + brightness(mask, black_coeff); + //printf("done with brightness\n"); + alpha_over(img, black_color, mask, imgx, imgy, 0, 0); + //printf("done with alpha_over\n"); + Py_DECREF(mask); + + } + } + + + { + // returns new references + PyObject* light_tup = PyObject_CallMethod(chunk, "get_lighting_coefficient", "iii", x, y+1, z); + PyObject *black_coeff_py = PySequence_GetItem(light_tup, 0); + double black_coeff = PyFloat_AsDouble(black_coeff_py); + Py_DECREF(black_coeff_py); + + PyObject *face_occlude_py = PySequence_GetItem(light_tup, 1); + int face_occlude = PyInt_AsLong(face_occlude_py); + Py_DECREF(face_occlude_py); + + + if (!face_occlude) { + //#composite.alpha_over(img, over_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[0]).enhance(black_coeff)) + + PyObject *mask = PyObject_CallMethod(facemasks[2], "copy", NULL); // new ref + //printf("black_coeff: %f\n", black_coeff); + brightness(mask, black_coeff); + //printf("done with brightness\n"); + alpha_over(img, black_color, mask, imgx, imgy, 0, 0); + //printf("done with alpha_over\n"); + Py_DECREF(mask); + + } + } + + + + } + } + } + + Py_DECREF(facemasks_py); + Py_DECREF(blocks_py); + Py_DECREF(blockmap); + Py_DECREF(special_blocks); + Py_DECREF(specialblockmap); + + return Py_BuildValue("i",2); + +} + /* TODO triple check this to make sure reference counting is correct */ PyObject* chunk_render(PyObject *self, PyObject *args) { diff --git a/src/main.c b/src/main.c index f56fb41..48968dd 100644 --- a/src/main.c +++ b/src/main.c @@ -24,6 +24,8 @@ static PyMethodDef COverviewerMethods[] = { "alpha over composite function"}, {"render_loop", chunk_render, METH_VARARGS, "Renders stuffs"}, + {"render_loop_lighting", chunk_render_lighting, METH_VARARGS, + "Renders stuffs, lighting"}, {NULL, NULL, 0, NULL} /* Sentinel */ }; diff --git a/src/overviewer.h b/src/overviewer.h index 5746b53..bfd9bb9 100644 --- a/src/overviewer.h +++ b/src/overviewer.h @@ -33,8 +33,10 @@ Imaging imaging_python_to_c(PyObject *obj); PyObject *alpha_over(PyObject *dest, PyObject *src, PyObject *mask, int dx, int dy, int xsize, int ysize); PyObject *alpha_over_wrap(PyObject *self, PyObject *args); +PyObject *brightness(PyObject *img, double factor); /* in iterate.c */ PyObject *chunk_render(PyObject *self, PyObject *args); +PyObject *chunk_render_lighting(PyObject *self, PyObject *args); #endif /* __OVERVIEWER_H_INCLUDED__ */ diff --git a/world.py b/world.py index 7ed790c..8099e94 100644 --- a/world.py +++ b/world.py @@ -67,9 +67,10 @@ class World(object): mincol = maxcol = minrow = maxrow = 0 - def __init__(self, worlddir, useBiomeData=False,regionlist=None): + def __init__(self, worlddir, useBiomeData=False,regionlist=None, lighting=False): self.worlddir = worlddir self.useBiomeData = useBiomeData + self.lighting = lighting #find region files, or load the region list #this also caches all the region file header info