From 1951d063b4853a2f68d0ce2011e2ad77e1ca1c3a Mon Sep 17 00:00:00 2001 From: Angelo Papenhoff Date: Thu, 25 Dec 2014 11:14:36 +0100 Subject: [PATCH] Added basic OpenGL instancing code. Corrected Geometry::streamWrite(). --- dffwrite.cpp | 3 + src/clump.cpp | 21 ++++-- src/geometry.cpp | 31 +++++--- src/ogl.cpp | 189 ++++++++++++++++++++++++++++++++++++++++++++++- src/plugins.cpp | 8 +- src/rwogl.h | 3 + 6 files changed, 232 insertions(+), 23 deletions(-) diff --git a/dffwrite.cpp b/dffwrite.cpp index 955a090..80cca3e 100644 --- a/dffwrite.cpp +++ b/dffwrite.cpp @@ -27,6 +27,9 @@ main(int argc, char *argv[]) c = Rw::Clump::streamRead(in); in.close(); + for(Rw::int32 i = 0; i < c->numAtomics; i++) + Rw::Gl::Instance(c->atomicList[i]); + ofstream out(argv[2], ios::binary); c->streamWrite(out); out.close(); diff --git a/src/clump.cpp b/src/clump.cpp index 4475db6..56ed30f 100644 --- a/src/clump.cpp +++ b/src/clump.cpp @@ -125,7 +125,9 @@ Clump::Clump(void) this->numAtomics = 0; this->numLights = 0; this->numCameras = 0; - constructPlugins(); + this->atomicList = NULL; + this->lightList = NULL; + this->constructPlugins(); } Clump::Clump(Clump *c) @@ -133,12 +135,13 @@ Clump::Clump(Clump *c) this->numAtomics = c->numAtomics; this->numLights = c->numLights; this->numCameras = c->numCameras; - copyPlugins(c); + // TODO: atomics and lights + this->copyPlugins(c); } Clump::~Clump(void) { - destructPlugins(); + this->destructPlugins(); } Clump* @@ -169,14 +172,17 @@ Clump::streamRead(istream &stream) assert(FindChunk(stream, ID_GEOMETRYLIST, NULL, NULL)); assert(FindChunk(stream, ID_STRUCT, NULL, NULL)); numGeometries = readInt32(stream); - Geometry **geometryList = new Geometry*[numGeometries]; + Geometry **geometryList = 0; + if(numGeometries) + geometryList = new Geometry*[numGeometries]; for(int32 i = 0; i < numGeometries; i++){ assert(FindChunk(stream, ID_GEOMETRY, NULL, NULL)); geometryList[i] = Geometry::streamRead(stream); } // Atomics - clump->atomicList = new Atomic*[clump->numAtomics]; + if(clump->numAtomics) + clump->atomicList = new Atomic*[clump->numAtomics]; for(int32 i = 0; i < clump->numAtomics; i++){ assert(FindChunk(stream, ID_ATOMIC, NULL, NULL)); clump->atomicList[i] = Atomic::streamReadClump(stream, @@ -185,7 +191,8 @@ Clump::streamRead(istream &stream) } // Lights - clump->lightList = new Light*[clump->numLights]; + if(clump->numLights) + clump->lightList = new Light*[clump->numLights]; for(int32 i = 0; i < clump->numLights; i++){ int32 frm; assert(FindChunk(stream, ID_STRUCT, NULL, NULL)); @@ -278,7 +285,7 @@ Clump::streamGetSize(void) size += 12 + this->atomicList[i]->streamGetSize(); // light - for(int32 i = 0; i < this->numAtomics; i++) + for(int32 i = 0; i < this->numLights; i++) size += 16 + 12 + this->lightList[i]->streamGetSize(); size += 12 + this->streamGetPluginSize(); diff --git a/src/geometry.cpp b/src/geometry.cpp index fe6a7e1..4416d36 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -154,7 +154,7 @@ geoStructSize(Geometry *geo) size += sizeof(GeoStreamData); if(Version < 0x34000) size += 12; // surface properties - if(!(geo->geoflags & 0xFF000000)){ + if(!(geo->geoflags & Geometry::NATIVE)){ if(geo->geoflags&geo->PRELIT) size += 4*geo->numVertices; for(int32 i = 0; i < geo->numTexCoordSets; i++) @@ -164,10 +164,12 @@ geoStructSize(Geometry *geo) for(int32 i = 0; i < geo->numMorphTargets; i++){ MorphTarget *m = &geo->morphTargets[i]; size += 4*4 + 2*4; // bounding sphere and bools - if(m->vertices) - size += 3*geo->numVertices*4; - if(m->normals) - size += 3*geo->numVertices*4; + if(!(geo->geoflags & Geometry::NATIVE)){ + if(m->vertices) + size += 3*geo->numVertices*4; + if(m->normals) + size += 3*geo->numVertices*4; + } } return size; } @@ -202,12 +204,19 @@ Geometry::streamWrite(ostream &stream) for(int32 i = 0; i < this->numMorphTargets; i++){ MorphTarget *m = &this->morphTargets[i]; stream.write((char*)m->boundingSphere, 4*4); - writeInt32(m->vertices != NULL, stream); - writeInt32(m->normals != NULL, stream); - if(m->vertices) - stream.write((char*)m->vertices, 3*this->numVertices*4); - if(m->normals) - stream.write((char*)m->normals, 3*this->numVertices*4); + if(!(this->geoflags & NATIVE)){ + writeInt32(m->vertices != NULL, stream); + writeInt32(m->normals != NULL, stream); + if(m->vertices) + stream.write((char*)m->vertices, + 3*this->numVertices*4); + if(m->normals) + stream.write((char*)m->normals, + 3*this->numVertices*4); + }else{ + writeInt32(0, stream); + writeInt32(0, stream); + } } size = 12 + 4; diff --git a/src/ogl.cpp b/src/ogl.cpp index eab86fe..74bcb7b 100644 --- a/src/ogl.cpp +++ b/src/ogl.cpp @@ -18,6 +18,17 @@ using namespace std; namespace Rw { namespace Gl { +// VC +// 8733 0 0 0 3 +// 45 1 0 0 2 +// 8657 1 3 0 2 +// 4610 2 1 1 3 +// 4185 3 2 1 4 +// 256 4 2 1 4 +// 201 4 4 1 4 +// 457 5 2 0 4 + +// SA // 20303 0 0 0 3 vertices: 3 float // 53 1 0 0 2 texCoords: 2 floats // 20043 1 3 0 2 texCoords: 2 shorts @@ -28,6 +39,7 @@ namespace Gl { // 421 5 2 0 4 indices: 4 ubytes // 12887 6 2 1 4 extracolor:4 ubytes normalized +/* static void printAttribInfo(AttribDesc *attribs, int n) { @@ -38,6 +50,7 @@ printAttribInfo(AttribDesc *attribs, int n) attribs[i].normalized, attribs[i].size); } +*/ void* DestroyNativeData(void *object, int32, int32) @@ -71,7 +84,7 @@ ReadNativeData(istream &stream, int32, void *object, int32, int32) } void -WriteNativeData(ostream &stream, int32 len, void *object, int32, int32) +WriteNativeData(ostream &stream, int32, void *object, int32, int32) { Geometry *geometry = (Geometry*)object; assert(geometry->instData->platform == PLATFORM_OGL); @@ -93,6 +106,180 @@ GetSizeNativeData(void *object, int32, int32) return 4 + header->numAttribs*sizeof(AttribDesc) + header->dataSize; } +static void +packattrib(uint8 *dst, float32 *src, AttribDesc *a) +{ + int8 *i8dst; + uint16 *u16dst; + int16 *i16dst; + + switch(a->type){ + case 0: // float + memcpy(dst, src, a->size*4); + break; + + // TODO: maybe have loop inside if? + case 1: // byte + i8dst = (int8*)dst; + for(int i = 0; i < a->size; i++){ + if(!a->normalized) + i8dst[i] = src[i]; + else if(src[i] > 0.0f) + i8dst[i] = src[i]*127.0f; + else + i8dst[i] = src[i]*128.0f; + } + break; + + case 2: // ubyte + for(int i = 0; i < a->size; i++){ + if(!a->normalized) + dst[i] = src[i]; + else + dst[i] = src[i]*255.0f; + } + break; + + case 3: // short + i16dst = (int16*)dst; + for(int i = 0; i < a->size; i++){ + if(!a->normalized) + i16dst[i] = src[i]; + else if(src[i] > 0.0f) + i16dst[i] = src[i]*32767.0f; + else + i16dst[i] = src[i]*32768.0f; + } + break; + + case 4: // ushort + u16dst = (uint16*)dst; + for(int i = 0; i < a->size; i++){ + if(!a->normalized) + u16dst[i] = src[i]; + else + u16dst[i] = src[i]*65535.0f; + } + break; + } +} + +// TODO: make pipeline dependent (skin data, night colors) +void +Instance(Atomic *atomic) +{ + Geometry *geo = atomic->geometry; + InstanceDataHeader *header = new InstanceDataHeader; + geo->instData = header; + header->platform = PLATFORM_OGL; + header->vbo = 0; + header->ibo = 0; + header->numAttribs = 1 + (geo->numTexCoordSets > 0); + if(geo->geoflags & Geometry::PRELIT) + header->numAttribs++; + if(geo->geoflags & Geometry::NORMALS) + header->numAttribs++; + int32 offset = 0; + header->attribs = new AttribDesc[header->numAttribs]; + + AttribDesc *a = header->attribs; + // Vertices + a->index = 0; + a->type = 0; + a->normalized = 0; + a->size = 3; + a->offset = offset; + offset += 12; + a++; + + // texCoords, only one set here + if(geo->numTexCoordSets){ + a->index = 1; + a->type = 3; + a->normalized = 0; + a->size = 2; + a->offset = offset; + offset += 4; + a++; + } + + if(geo->geoflags & Geometry::NORMALS){ + a->index = 2; + a->type = 1; + a->normalized = 1; + a->size = 3; + a->offset = offset; + offset += 4; + a++; + } + + if(geo->geoflags & Geometry::PRELIT){ + a->index = 3; + a->type = 2; + a->normalized = 1; + a->size = 4; + a->offset = offset; + offset += 4; + a++; + } + // TODO: skin, extra colors; what to do with multiple coords? + + a = header->attribs; + for(int32 i = 0; i < header->numAttribs; i++) + a[i].stride = offset; + + header->dataSize = offset*geo->numVertices; + header->data = new uint8[header->dataSize]; + memset(header->data, 0xFF, header->dataSize); + + uint8 *p = header->data + a->offset; + float32 *vert = geo->morphTargets->vertices; + for(int32 i = 0; i < geo->numVertices; i++){ + packattrib(p, vert, a); + vert += 3; + p += a->stride; + } + a++; + + if(geo->numTexCoordSets){ + p = header->data + a->offset; + float32 *texcoord = geo->texCoords[0]; + for(int32 i = 0; i < geo->numVertices; i++){ + packattrib(p, texcoord, a); + texcoord += 2; + p += a->stride; + } + a++; + } + + if(geo->geoflags & Geometry::NORMALS){ + p = header->data + a->offset; + float32 *norm = geo->morphTargets->normals; + for(int32 i = 0; i < geo->numVertices; i++){ + packattrib(p, norm, a); + norm += 3; + p += a->stride; + } + a++; + } + + if(geo->geoflags & Geometry::PRELIT){ + p = header->data + a->offset; + uint8 *color = geo->colors; + float32 f[4]; + for(int32 i = 0; i < geo->numVertices; i++){ + f[0] = color[0]; + f[1] = color[1]; + f[2] = color[2]; + f[3] = color[3]; + packattrib(p, f, a); + color += 4; + p += a->stride; + } + a++; + } + geo->geoflags |= Geometry::NATIVE; +} #ifdef RW_OPENGL void diff --git a/src/plugins.cpp b/src/plugins.cpp index 097b835..de66520 100644 --- a/src/plugins.cpp +++ b/src/plugins.cpp @@ -290,7 +290,7 @@ struct Breakable }; static void* -destroyBreakableModel(void *object, int32 offset, int32 size) +destroyBreakableModel(void *object, int32 offset, int32) { uint8 *p = *PLUGINOFFSET(uint8*, object, offset); delete[] p; @@ -298,7 +298,7 @@ destroyBreakableModel(void *object, int32 offset, int32 size) } static void -readBreakableModel(istream &stream, int32 len, void *object, int32 o, int32 s) +readBreakableModel(istream &stream, int32, void *object, int32 o, int32) { uint32 header[13]; uint32 hasBreakable = readUInt32(stream); @@ -334,7 +334,7 @@ readBreakableModel(istream &stream, int32 len, void *object, int32 o, int32 s) } static void -writeBreakableModel(ostream &stream, int32 len, void *object, int32 o, int32 s) +writeBreakableModel(ostream &stream, int32, void *object, int32 o, int32) { uint32 header[13]; Breakable *breakable = *PLUGINOFFSET(Breakable*, object, o); @@ -357,7 +357,7 @@ writeBreakableModel(ostream &stream, int32 len, void *object, int32 o, int32 s) } static int32 -getSizeBreakableModel(void *object, int32 offset, int32 size) +getSizeBreakableModel(void *object, int32 offset, int32) { Breakable *breakable = *PLUGINOFFSET(Breakable*, object, offset); if(breakable == NULL) diff --git a/src/rwogl.h b/src/rwogl.h index f1e53a9..9b0918e 100644 --- a/src/rwogl.h +++ b/src/rwogl.h @@ -31,6 +31,9 @@ void ReadNativeData(std::istream &stream, int32 len, void *object, int32, int32) void WriteNativeData(std::ostream &stream, int32 len, void *object, int32, int32); int32 GetSizeNativeData(void *object, int32, int32); +void Instance(Atomic *atomic); + +// only RW_OPENGL void UploadGeo(Geometry *geo); void SetAttribPointers(InstanceDataHeader *inst);