Store cooked models as structs instead of list of tuples - now the important loops are all white (C code) but it leaks memory

This commit is contained in:
David Vierra 2015-01-04 12:46:40 -10:00
parent 864990429d
commit 801307e069
3 changed files with 120 additions and 35 deletions

View File

@ -0,0 +1,20 @@
cdef struct ModelQuad:
float[24] xyzuvc
char[4] cullface # isCulled, dx, dy, dz
cdef struct ModelQuadList:
int count
ModelQuad *quads
cdef class BlockModels:
cdef object resourceLoader
cdef object blocktypes
cdef object modelBlockJsons
cdef object modelStateJsons
cdef object modelQuads
cdef object _textureNames
cdef public object firstTextures
cdef object cookedModels
cdef ModelQuadList cookedModelsByID[4096][16]
cdef object cooked

View File

@ -16,10 +16,21 @@ from array import array
from mceditlib import faces from mceditlib import faces
from mceditlib.geometry import Vector, FloatBox from mceditlib.geometry import Vector, FloatBox
from libc.stdlib cimport malloc, free
from libc.string cimport memset
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
cdef struct ModelQuad:
float[24] xyzuvc
char[4] cullface # isCulled, dx, dy, dz
cdef struct ModelQuadList:
int count
ModelQuad *quads
cdef class BlockModels(object):
class BlockModels(object):
def _getBlockModel(self, modelName): def _getBlockModel(self, modelName):
model = self.modelBlockJsons.get(modelName) model = self.modelBlockJsons.get(modelName)
if model is None: if model is None:
@ -53,7 +64,8 @@ class BlockModels(object):
self._textureNames = set() self._textureNames = set()
self.firstTextures = {} # first texture found for each block - used for icons (xxx) self.firstTextures = {} # first texture found for each block - used for icons (xxx)
self.cookedModels = {} # nameAndState -> list[(xyzuvc, cullface)] self.cookedModels = {} # nameAndState -> list[(xyzuvc, cullface)]
self.cookedModelsByID = numpy.zeros((256*16, 16), dtype=list) # (id, meta) -> list[(xyzuvc, cullface)] #self.cookedModelsByID = numpy.zeros((256*16, 16), dtype=list) # (id, meta) -> list[(xyzuvc, cullface)]
memset(self.cookedModelsByID, 0, sizeof(self.cookedModelsByID))
self.cooked = False self.cooked = False
for i, block in enumerate(blocktypes): for i, block in enumerate(blocktypes):
@ -266,17 +278,44 @@ class BlockModels(object):
xyzuvc.view('uint8')[:, 20:] = faceShades[face] xyzuvc.view('uint8')[:, 20:] = faceShades[face]
else: else:
xyzuvc.view('uint8')[:, 20:] = 0xff xyzuvc.view('uint8')[:, 20:] = 0xff
xyzuvc.shape = 1, 4, 6 # add the first dimension to stack along in modelmesh.pyx xyzuvc.shape = 24 # flatten to store in ModelQuad.xyzuvc
cookedQuads.append((xyzuvc, cullface)) cookedQuads.append((xyzuvc, cullface))
cookedModels[nameAndState] = cookedQuads cookedModels[nameAndState] = cookedQuads
ID, meta = self.blocktypes.IDsByState[nameAndState] ID, meta = self.blocktypes.IDsByState[nameAndState]
self.cookedModelsByID[ID, meta] = cookedQuads self.storeQuads(cookedQuads, ID, meta)
self.cookedModels = cookedModels self.cookedModels = cookedModels
self.cooked = True self.cooked = True
def storeQuads(self, list cookedQuads, unsigned short ID, unsigned char meta):
cdef ModelQuadList modelQuads
modelQuads.count = len(cookedQuads)
cdef void * quads = malloc(modelQuads.count * sizeof(ModelQuad))
modelQuads.quads = <ModelQuad *>quads
cdef float[:] xyzuvc, quadxyzuvc
cdef int i
for i in range(modelQuads.count):
xyzuvc, cullface = cookedQuads[i]
quadxyzuvc = modelQuads.quads[i].xyzuvc
quadxyzuvc[:] = xyzuvc[:]
if cullface:
modelQuads.quads[i].cullface[0] = 1
dx, dy, dz = cullface.vector
modelQuads.quads[i].cullface[1] = dx
modelQuads.quads[i].cullface[2] = dy
modelQuads.quads[i].cullface[3] = dz
else:
modelQuads.quads[i].cullface[0] = 0
modelQuads.quads[i].cullface[1] = 0
modelQuads.quads[i].cullface[2] = 0
modelQuads.quads[i].cullface[3] = 0
self.cookedModelsByID[ID][meta] = modelQuads
def rotateVertices(self, rotation, variantXrot, variantYrot, variantZrot, xyzuvc): def rotateVertices(self, rotation, variantXrot, variantYrot, variantZrot, xyzuvc):
if rotation is not None: if rotation is not None:
origin = rotation["origin"] origin = rotation["origin"]

View File

