/* TODO triple check this to make sure reference counting is correct */ PyObject* chunk_render(PyObject *self, PyObject *args) { RenderState state; PyObject *modeobj; PyObject *blockmap; int xoff, yoff; PyObject *imgsize, *imgsize0_py, *imgsize1_py; int imgsize0, imgsize1; PyObject *blocks_py; PyObject *left_blocks_py; PyObject *right_blocks_py; PyObject *up_left_blocks_py; PyObject *up_right_blocks_py; RenderMode *rendermode; int i, j; PyObject *t = NULL; if (!PyArg_ParseTuple(args, "OOiiiOiiOO", &state.world, &state.regionset, &state.chunkx, &state.chunky, &state.chunkz, &state.img, &xoff, &yoff, &modeobj, &state.textures)) return NULL; /* set up the render mode */ state.rendermode = rendermode = render_mode_create(modeobj, &state); if (rendermode == NULL) { return NULL; // note that render_mode_create will // set PyErr. No need to set it here } /* get the blockmap from the textures object */ blockmap = PyObject_GetAttrString(state.textures, "blockmap"); if (blockmap == NULL) { render_mode_destroy(rendermode); return NULL; } if (blockmap == Py_None) { render_mode_destroy(rendermode); PyErr_SetString(PyExc_RuntimeError, "you must call Textures.generate()"); return NULL; } /* get the image size */ imgsize = PyObject_GetAttrString(state.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); /* set all block data to unloaded */ for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { state.chunks[i][j].loaded = 0; } } /* get the block data for the center column, erroring out if needed */ if (load_chunk(&state, 0, 0, 1)) { render_mode_destroy(rendermode); Py_DECREF(blockmap); return NULL; } if (state.chunks[1][1].sections[state.chunky].blocks == NULL) { /* this section doesn't exist, let's skeddadle */ render_mode_destroy(rendermode); Py_DECREF(blockmap); unload_all_chunks(&state); Py_RETURN_NONE; } /* set blocks_py, state.blocks, and state.blockdatas as convenience */ blocks_py = state.blocks = state.chunks[1][1].sections[state.chunky].blocks; state.blockdatas = state.chunks[1][1].sections[state.chunky].data; /* set up the random number generator again for each chunk so tallgrass is in the same place, no matter what mode is used */ srand(1); for (state.x = 15; state.x > -1; state.x--) { for (state.z = 0; state.z < 16; state.z++) { /* set up the render coordinates */ state.imgx = xoff + state.x*12 + state.z*12; /* 16*12 -- offset for y direction, 15*6 -- offset for x */ state.imgy = yoff - state.x*6 + state.z*6 + 16*12 + 15*6; for (state.y = 0; state.y < 16; state.y++) { unsigned char ancilData; state.imgy -= 12; /* get blockid */ state.block = getArrayShort3D(blocks_py, state.x, state.y, state.z); if (state.block == 0 || render_mode_hidden(rendermode, state.x, state.y, state.z)) { continue; } /* make sure we're rendering inside the image boundaries */ if ((state.imgx >= imgsize0 + 24) || (state.imgx <= -24)) { continue; } if ((state.imgy >= imgsize1 + 24) || (state.imgy <= -24)) { continue; } /* check for occlusion */ if (render_mode_occluded(rendermode, state.x, state.y, state.z)) { continue; } /* everything stored here will be a borrowed ref */ if (block_has_property(state.block, NODATA)) { /* block shouldn't have data associated with it, set it to 0 */ ancilData = 0; state.block_data = 0; state.block_pdata = 0; } else { /* block has associated data, use it */ ancilData = getArrayByte3D(state.blockdatas, state.x, state.y, state.z); state.block_data = ancilData; /* block that need pseudo ancildata: * grass, water, glass, chest, restone wire, * ice, fence, portal, iron bars, glass panes */ if ((state.block == 2) || (state.block == 9) || (state.block == 20) || (state.block == 54) || (state.block == 55) || (state.block == 64) || (state.block == 71) || (state.block == 79) || (state.block == 85) || (state.block == 90) || (state.block == 101) || (state.block == 102) || (state.block == 113) || (state.block == 139)) { ancilData = generate_pseudo_data(&state, ancilData); state.block_pdata = ancilData; } else { state.block_pdata = 0; } } /* make sure our block info is in-bounds */ if (state.block >= max_blockid || ancilData >= max_data) continue; /* get the texture */ t = PyList_GET_ITEM(blockmap, max_data * state.block + ancilData); /* if we don't get a texture, try it again with 0 data */ if ((t == NULL || t == Py_None) && ancilData != 0) t = PyList_GET_ITEM(blockmap, max_data * state.block); /* if we found a proper texture, render it! */ if (t != NULL && t != Py_None) { PyObject *src, *mask, *mask_light; int randx = 0, randy = 0; src = PyTuple_GetItem(t, 0); mask = PyTuple_GetItem(t, 0); mask_light = PyTuple_GetItem(t, 1); if (mask == Py_None) mask = src; if (state.block == 31) { /* add a random offset to the postion of the tall grass to make it more wild */ randx = rand() % 6 + 1 - 3; randy = rand() % 6 + 1 - 3; state.imgx += randx; state.imgy += randy; } render_mode_draw(rendermode, src, mask, mask_light); if (state.block == 31) { /* undo the random offsets */ state.imgx -= randx; state.imgy -= randy; } } } } } /* free up the rendermode info */ render_mode_destroy(rendermode); Py_DECREF(blockmap); unload_all_chunks(&state); Py_RETURN_NONE; }
/* TODO triple check this to make sure reference counting is correct */ PyObject* chunk_render(PyObject *self, PyObject *args) { RenderState state; int xoff, yoff; PyObject *imgsize, *imgsize0_py, *imgsize1_py; int imgsize0, imgsize1; PyObject *blocks_py; PyObject *left_blocks_py; PyObject *right_blocks_py; PyObject *up_left_blocks_py; PyObject *up_right_blocks_py; RenderModeInterface *rendermode; void *rm_data; PyObject *t = NULL; if (!PyArg_ParseTuple(args, "OOiiO", &state.self, &state.img, &xoff, &yoff, &state.blockdata_expanded)) return NULL; /* fill in important modules */ state.textures = textures; state.chunk = chunk_mod; /* set up the render mode */ rendermode = get_render_mode(&state); rm_data = calloc(1, rendermode->data_size); if (rendermode->start(rm_data, &state)) { free(rm_data); return Py_BuildValue("i", "-1"); } /* get the image size */ imgsize = PyObject_GetAttrString(state.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(state.self, "blocks"); state.blocks = blocks_py; left_blocks_py = PyObject_GetAttrString(state.self, "left_blocks"); state.left_blocks = left_blocks_py; right_blocks_py = PyObject_GetAttrString(state.self, "right_blocks"); state.right_blocks = right_blocks_py; up_left_blocks_py = PyObject_GetAttrString(state.self, "up_left_blocks"); state.up_left_blocks = up_left_blocks_py; up_right_blocks_py = PyObject_GetAttrString(state.self, "up_right_blocks"); state.up_right_blocks = up_right_blocks_py; for (state.x = 15; state.x > -1; state.x--) { for (state.y = 0; state.y < 16; state.y++) { PyObject *blockid = NULL; /* set up the render coordinates */ state.imgx = xoff + state.x*12 + state.y*12; /* 128*12 -- offset for z direction, 15*6 -- offset for x */ state.imgy = yoff - state.x*6 + state.y*6 + 128*12 + 15*6; for (state.z = 0; state.z < 128; state.z++) { state.imgy -= 12; /* get blockid */ state.block = getArrayByte3D(blocks_py, state.x, state.y, state.z); if (state.block == 0) { continue; } /* make sure we're rendering inside the image boundaries */ if ((state.imgx >= imgsize0 + 24) || (state.imgx <= -24)) { continue; } if ((state.imgy >= imgsize1 + 24) || (state.imgy <= -24)) { continue; } /* decref'd on replacement *and* at the end of the z for block */ if (blockid) { Py_DECREF(blockid); } blockid = PyInt_FromLong(state.block); // check for occlusion if (rendermode->occluded(rm_data, &state)) { continue; } // everything stored here will be a borrowed ref /* get the texture and mask from block type / ancil. data */ if (!PySequence_Contains(special_blocks, blockid)) { /* t = textures.blockmap[blockid] */ t = PyList_GetItem(blockmap, state.block); } else { PyObject *tmp; unsigned char ancilData = getArrayByte3D(state.blockdata_expanded, state.x, state.y, state.z); if ((state.block == 85) || (state.block == 9) || (state.block == 55) || (state.block == 54) || (state.block == 2) || (state.block == 90)) { ancilData = generate_pseudo_data(&state, ancilData); } 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 we found a proper texture, render it! */ if (t != NULL && t != Py_None) { PyObject *src, *mask, *mask_light; src = PyTuple_GetItem(t, 0); mask = PyTuple_GetItem(t, 1); mask_light = PyTuple_GetItem(t, 2); if (mask == Py_None) mask = src; rendermode->draw(rm_data, &state, src, mask, mask_light); } } if (blockid) { Py_DECREF(blockid); blockid = NULL; } } } /* free up the rendermode info */ rendermode->finish(rm_data, &state); free(rm_data); Py_DECREF(blocks_py); Py_XDECREF(left_blocks_py); Py_XDECREF(right_blocks_py); Py_XDECREF(up_left_blocks_py); Py_XDECREF(up_right_blocks_py); return Py_BuildValue("i",2); }