diff --git a/src/d3d/d3d8.cpp b/src/d3d/d3d8.cpp index 0cfa398..40756da 100644 --- a/src/d3d/d3d8.cpp +++ b/src/d3d/d3d8.cpp @@ -257,7 +257,7 @@ instance(rw::ObjPipeline *rwpipe, Atomic *atomic) geo->instData = header; header->platform = PLATFORM_D3D8; - header->serialNumber = 0; + header->serialNumber = meshh->serialNum; header->numMeshes = meshh->numMeshes; header->inst = rwNewT(InstanceData, header->numMeshes, MEMDUR_EVENT | ID_GEOMETRY); diff --git a/src/d3d/d3d9.cpp b/src/d3d/d3d9.cpp index 923c62a..a4f75ed 100644 --- a/src/d3d/d3d9.cpp +++ b/src/d3d/d3d9.cpp @@ -97,14 +97,12 @@ getDeclaration(void *declaration, VertexElement *elements) #endif } - -void* -destroyNativeData(void *object, int32, int32) +void +freeInstanceData(Geometry *geometry) { - Geometry *geometry = (Geometry*)object; if(geometry->instData == nil || geometry->instData->platform != PLATFORM_D3D9) - return object; + return; InstanceDataHeader *header = (InstanceDataHeader*)geometry->instData; geometry->instData = nil; @@ -114,6 +112,14 @@ destroyNativeData(void *object, int32, int32) deleteObject(header->vertexStream[1].vertexBuffer); rwFree(header->inst); rwFree(header); + return; +} + + +void* +destroyNativeData(void *object, int32, int32) +{ + freeInstanceData((Geometry*)object); return object; } @@ -309,23 +315,18 @@ registerNativeDataPlugin(void) getSizeNativeData); } -static void -instance(rw::ObjPipeline *rwpipe, Atomic *atomic) +static InstanceDataHeader* +instanceMesh(rw::ObjPipeline *rwpipe, Geometry *geo) { - ObjPipeline *pipe = (ObjPipeline*)rwpipe; - Geometry *geo = atomic->geometry; - // TODO: allow for REINSTANCE - if(geo->instData) - return; InstanceDataHeader *header = rwNewT(InstanceDataHeader, 1, MEMDUR_EVENT | ID_GEOMETRY); MeshHeader *meshh = geo->meshHeader; - geo->instData = header; header->platform = PLATFORM_D3D9; - header->serialNumber = 0; + header->serialNumber = meshh->serialNum; header->numMeshes = meshh->numMeshes; header->primType = meshh->flags == 1 ? D3DPT_TRIANGLESTRIP : D3DPT_TRIANGLELIST; header->useOffsets = 0; + header->vertexDeclaration = nil; header->totalNumVertex = geo->numVertices; header->totalNumIndex = meshh->totalIndices; header->inst = rwNewT(InstanceData, header->numMeshes, MEMDUR_EVENT | ID_GEOMETRY); @@ -359,7 +360,36 @@ instance(rw::ObjPipeline *rwpipe, Atomic *atomic) memset(&header->vertexStream, 0, 2*sizeof(VertexStream)); - pipe->instanceCB(geo, header); + return header; +} + +static void +instance(rw::ObjPipeline *rwpipe, Atomic *atomic) +{ + ObjPipeline *pipe = (ObjPipeline*)rwpipe; + Geometry *geo = atomic->geometry; + // don't try to (re)instance native data + if(geo->flags & Geometry::NATIVE) + return; + + InstanceDataHeader *header = (InstanceDataHeader*)geo->instData; + if(geo->instData){ + // Already have instanced data, so check if we have to reinstance + assert(header->platform == PLATFORM_D3D9); + if(header->serialNumber != geo->meshHeader->serialNum){ + // Mesh changed, so reinstance everything + freeInstanceData(geo); + } + } + + // no instance or complete reinstance + if(geo->instData == nil){ + geo->instData = instanceMesh(rwpipe, geo); + pipe->instanceCB(geo, (InstanceDataHeader*)geo->instData, 0); + }else if(geo->lockedSinceInst) + pipe->instanceCB(geo, (InstanceDataHeader*)geo->instData, 1); + + geo->lockedSinceInst = 0; } static void @@ -401,9 +431,7 @@ render(rw::ObjPipeline *rwpipe, Atomic *atomic) { ObjPipeline *pipe = (ObjPipeline*)rwpipe; Geometry *geo = atomic->geometry; - // TODO: allow for REINSTANCE - if(geo->instData == nil) - pipe->instance(atomic); + pipe->instance(atomic); assert(geo->instData != nil); assert(geo->instData->platform == PLATFORM_D3D9); if(pipe->renderCB) @@ -422,81 +450,95 @@ ObjPipeline::ObjPipeline(uint32 platform) } void -defaultInstanceCB(Geometry *geo, InstanceDataHeader *header) +defaultInstanceCB(Geometry *geo, InstanceDataHeader *header, bool32 reinstance) { - VertexElement dcl[NUMDECLELT]; - - VertexStream *s = &header->vertexStream[0]; - s->offset = 0; - s->managed = 1; - s->geometryFlags = 0; - s->dynamicLock = 0; - int i = 0; - dcl[i].stream = 0; - dcl[i].offset = 0; - dcl[i].type = D3DDECLTYPE_FLOAT3; - dcl[i].method = D3DDECLMETHOD_DEFAULT; - dcl[i].usage = D3DDECLUSAGE_POSITION; - dcl[i].usageIndex = 0; - i++; - uint16 stride = 12; - s->geometryFlags |= 0x2; + VertexElement dcl[NUMDECLELT]; + VertexStream *s = &header->vertexStream[0]; bool isPrelit = (geo->flags & Geometry::PRELIT) != 0; - if(isPrelit){ - dcl[i].stream = 0; - dcl[i].offset = stride; - dcl[i].type = D3DDECLTYPE_D3DCOLOR; - dcl[i].method = D3DDECLMETHOD_DEFAULT; - dcl[i].usage = D3DDECLUSAGE_COLOR; - dcl[i].usageIndex = 0; - i++; - s->geometryFlags |= 0x8; - stride += 4; - } - - for(int32 n = 0; n < geo->numTexCoordSets; n++){ - dcl[i].stream = 0; - dcl[i].offset = stride; - dcl[i].type = D3DDECLTYPE_FLOAT2; - dcl[i].method = D3DDECLMETHOD_DEFAULT; - dcl[i].usage = D3DDECLUSAGE_TEXCOORD; - dcl[i].usageIndex = (uint8)n; - i++; - s->geometryFlags |= 0x10 << n; - stride += 8; - } - bool hasNormals = (geo->flags & Geometry::NORMALS) != 0; - if(hasNormals){ - dcl[i].stream = 0; - dcl[i].offset = stride; - dcl[i].type = D3DDECLTYPE_FLOAT3; - dcl[i].method = D3DDECLMETHOD_DEFAULT; - dcl[i].usage = D3DDECLUSAGE_NORMAL; - dcl[i].usageIndex = 0; - i++; - s->geometryFlags |= 0x4; - stride += 12; - } - dcl[i] = D3DDECL_END(); - header->vertexStream[0].stride = stride; - - header->vertexDeclaration = createVertexDeclaration((VertexElement*)dcl); - - s->vertexBuffer = createVertexBuffer(header->totalNumVertex*s->stride, 0, D3DPOOL_MANAGED); // TODO: support both vertex buffers - uint8 *verts = lockVertices(s->vertexBuffer, 0, 0, D3DLOCK_NOSYSLOCK); - for(i = 0; dcl[i].usage != D3DDECLUSAGE_POSITION || dcl[i].usageIndex != 0; i++) - ; - instV3d(vertFormatMap[dcl[i].type], verts + dcl[i].offset, - geo->morphTargets[0].vertices, - header->totalNumVertex, - header->vertexStream[dcl[i].stream].stride); - if(isPrelit){ + if(!reinstance){ + // Create declarations and buffers only the first time + + assert(s->vertexBuffer == nil); + s->offset = 0; + s->managed = 1; + s->geometryFlags = 0; + s->dynamicLock = 0; + + dcl[i].stream = 0; + dcl[i].offset = 0; + dcl[i].type = D3DDECLTYPE_FLOAT3; + dcl[i].method = D3DDECLMETHOD_DEFAULT; + dcl[i].usage = D3DDECLUSAGE_POSITION; + dcl[i].usageIndex = 0; + i++; + uint16 stride = 12; + s->geometryFlags |= 0x2; + + if(isPrelit){ + dcl[i].stream = 0; + dcl[i].offset = stride; + dcl[i].type = D3DDECLTYPE_D3DCOLOR; + dcl[i].method = D3DDECLMETHOD_DEFAULT; + dcl[i].usage = D3DDECLUSAGE_COLOR; + dcl[i].usageIndex = 0; + i++; + s->geometryFlags |= 0x8; + stride += 4; + } + + for(int32 n = 0; n < geo->numTexCoordSets; n++){ + dcl[i].stream = 0; + dcl[i].offset = stride; + dcl[i].type = D3DDECLTYPE_FLOAT2; + dcl[i].method = D3DDECLMETHOD_DEFAULT; + dcl[i].usage = D3DDECLUSAGE_TEXCOORD; + dcl[i].usageIndex = (uint8)n; + i++; + s->geometryFlags |= 0x10 << n; + stride += 8; + } + + if(hasNormals){ + dcl[i].stream = 0; + dcl[i].offset = stride; + dcl[i].type = D3DDECLTYPE_FLOAT3; + dcl[i].method = D3DDECLMETHOD_DEFAULT; + dcl[i].usage = D3DDECLUSAGE_NORMAL; + dcl[i].usageIndex = 0; + i++; + s->geometryFlags |= 0x4; + stride += 12; + } + dcl[i] = D3DDECL_END(); + s->stride = stride; + + assert(header->vertexDeclaration == nil); + header->vertexDeclaration = createVertexDeclaration((VertexElement*)dcl); + + s->vertexBuffer = createVertexBuffer(header->totalNumVertex*s->stride, 0, D3DPOOL_MANAGED); + }else + getDeclaration(header->vertexDeclaration, dcl); + + uint8 *verts = lockVertices(s->vertexBuffer, 0, 0, D3DLOCK_NOSYSLOCK); + + // Instance vertices + if(!reinstance || geo->lockedSinceInst&Geometry::LOCKVERTICES){ + for(i = 0; dcl[i].usage != D3DDECLUSAGE_POSITION || dcl[i].usageIndex != 0; i++) + ; + instV3d(vertFormatMap[dcl[i].type], verts + dcl[i].offset, + geo->morphTargets[0].vertices, + header->totalNumVertex, + header->vertexStream[dcl[i].stream].stride); + } + + // Instance prelight colors + if(isPrelit && (!reinstance || geo->lockedSinceInst&Geometry::LOCKPRELIGHT)){ for(i = 0; dcl[i].usage != D3DDECLUSAGE_COLOR || dcl[i].usageIndex != 0; i++) ; InstanceData *inst = header->inst; @@ -512,16 +554,20 @@ defaultInstanceCB(Geometry *geo, InstanceDataHeader *header) } } + // Instance tex coords for(int32 n = 0; n < geo->numTexCoordSets; n++){ - for(i = 0; dcl[i].usage != D3DDECLUSAGE_TEXCOORD || dcl[i].usageIndex != n; i++) - ; - instTexCoords(vertFormatMap[dcl[i].type], verts + dcl[i].offset, - geo->texCoords[n], - header->totalNumVertex, - header->vertexStream[dcl[i].stream].stride); + if(!reinstance || geo->lockedSinceInst&(Geometry::LOCKTEXCOORDS<texCoords[n], + header->totalNumVertex, + header->vertexStream[dcl[i].stream].stride); + } } - if(hasNormals){ + // Instance normals + if(hasNormals && (!reinstance || geo->lockedSinceInst&Geometry::LOCKNORMALS)){ for(i = 0; dcl[i].usage != D3DDECLUSAGE_NORMAL || dcl[i].usageIndex != 0; i++) ; instV3d(vertFormatMap[dcl[i].type], verts + dcl[i].offset, diff --git a/src/d3d/rwd3d9.h b/src/d3d/rwd3d9.h index b06af7a..38a5c7e 100644 --- a/src/d3d/rwd3d9.h +++ b/src/d3d/rwd3d9.h @@ -67,14 +67,14 @@ void registerNativeDataPlugin(void); class ObjPipeline : public rw::ObjPipeline { public: - void (*instanceCB)(Geometry *geo, InstanceDataHeader *header); + void (*instanceCB)(Geometry *geo, InstanceDataHeader *header, bool32 reinstance); void (*uninstanceCB)(Geometry *geo, InstanceDataHeader *header); void (*renderCB)(Atomic *atomic, InstanceDataHeader *header); ObjPipeline(uint32 platform); }; -void defaultInstanceCB(Geometry *geo, InstanceDataHeader *header); +void defaultInstanceCB(Geometry *geo, InstanceDataHeader *header, bool32 reinstance); void defaultUninstanceCB(Geometry *geo, InstanceDataHeader *header); void defaultRenderCB(Atomic *atomic, InstanceDataHeader *header); diff --git a/src/d3d/xbox.cpp b/src/d3d/xbox.cpp index cb50b18..e293695 100644 --- a/src/d3d/xbox.cpp +++ b/src/d3d/xbox.cpp @@ -212,7 +212,7 @@ instance(rw::ObjPipeline *rwpipe, Atomic *atomic) // The 0x18 byte are the resentryheader. // We don't have it but it's used for alignment. header->data = rwNewT(uint8, header->size + 0x18, MEMDUR_EVENT | ID_GEOMETRY); - header->serialNumber = 0; + header->serialNumber = meshh->serialNum; header->numMeshes = meshh->numMeshes; header->primType = meshh->flags == MeshHeader::TRISTRIP ? D3DPT_TRIANGLESTRIP : D3DPT_TRIANGLELIST; diff --git a/src/geometry.cpp b/src/geometry.cpp index 6fa4876..1db174c 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -73,6 +73,7 @@ Geometry::create(int32 numVerts, int32 numTris, uint32 flags) geo->addMorphTargets(1); geo->matList.init(); + geo->lockedSinceInst = 0; geo->meshHeader = nil; geo->instData = nil; geo->refCount = 1; @@ -98,6 +99,24 @@ Geometry::destroy(void) } } +void +Geometry::lock(int32 lockFlags) +{ + lockedSinceInst |= lockFlags; + if(lockFlags & LOCKPOLYGONS){ + rwFree(this->meshHeader); + this->meshHeader = nil; + } +} + +void +Geometry::unlock(void) +{ + if(this->meshHeader == nil) + this->buildMeshes(); + +} + struct GeoStreamData { uint32 flags; diff --git a/src/geoplg.cpp b/src/geoplg.cpp index 06b52a5..db0c72c 100644 --- a/src/geoplg.cpp +++ b/src/geoplg.cpp @@ -23,6 +23,8 @@ namespace rw { +static uint16 nextSerialNum = 1; + // Mesh // Allocate a mesh header, meshes and optionally indices. @@ -50,7 +52,7 @@ Geometry::allocateMeshes(int32 numMeshes, uint32 numIndices, bool32 noIndices) this->meshHeader = mh; } mh->numMeshes = numMeshes; - mh->serialNum = 0; // TODO + mh->serialNum = nextSerialNum++; mh->totalIndices = numIndices; m = mh->getMeshes(); indices = (uint16*)&m[numMeshes]; diff --git a/src/gl/gl3pipe.cpp b/src/gl/gl3pipe.cpp index f50bfa5..793d794 100644 --- a/src/gl/gl3pipe.cpp +++ b/src/gl/gl3pipe.cpp @@ -35,7 +35,7 @@ instance(rw::ObjPipeline *rwpipe, Atomic *atomic) geo->instData = header; header->platform = PLATFORM_GL3; - header->serialNumber = 0; + header->serialNumber = meshh->serialNum; header->numMeshes = meshh->numMeshes; header->primType = meshh->flags == 1 ? GL_TRIANGLE_STRIP : GL_TRIANGLES; header->totalNumVertex = geo->numVertices; diff --git a/src/rwobjects.h b/src/rwobjects.h index ed38d38..8372703 100644 --- a/src/rwobjects.h +++ b/src/rwobjects.h @@ -343,7 +343,7 @@ struct MeshHeader }; uint32 flags; uint16 numMeshes; - uint16 serialNum; // not used yet + uint16 serialNum; uint32 totalIndices; uint32 pad; // needed for alignment of Meshes // after this the meshes @@ -391,13 +391,13 @@ struct MaterialList uint32 streamGetSize(void); }; -// TODO: implement locking struct Geometry { PLUGINBASE enum { ID = 8 }; Object object; uint32 flags; + uint16 lockedSinceInst; int32 numTriangles; int32 numVertices; int32 numMorphTargets; @@ -417,6 +417,8 @@ struct Geometry static Geometry *create(int32 numVerts, int32 numTris, uint32 flags); void destroy(void); + void lock(int32 lockFlags); + void unlock(void); void addMorphTargets(int32 n); void calculateBoundingSphere(void); bool32 hasColoredMaterial(void); @@ -453,6 +455,26 @@ struct Geometry NATIVEINSTANCE = 0x02000000 }; + enum LockFlags + { + LOCKPOLYGONS = 0x0001, + LOCKVERTICES = 0x0002, + LOCKNORMALS = 0x0004, + LOCKPRELIGHT = 0x0008, + + LOCKTEXCOORDS = 0x0010, + LOCKTEXCOORDS1 = 0x0010, + LOCKTEXCOORDS2 = 0x0020, + LOCKTEXCOORDS3 = 0x0040, + LOCKTEXCOORDS4 = 0x0080, + LOCKTEXCOORDS5 = 0x0100, + LOCKTEXCOORDS6 = 0x0200, + LOCKTEXCOORDS7 = 0x0400, + LOCKTEXCOORDS8 = 0x0800, + LOCKTEXCOORDSALL = 0x0ff0, + + LOCKALL = 0x0fff + }; }; void registerMeshPlugin(void);