diff --git a/src/geometry.cpp b/src/geometry.cpp index 7db2f16..62c8fc9 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -29,7 +29,7 @@ Geometry::Geometry(int32 numVerts, int32 numTris, uint32 flags) for(int32 i = 0; i < this->numTexCoordSets; i++) this->texCoords[i] = NULL; this->triangles = NULL; - if(!(this->geoflags & NATIVE)){ + if(!(this->geoflags & NATIVE) && this->numVertices){ if(this->geoflags & PRELIT) this->colors = new uint8[4*this->numVertices]; if((this->geoflags & TEXTURED) || (this->geoflags & TEXTURED2)) @@ -42,7 +42,7 @@ Geometry::Geometry(int32 numVerts, int32 numTris, uint32 flags) MorphTarget *m = this->morphTargets; m->vertices = NULL; m->normals = NULL; - if(!(this->geoflags & NATIVE)){ + if(!(this->geoflags & NATIVE) && this->numVertices){ m->vertices = new float32[3*this->numVertices]; if(this->geoflags & NORMALS) m->normals = new float32[3*this->numVertices]; @@ -87,7 +87,7 @@ void Geometry::decRef(void) { this->refCount--; - if(this->refCount) + if(this->refCount == 0) delete this; } @@ -375,16 +375,19 @@ Material::Material(void) Material::Material(Material *m) { - m->color[0] = this->color[0]; - m->color[1] = this->color[1]; - m->color[2] = this->color[2]; - m->color[3] = this->color[3]; - m->surfaceProps[0] = this->surfaceProps[0]; - m->surfaceProps[1] = this->surfaceProps[1]; - m->surfaceProps[2] = this->surfaceProps[2]; - m->texture = this->texture; - if(m->texture) - m->texture->refCount++; + this->color[0] = m->color[0]; + this->color[1] = m->color[1]; + this->color[2] = m->color[2]; + this->color[3] = m->color[3]; + this->surfaceProps[0] = m->surfaceProps[0]; + this->surfaceProps[1] = m->surfaceProps[1]; + this->surfaceProps[2] = m->surfaceProps[2]; + this->texture = m->texture; + if(this->texture) + this->texture->refCount++; + this->pipeline = m->pipeline; + this->refCount = 1; + this->constructPlugins(); this->copyPlugins(m); } @@ -399,7 +402,7 @@ void Material::decRef(void) { this->refCount--; - if(this->refCount) + if(this->refCount == 0) delete this; } @@ -418,6 +421,7 @@ Material::streamRead(Stream *stream) { uint32 length, version; MatStreamData buf; + assert(findChunk(stream, ID_STRUCT, NULL, &version)); stream->read(&buf, sizeof(buf)); Material *mat = new Material; @@ -436,7 +440,6 @@ Material::streamRead(Stream *stream) mat->surfaceProps[1] = surfaceProps[1]; mat->surfaceProps[2] = surfaceProps[2]; } - if(buf.textured){ assert(findChunk(stream, ID_TEXTURE, &length, NULL)); mat->texture = Texture::streamRead(stream); diff --git a/src/gtaplg.cpp b/src/gtaplg.cpp index 61686c5..c43fa3b 100644 --- a/src/gtaplg.cpp +++ b/src/gtaplg.cpp @@ -520,6 +520,8 @@ static void* destroySpecMat(void *object, int32 offset, int32) { SpecMat **specmat = PLUGINOFFSET(SpecMat*, object, offset); + if(*specmat == NULL) + return object; if((*specmat)->texture) (*specmat)->texture->decRef(); delete *specmat; diff --git a/src/image.cpp b/src/image.cpp index 9944428..a47ea0a 100755 --- a/src/image.cpp +++ b/src/image.cpp @@ -112,7 +112,7 @@ void Texture::decRef(void) { this->refCount--; - if(this->refCount) + if(this->refCount == NULL) delete this; } @@ -346,7 +346,7 @@ Image::getFilename(const char *name) char *s, *p = searchPaths; int len = strlen(name)+1; if(numSearchPaths == 0){ - f = fopen(name, "r"); + f = fopen(name, "rb"); if(f){ fclose(f); printf("found %s\n", name); diff --git a/src/mdl.cpp b/src/mdl.cpp index a267c03..b4c3181 100644 --- a/src/mdl.cpp +++ b/src/mdl.cpp @@ -39,7 +39,7 @@ struct RslGeometry { float32 bound[4]; uint32 size; - int32 type; + int32 flags; int32 unknown[4]; float32 scale[3]; float32 pos[3]; @@ -59,24 +59,38 @@ unpackSize(uint32 unpack) return ((unpack>>26 & 3)+1)*size[unpack>>24 & 3]/8; } -void -analyzeData(uint8 *p) +int +analyzeDMA(uint8 *p) { uint32 *w = (uint32*)p; uint32 *end; - end = (uint32*)(p + ((w[0] & 0xFFFF) + 1)*0x10); // TODO: find out real mask - printf("start: %p end: %p\n", w, end); + end = (uint32*)(p + ((w[0] & 0xFFFF) + 1)*0x10); w += 4; + int flags = 0; while(w < end){ if((w[0] & 0x60000000) == 0x60000000){ - printf("UNPACK %x %x\n", w[0], unpackSize(w[0])); +// printf("UNPACK %x %x\n", w[0], unpackSize(w[0])); + printf("UNPACK %x %x %x\n", w[0] & 0x7F004000, w[0], unpackSize(w[0])); + uint32 type = w[0] & 0x7F004000; + if(w[0] != 0x6c018000){ + if(type == 0x79000000) + flags |= 0x1; + if(type == 0x76004000) + flags |= 0x10; + if(type == 0x6a000000) + flags |= 0x100; + if(type == 0x6f000000) + flags |= 0x1000; + if(type == 0x6c000000) + flags |= 0x10000; + } int32 n = (w[0] >> 16) & 0xFF; p = (uint8*)(w+1); - p += n*unpackSize(w[0]); + p += (n*unpackSize(w[0])+3)&~3; w = (uint32*)p; continue; } - switch(w[0] & 0x7FFFFFFF){ + switch(w[0] & 0x7F000000){ case 0x20000000: // STMASK printf("STMASK %x\n", w[1]); w++; @@ -89,6 +103,10 @@ analyzeData(uint8 *p) printf("STCOL %x %x %x %x\n", w[1], w[2], w[3], w[4]); w+=4; break; + case 0x14000000: + printf("MSCAL %x\n", w[0]&0xFFFF); + return flags; + break; case 0: break; default: @@ -97,6 +115,156 @@ analyzeData(uint8 *p) } w++; } + return flags; +} + +uint32* +skipUnpack(uint32 *p) +{ + int32 n = (p[0] >> 16) & 0xFF; + return p + (n*unpackSize(p[0])+3 >> 2) + 1; +} + +void +unpackVertices(RslGeometry *rg, int16 *data, float32 *verts, int32 n) +{ + while(n--){ + verts[0] = data[0]/32768.0f*rg->scale[0] + rg->pos[0]; + verts[1] = data[1]/32768.0f*rg->scale[1] + rg->pos[1]; + verts[2] = data[2]/32768.0f*rg->scale[2] + rg->pos[2]; + verts += 3; + data += 3; + } +} + +void +unpackTex(RslMesh *rm, uint8 *data, float32 *tex, int32 n) +{ + while(n--){ + tex[0] = data[0]/255.0f*rm->uvOff[0]; + tex[1] = data[1]/255.0f*rm->uvOff[1]; + tex += 2; + data += 2; + } +} + +void +unpackNormals(int8 *data, float32 *norms, int32 n) +{ + while(n--){ + norms[0] = data[0]/127.0f; + norms[1] = data[1]/127.0f; + norms[2] = data[2]/127.0f; + norms += 3; + data += 3; + } +} + +void +unpackColors(uint16 *data, uint8 *cols, int32 n) +{ + while(n--){ + cols[0] = (data[0] & 0x1f) * 255 / 0x1F; + cols[1] = (data[0]>>5 & 0x1f) * 255 / 0x1F; + cols[2] = (data[0]>>10 & 0x1f) * 255 / 0x1F; + cols[3] = data[0]&0x80 ? 0xFF : 0; + cols += 4; + data++; + } +} + +void +unpackSkinData(uint32 *data, float32 *weights, uint8 *indices, int32 n) +{ + while(n--){ + for(int j = 0; j < 4; j++){ + ((uint32*)weights)[j] = data[j] & ~0x3FF; + indices[j] = data[j] >> 2; + if(indices[j]) indices[j]--; + if(weights[j] == 0.0f) indices[j] = 0; + } + weights += 4; + indices += 4; + data += 4; + } +} + +void +insertVertices(Geometry *g, RslGeometry *rg, RslMesh *rm) +{ + float32 *verts = &g->morphTargets[0].vertices[g->numVertices*3]; + float32 *norms = &g->morphTargets[0].normals[g->numVertices*3]; + uint8 *cols = &g->colors[g->numVertices*4]; + float32 *texCoords = &g->texCoords[0][g->numVertices*2]; + uint8 *indices = NULL; + float32 *weights = NULL; + Skin *skin = *PLUGINOFFSET(Skin*, g, skinGlobals.offset); + if(skin){ + indices = &skin->indices[g->numVertices*4]; + weights = &skin->weights[g->numVertices*4]; + } + bool first = 1; + + uint8 *p = rg->data + rm->dmaOffset; + uint32 *w = (uint32*)p; + uint32 *end = (uint32*)(p + ((w[0] & 0xFFFF) + 1)*0x10); + w += 4; + int flags = 0; + int32 nvert, n; + while(w < end){ + assert(w[0] == 0x6C018000); // UNPACK + nvert = w[4] & 0x7FFF; + n = first ? nvert : nvert-2; + w += 5; + + // positions + assert(w[0] == 0x20000000); // STMASK + w += 2; + assert(w[0] == 0x30000000); // STROW + w += 5; + assert((w[0] & 0xFF004000) == 0x79000000); + unpackVertices(rg, (int16*)(w+1), verts, nvert); + w = skipUnpack(w); + verts += 3*n; + + // tex coords + assert(w[0] == 0x20000000); // STMASK + w += 2; + assert(w[0] == 0x30000000); // STROW + w += 5; + assert((w[0] & 0xFF004000) == 0x76004000); + unpackTex(rm, (uint8*)(w+1), texCoords, nvert); + w = skipUnpack(w); + texCoords += 2*n; + + if(g->geoflags & Geometry::NORMALS){ + assert((w[0] & 0xFF004000) == 0x6A000000); + unpackNormals((int8*)(w+1), norms, nvert); + w = skipUnpack(w); + norms += 3*n; + } + + if(g->geoflags & Geometry::PRELIT){ + assert((w[0] & 0xFF004000) == 0x6F000000); + unpackColors((uint16*)(w+1), cols, nvert); + w = skipUnpack(w); + cols += 4*n; + } + + if(skin){ + assert((w[0] & 0xFF004000) == 0x6C000000); + unpackSkinData((w+1), weights, indices, nvert); + w = skipUnpack(w); + indices += 4*n; + weights += 4*n; + } + g->numVertices += n; + + assert(w[0] == 0x14000006); + w++; + while(w[0] == 0) w++; + first = 0; + } } void @@ -104,9 +272,59 @@ convertRslGeometry(Geometry *g) { RslGeometry *rg = *PLUGINOFFSET(RslGeometry*, g, rslPluginOffset); assert(rg != NULL); - RslMesh *m = rg->meshes; - for(int32 i = 0; i < rg->numMeshes; i++, m++) - analyzeData(rg->data + m->dmaOffset); + + g->meshHeader = new MeshHeader; + g->meshHeader->flags = 1; + g->meshHeader->numMeshes = rg->numMeshes; + g->meshHeader->mesh = new Mesh[rg->numMeshes]; + g->meshHeader->totalIndices = 0; + int32 nverts = 0; + RslMesh *rm = rg->meshes; + Mesh *m = g->meshHeader->mesh; + for(uint32 i = 0; i < rg->numMeshes; i++, rm++, m++){ + nverts += m->numIndices = rm->numTriangles+2; + m->material = g->materialList[i]; + } + g->geoflags = Geometry::TRISTRIP | + Geometry::POSITIONS | /* 0x01 ? */ + Geometry::TEXTURED; /* 0x04 ? */ + if(rg->flags & 0x2) + g->geoflags |= Geometry::NORMALS; + if(rg->flags & 0x8) + g->geoflags |= Geometry::PRELIT; + g->numTexCoordSets = 1; + + g->numVertices = nverts; + g->meshHeader->totalIndices = nverts; + g->allocateData(); + g->meshHeader->allocateIndices(); + + Skin *skin = *PLUGINOFFSET(Skin*, g, skinGlobals.offset); + if(rg->flags & 0x10) + assert(skin); + if(skin){ + uint8 *data = skin->data; + float *invMats = skin->inverseMatrices; + skin->init(skin->numBones, skin->numBones, g->numVertices); + memcpy(skin->inverseMatrices, invMats, skin->numBones*64); + delete[] data; + } + + uint16 idx = 0; + rm = rg->meshes; + m = g->meshHeader->mesh; + g->numVertices = 0; + for(uint32 i = 0; i < rg->numMeshes; i++, rm++, m++){ + for(uint32 j = 0; j < m->numIndices; j++) + m->indices[j] = idx++; + insertVertices(g, rg, rm); + } + + if(skin){ + skin->findNumWeights(g->numVertices); + skin->findUsedBones(g->numVertices); + } + g->generateTriangles(); } Geometry* @@ -128,14 +346,25 @@ geometryStreamReadRsl(Stream *stream) assert(findChunk(stream, ID_MATLIST, NULL, NULL)); assert(findChunk(stream, ID_STRUCT, NULL, NULL)); - g->numMaterials = stream->readI32(); - g->materialList = new Material*[g->numMaterials]; - stream->seek(g->numMaterials*4); // unused (-1) - for(int32 i = 0; i < g->numMaterials; i++){ + int32 numMaterials = stream->readI32(); + Material **materialList = new Material*[numMaterials]; + stream->seek(numMaterials*4); // unused (-1) + for(int32 i = 0; i < numMaterials; i++){ assert(findChunk(stream, ID_MATERIAL, NULL, NULL)); - g->materialList[i] = Material::streamRead(stream); + materialList[i] = Material::streamRead(stream); } + g->numMaterials = rg->numMeshes; + g->materialList = new Material*[g->numMaterials]; + for(int32 i = 0; i < rg->numMeshes; i++){ + g->materialList[i] = materialList[rg->meshes[i].matID]; + g->materialList[i]->refCount++; + //g->materialList[i] = new Material(materialList[rg->meshes[i].matID]); + } + + for(int32 i = 0; i < numMaterials; i++) + materialList[i]->decRef(); + g->streamReadPlugins(stream); return g; diff --git a/src/plugins.cpp b/src/plugins.cpp index af7db34..06fd692 100644 --- a/src/plugins.cpp +++ b/src/plugins.cpp @@ -882,6 +882,11 @@ readMaterialMatFX(Stream *stream, int32, void *object, int32 offset, int32) *PLUGINOFFSET(MatFX*, object, offset) = matfx; matfx->setEffects(stream->readU32()); + if(matfx->flags == MatFX::BUMPMAP && matFXGlobals.hack){ + stream->seek(12); + return; + } + int32 n = matFXGlobals.hack ? 1 : 2; for(int i = 0; i < n; i++){ uint32 type = stream->readU32(); diff --git a/tools/dffwrite/dffwrite.cpp b/tools/dffwrite/dffwrite.cpp index 2455dca..359a86b 100644 --- a/tools/dffwrite/dffwrite.cpp +++ b/tools/dffwrite/dffwrite.cpp @@ -107,9 +107,9 @@ main(int argc, char *argv[]) out.open(argv[2], "wb"); else out.open("out.dff", "wb"); - if(lcs) - clumpStreamWriteRsl(&out, c); - else +// if(lcs) +// clumpStreamWriteRsl(&out, c); +// else c->streamWrite(&out); out.close(); }