@ -10,6 +10,10 @@ cimport numpy
from mcedit2.rendering import renderstates from mcedit2.rendering import renderstates
from mcedit2.rendering.vertexarraybuffer import VertexArrayBuffer from mcedit2.rendering.vertexarraybuffer import VertexArrayBuffer
from mcedit2.rendering cimport blockmodels
from libc.stdlib cimport malloc, realloc, free
from libc.string cimport memcpy
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -32,12 +36,9 @@ class BlockModelMesh(object):
cdef numpy.ndarray[numpy.uint8_t, ndim=3] data cdef numpy.ndarray[numpy.uint8_t, ndim=3] data
cdef numpy.ndarray[numpy.uint8_t, ndim=1] renderType cdef numpy.ndarray[numpy.uint8_t, ndim=1] renderType
cdef numpy.ndarray[numpy.uint8_t, ndim=1] opaqueCube cdef numpy.ndarray[numpy.uint8_t, ndim=1] opaqueCube
cdef blockmodels.BlockModels blockModels
chunk = self.sectionUpdate.chunkUpdate.chunk
cdef short cy = self.sectionUpdate.cy cdef short cy = self.sectionUpdate.cy
section = chunk.getSection(cy)
if section is None:
return
atlas = self.sectionUpdate.chunkUpdate.updateTask.textureAtlas atlas = self.sectionUpdate.chunkUpdate.updateTask.textureAtlas
blockModels = atlas.blockModels blockModels = atlas.blockModels
@ -45,28 +46,33 @@ class BlockModelMesh(object):
blocktypes = self.sectionUpdate.blocktypes blocktypes = self.sectionUpdate.blocktypes
areaBlocks = self.sectionUpdate.areaBlocks areaBlocks = self.sectionUpdate.areaBlocks
data = section.Data data = self.sectionUpdate.Data
renderType = self.sectionUpdate.renderType renderType = self.sectionUpdate.renderType
opaqueCube = blocktypes.opaqueCube opaqueCube = blocktypes.opaqueCube
faceQuadVerts = [] #faceQuadVerts = []
cdef unsigned short y, z, x, ID, meta cdef unsigned short y, z, x, ID, meta
cdef short dx, dy, dz, cdef short dx, dy, dz,
cdef unsigned short nx, ny, nz, nID cdef unsigned short nx, ny, nz, nID
cdef numpy.ndarray verts cdef blockmodels.ModelQuadList quads
cdef list quads cdef blockmodels.ModelQuad quad
cdef tuple quad
cdef numpy.ndarray[numpy.uint16_t, ndim=1] coords = numpy.zeros(3, dtype=numpy.uint16) cdef unsigned short rx, ry, rz
cdef numpy.ndarray[list, ndim=2] cookedModelsByID = blockModels.cookedModelsByID
cdef unsigned int buffer_ptr = 0
cdef unsigned int buffer_size = 256
cdef float * vertexBuffer = <float *>malloc(buffer_size * sizeof(float) * 24)
cdef float * xyzuvc
cdef numpy.ndarray vabuffer
if vertexBuffer == NULL:
return
for y in range(1, 17): for y in range(1, 17):
coords[1] = y - 1 + (cy << 4) ry = y - 1 + (cy << 4)
for z in range(1, 17): for z in range(1, 17):
coords[2] = z - 1 rz = z - 1
for x in range(1, 17): for x in range(1, 17):
coords[0] = x - 1 rx = x - 1
ID = areaBlocks[y, z, x] ID = areaBlocks[y, z, x]
if ID == 0: if ID == 0:
continue continue
@ -74,27 +80,47 @@ class BlockModelMesh(object):
if renderType[ID] != 3: # only model blocks for now if renderType[ID] != 3: # only model blocks for now
continue continue
quads = cookedModelsByID[ID, meta] quads = blockModels.cookedModelsByID[ID][meta]
if quads is None: if quads.count == 0:
continue continue
for xyzuvc, cullface in quads: for i in range(quads.count):
if cullface is not None: quad = quads.quads[i]
dx, dy, dz = cullface.vector if quad.cullface[0]:
nx = x + dx nx = x + quad.cullface[1]
ny = y + dy ny = y + quad.cullface[2]
nz = z + dz nz = z + quad.cullface[3]
nID = areaBlocks[ny, nz, nx] nID = areaBlocks[ny, nz, nx]
if opaqueCube[nID]: if opaqueCube[nID]:
continue continue
verts = numpy.array(xyzuvc) xyzuvc = vertexBuffer + buffer_ptr * 24
verts[..., :3] += coords memcpy(xyzuvc, quad.xyzuvc, sizeof(float) * 24)
faceQuadVerts.append(verts)
# log.info("Block %s:\nVertices: %s", (x-1, y-1, z-1), verts)
# raise SystemExit #(<object>verts).shape = 1, 4, 6
if len(faceQuadVerts): #verts[..., :3] += coords
vertexArray = VertexArrayBuffer(len(faceQuadVerts), lights=False) xyzuvc[0] += rx
vertexArray.buffer[..., :6] = numpy.vstack(faceQuadVerts) xyzuvc[1] += ry
xyzuvc[2] += rz
xyzuvc[6] += rx
xyzuvc[7] += ry
xyzuvc[8] += rz
xyzuvc[12] += rx
xyzuvc[13] += ry
xyzuvc[14] += rz
xyzuvc[18] += rx
xyzuvc[19] += ry
xyzuvc[20] += rz
buffer_ptr += 1
if buffer_ptr >= buffer_size:
buffer_size *= 2
vertexBuffer = <float *>realloc(vertexBuffer, buffer_size * sizeof(float) * 24)
#buffer.resize((buffer_size, 24))
#faceQuadVerts.append(verts)
if buffer_ptr: # now buffer size
vertexArray = VertexArrayBuffer(buffer_ptr, lights=False)
vabuffer = vertexArray.buffer
memcpy(vabuffer.data, vertexBuffer, buffer_ptr * sizeof(float) * 24)
self.vertexArrays = [vertexArray] self.vertexArrays = [vertexArray]
free(vertexBuffer)