diff --git a/src/graphics/aurora/model_kotor.cpp b/src/graphics/aurora/model_kotor.cpp index 782270a14f..7e8a6529d4 100644 --- a/src/graphics/aurora/model_kotor.cpp +++ b/src/graphics/aurora/model_kotor.cpp @@ -524,40 +524,66 @@ void ModelNode_KotOR::readMesh(Model_KotOR::ParserContext &ctx) { loadTextures(textures); - // Read vertex coordinates - - std::vector vX, vY, vZ; - - vX.resize(vertexCount); - vY.resize(vertexCount); - vZ.resize(vertexCount); - - std::vector< std::vector > tX, tY; - - tX.resize(textureCount); - tY.resize(textureCount); + // Read vertices (interleaved) + + assert(!_vertData); + + GLsizei vpsize = 3; + GLsizei vnsize = 3; + GLsizei vtsize = 2; + _vertSize = (vpsize + vnsize + vtsize * textureCount) * sizeof(float); + _vertCount = vertexCount; + _vertData = std::malloc(_vertCount * _vertSize); + + VertexAttrib vp; + vp.index = VPOSITION; + vp.size = vpsize; + vp.type = GL_FLOAT; + vp.stride = _vertSize; + vp.pointer = (float*) _vertData; + _vertDecl.push_back(vp); + + VertexAttrib vn; + vn.index = VNORMAL; + vn.size = vnsize; + vn.type = GL_FLOAT; + vn.stride = _vertSize; + vn.pointer = (float*) _vertData + vpsize; + _vertDecl.push_back(vn); for (uint16 t = 0; t < textureCount; t++) { - tX[t].resize(vertexCount); - tY[t].resize(vertexCount); + VertexAttrib vt; + vt.index = VTCOORD + t; + vt.size = vtsize; + vt.type = GL_FLOAT; + vt.stride = _vertSize; + vt.pointer = (float*) _vertData + vpsize + vnsize + vtsize * t; + _vertDecl.push_back(vt); } - for (int i = 0; i < vertexCount; i++) { + float *v = (float*) _vertData; + for (uint32 i = 0; i < _vertCount; i++) { + // Position ctx.mdx->seekTo(offNodeData + i * mdxStructSize); + *v++ = ctx.mdx->readIEEEFloatLE(); + *v++ = ctx.mdx->readIEEEFloatLE(); + *v++ = ctx.mdx->readIEEEFloatLE(); - vX[i] = ctx.mdx->readIEEEFloatLE(); - vY[i] = ctx.mdx->readIEEEFloatLE(); - vZ[i] = ctx.mdx->readIEEEFloatLE(); + // Normal + //ctx.mdx->seekTo(offNodeData + i * mdxStructSize + offNormals); + *v++ = ctx.mdx->readIEEEFloatLE(); + *v++ = ctx.mdx->readIEEEFloatLE(); + *v++ = ctx.mdx->readIEEEFloatLE(); + // TexCoords for (uint16 t = 0; t < textureCount; t++) { if (offUV[t] != 0xFFFFFFFF) { ctx.mdx->seekTo(offNodeData + i * mdxStructSize + offUV[t]); - - tX[t][i] = ctx.mdx->readIEEEFloatLE(); - tY[t][i] = ctx.mdx->readIEEEFloatLE(); + *v++ = ctx.mdx->readIEEEFloatLE(); + *v++ = ctx.mdx->readIEEEFloatLE(); } else { - tX[t][i] = 0.0; - tY[t][i] = 0.0; + *v++ = 0.0; + *v++ = 0.0; } } } @@ -565,53 +591,23 @@ void ModelNode_KotOR::readMesh(Model_KotOR::ParserContext &ctx) { // Read faces - if (!createFaces(facesCount)) { - ctx.mdl->seekTo(endPos); - return; - } + assert(!_faceData); + + _faceCount = facesCount; + _faceSize = 3 * sizeof(uint16); + _faceType = GL_UNSIGNED_SHORT; + _faceData = std::malloc(_faceCount * _faceSize); ctx.mdl->seekTo(ctx.offModelData + offOffVerts); uint32 offVerts = ctx.mdl->readUint32LE(); ctx.mdl->seekTo(ctx.offModelData + offVerts); + uint16 *f = (uint16 *)_faceData; + for (uint32 i = 0; i < _faceCount * 3; i++) + f[i] = ctx.mdl->readUint16LE(); - for (uint32 i = 0; i < facesCount; i++) { - // Vertex indices - const uint16 v1 = ctx.mdl->readUint16LE(); - const uint16 v2 = ctx.mdl->readUint16LE(); - const uint16 v3 = ctx.mdl->readUint16LE(); - - // Vertex coordinates - _vX[3 * i + 0] = v1 < vX.size() ? vX[v1] : 0.0; - _vY[3 * i + 0] = v1 < vY.size() ? vY[v1] : 0.0; - _vZ[3 * i + 0] = v1 < vZ.size() ? vZ[v1] : 0.0; - _boundBox.add(_vX[3 * i + 0], _vY[3 * i + 0], _vZ[3 * i + 0]); - - _vX[3 * i + 1] = v2 < vX.size() ? vX[v2] : 0.0; - _vY[3 * i + 1] = v2 < vY.size() ? vY[v2] : 0.0; - _vZ[3 * i + 1] = v2 < vZ.size() ? vZ[v2] : 0.0; - _boundBox.add(_vX[3 * i + 1], _vY[3 * i + 1], _vZ[3 * i + 1]); - - _vX[3 * i + 2] = v3 < vX.size() ? vX[v3] : 0.0; - _vY[3 * i + 2] = v3 < vY.size() ? vY[v3] : 0.0; - _vZ[3 * i + 2] = v3 < vZ.size() ? vZ[v3] : 0.0; - _boundBox.add(_vX[3 * i + 2], _vY[3 * i + 2], _vZ[3 * i + 2]); - - // Texture coordinates - for (uint16 t = 0 ; t < textureCount; t++) { - _tX[3 * textureCount * i + 3 * t + 0] = v1 < tX[t].size() ? tX[t][v1] : 0.0; - _tY[3 * textureCount * i + 3 * t + 0] = v1 < tY[t].size() ? tY[t][v1] : 0.0; - - _tX[3 * textureCount * i + 3 * t + 1] = v2 < tX[t].size() ? tX[t][v2] : 0.0; - _tY[3 * textureCount * i + 3 * t + 1] = v2 < tY[t].size() ? tY[t][v2] : 0.0; - - _tX[3 * textureCount * i + 3 * t + 2] = v3 < tX[t].size() ? tX[t][v3] : 0.0; - _tY[3 * textureCount * i + 3 * t + 2] = v3 < tY[t].size() ? tY[t][v3] : 0.0; - } - } - - createCenter(); + createBound(); ctx.mdl->seekTo(endPos); } diff --git a/src/graphics/aurora/model_nwn.cpp b/src/graphics/aurora/model_nwn.cpp index 549ae8f668..74cf0e5aeb 100644 --- a/src/graphics/aurora/model_nwn.cpp +++ b/src/graphics/aurora/model_nwn.cpp @@ -31,11 +31,14 @@ #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#include + #include "common/error.h" #include "common/maths.h" #include "common/debug.h" #include "common/stream.h" #include "common/streamtokenizer.h" +#include "common/vector3.h" #include "aurora/types.h" #include "aurora/resman.h" @@ -622,6 +625,26 @@ void ModelNode_NWN_Binary::load(Model_NWN::ParserContext &ctx) { } +struct Normal { + uint16 vi; // id of vertex this normal belongs to + float xyz[3]; // vertex normal +}; + +bool operator == (const Normal &a, const Normal &b) { + return a.vi == b.vi; +} + +std::size_t hash_value(const Normal &b) { + boost::hash hasher; + return hasher(b.vi); +} + +bool fuzzy_equal(const float a[3], const float b[3]) { + return fabs(a[0] - b[0]) < 1E-4 && + fabs(a[1] - b[1]) < 1E-4 && + fabs(a[2] - b[2]) < 1E-4; +} + void ModelNode_NWN_Binary::readMesh(Model_NWN::ParserContext &ctx) { ctx.mdl->skip(8); // Function pointers @@ -684,7 +707,7 @@ void ModelNode_NWN_Binary::readMesh(Model_NWN::ParserContext &ctx) { ctx.mdl->skip(8); // Unknown - byte triangleMode = ctx.mdl->readByte(); + byte triangleMode = ctx.mdl->readByte(); // 3 - Triangle, 4 - TriStrip ctx.mdl->skip(3 + 4); // Padding + Unknown @@ -698,10 +721,12 @@ void ModelNode_NWN_Binary::readMesh(Model_NWN::ParserContext &ctx) { textureVertexOffset[2] = ctx.mdl->readUint32LE(); textureVertexOffset[3] = ctx.mdl->readUint32LE(); - ctx.mdl->skip(4); // Vertex normals - ctx.mdl->skip(4); // Vertex RGBA colors + uint32 normalOffset = ctx.mdl->readUint32LE(); // Vertex normals + uint32 colorOffset = ctx.mdl->readUint32LE(); // Vertex RGBA colors - ctx.mdl->skip(6 * 4); // Texture animation data + uint32 textureAnimOffset[6]; // Texture animation data + for (uint32 i = 0; i < 6; i++) + textureAnimOffset[i] = ctx.mdl->readUint32LE(); bool lightMapped = ctx.mdl->readByte() == 1; @@ -729,90 +754,153 @@ void ModelNode_NWN_Binary::readMesh(Model_NWN::ParserContext &ctx) { uint32 endPos = ctx.mdl->pos(); - // Read vertex coordinates - std::vector vX, vY, vZ; - if (vertexOffset != 0xFFFFFFFF) { - ctx.mdl->seekTo(ctx.offRawData + vertexOffset); - vX.resize(vertexCount); - vY.resize(vertexCount); - vZ.resize(vertexCount); + // Read faces - for (uint32 i = 0; i < vertexCount; i++) { - vX[i] = ctx.mdl->readIEEEFloatLE(); - vY[i] = ctx.mdl->readIEEEFloatLE(); - vZ[i] = ctx.mdl->readIEEEFloatLE(); + assert(!_faceData); + + _faceCount = facesCount; + _faceSize = 3 * sizeof(uint16); + _faceType = GL_UNSIGNED_SHORT; + _faceData = std::malloc(_faceCount * _faceSize); + + // NWN stores 1 normal per face + // Convert to one normal per vertex by duplicating vertex data + // for face verts with multiple normals + + std::vector new_verts_norms; + boost::unordered_set verts_norms; + typedef boost::unordered_set::iterator norms_set_it; + + Normal n; + uint16 vertexCountNew = vertexCount; + uint16 *f = (uint16 *)_faceData; + ctx.mdl->seekTo(ctx.offModelData + facesOffset); + for (uint32 i = 0; i < _faceCount; i++) { + // Face normal + n.xyz[0] = ctx.mdl->readIEEEFloatLE(); + n.xyz[1] = ctx.mdl->readIEEEFloatLE(); + n.xyz[2] = ctx.mdl->readIEEEFloatLE(); + + ctx.mdl->skip( 4); // Plane distance + ctx.mdl->skip( 4); // Surface ID / smoothing group ?? + ctx.mdl->skip(3 * 2); // Adjacent face number or -1 + + // Face indices + for (uint32 j = 0; j < 3; j++) { + n.vi = ctx.mdl->readUint16LE(); + assert(n.vi <= vertexCount); + + // check if we have a normal for this vertex already + std::pair it = verts_norms.insert(n); + if (!it.second && !fuzzy_equal(n.xyz, it.first->xyz)) { + new_verts_norms.push_back(n); + n.vi = vertexCountNew++; + } + + *f++ = n.vi; } } + + // Read vertex data + + assert(!_vertData); + + GLsizei vpsize = 3; + GLsizei vnsize = 3; + GLsizei vtsize = 2; + _vertSize = (vpsize + vnsize + vtsize * textureCount) * sizeof(float); + _vertCount = vertexCountNew; + _vertData = std::malloc(_vertCount * _vertSize); + + // Read vertex coordinates + + VertexAttrib vp; + vp.index = VPOSITION; + vp.size = vpsize; + vp.type = GL_FLOAT; + vp.stride = 0; + vp.pointer = (float *) _vertData; + _vertDecl.push_back(vp); + + assert (vertexOffset != 0xFFFFFFFF); + ctx.mdl->seekTo(ctx.offRawData + vertexOffset); + + float *v = (float *) vp.pointer; + for (uint32 i = 0; i < vertexCount; i++) { + *v++ = ctx.mdl->readIEEEFloatLE(); + *v++ = ctx.mdl->readIEEEFloatLE(); + *v++ = ctx.mdl->readIEEEFloatLE(); + } + + // duplicate positions for unique norms + for (uint32 i = 0; i < new_verts_norms.size(); i++) { + uint32 vi = new_verts_norms[i].vi; + float *v0 = (float *) vp.pointer + vi * vpsize; + *v++ = *v0++; + *v++ = *v0++; + *v++ = *v0++; + } + + // Read vertex normals + + VertexAttrib vn; + vn.index = VNORMAL; + vn.size = vnsize; + vn.type = GL_FLOAT; + vn.stride = 0; + vn.pointer = (float *) _vertData + vpsize * _vertCount; + _vertDecl.push_back(vn); + + for (norms_set_it i = verts_norms.begin(); i != verts_norms.end(); i++) { + v = (float *) vn.pointer + i->vi * vnsize; + *v++ = i->xyz[0]; + *v++ = i->xyz[0]; + *v++ = i->xyz[0]; + } + + // additional unique verts norms + v = (float *) vn.pointer + vnsize * vertexCount; + for (uint32 i = 0; i < new_verts_norms.size(); i++) { + *v++ = new_verts_norms[i].xyz[0]; + *v++ = new_verts_norms[i].xyz[1]; + *v++ = new_verts_norms[i].xyz[2]; + } + // Read texture coordinates - std::vector< std::vector > tX, tY; - tX.resize(textureCount); - tY.resize(textureCount); + for (uint16 t = 0; t < textureCount; t++) { - tX[t].resize(vertexCount); - tY[t].resize(vertexCount); + VertexAttrib vt; + vt.index = VTCOORD + t; + vt.size = vtsize; + vt.type = GL_FLOAT; + vt.stride = 0; + vt.pointer = (float *) _vertData + (vpsize + vnsize + vtsize * t) * _vertCount; + _vertDecl.push_back(vt); bool hasTexture = textureVertexOffset[t] != 0xFFFFFFFF; if (hasTexture) ctx.mdl->seekTo(ctx.offRawData + textureVertexOffset[t]); + v = (float *) vt.pointer; for (uint32 i = 0; i < vertexCount; i++) { - tX[t][i] = hasTexture ? ctx.mdl->readIEEEFloatLE() : 0.0; - tY[t][i] = hasTexture ? ctx.mdl->readIEEEFloatLE() : 0.0; + *v++ = hasTexture ? ctx.mdl->readIEEEFloatLE() : 0.0; + *v++ = hasTexture ? ctx.mdl->readIEEEFloatLE() : 0.0; } - } - - // Read faces - if (!createFaces(facesCount)) { - ctx.mdl->seekTo(endPos); - return; - } - - ctx.mdl->seekTo(ctx.offModelData + facesOffset); - for (uint32 i = 0; i < facesCount; i++) { - ctx.mdl->skip(3 * 4); // Normal - ctx.mdl->skip( 4); // Distance - ctx.mdl->skip( 4); // ID - ctx.mdl->skip(3 * 2); // Adjacent face number - - // Vertex indices - const uint16 v1 = ctx.mdl->readUint16LE(); - const uint16 v2 = ctx.mdl->readUint16LE(); - const uint16 v3 = ctx.mdl->readUint16LE(); - - // Vertex coordinates - _vX[3 * i + 0] = v1 < vX.size() ? vX[v1] : 0.0; - _vY[3 * i + 0] = v1 < vY.size() ? vY[v1] : 0.0; - _vZ[3 * i + 0] = v1 < vZ.size() ? vZ[v1] : 0.0; - _boundBox.add(_vX[3 * i + 0], _vY[3 * i + 0], _vZ[3 * i + 0]); - - _vX[3 * i + 1] = v2 < vX.size() ? vX[v2] : 0.0; - _vY[3 * i + 1] = v2 < vY.size() ? vY[v2] : 0.0; - _vZ[3 * i + 1] = v2 < vZ.size() ? vZ[v2] : 0.0; - _boundBox.add(_vX[3 * i + 1], _vY[3 * i + 1], _vZ[3 * i + 1]); - - _vX[3 * i + 2] = v3 < vX.size() ? vX[v3] : 0.0; - _vY[3 * i + 2] = v3 < vY.size() ? vY[v3] : 0.0; - _vZ[3 * i + 2] = v3 < vZ.size() ? vZ[v3] : 0.0; - _boundBox.add(_vX[3 * i + 2], _vY[3 * i + 2], _vZ[3 * i + 2]); - - // Texture coordinates - for (uint32 t = 0; t < textureCount; t++) { - _tX[3 * textureCount * i + 3 * t + 0] = v1 < tX[t].size() ? tX[t][v1] : 0.0; - _tY[3 * textureCount * i + 3 * t + 0] = v1 < tY[t].size() ? tY[t][v1] : 0.0; - - _tX[3 * textureCount * i + 3 * t + 1] = v2 < tX[t].size() ? tX[t][v2] : 0.0; - _tY[3 * textureCount * i + 3 * t + 1] = v2 < tY[t].size() ? tY[t][v2] : 0.0; - - _tX[3 * textureCount * i + 3 * t + 2] = v3 < tX[t].size() ? tX[t][v3] : 0.0; - _tY[3 * textureCount * i + 3 * t + 2] = v3 < tY[t].size() ? tY[t][v3] : 0.0; + // duplicate tcoords for unique norms + for (uint32 i = 0; i < new_verts_norms.size(); i++) { + uint32 vi = new_verts_norms[i].vi; + float *v0 = (float *) vt.pointer + vi * vtsize; + *v++ = *v0++; + *v++ = *v0++; } - } - createCenter(); + assert((byte *) v == (byte *) _vertData + _vertCount * _vertSize); + + createBound(); ctx.mdl->seekTo(endPos); } @@ -1160,55 +1248,144 @@ void ModelNode_NWN_ASCII::readFaces(Model_NWN::ParserContext &ctx, Mesh &mesh) { } } +typedef Common::Vector3 Vec3; + +struct FaceVert { + uint32 p, t; // position, texture coord indices + uint32 i; // unique vertex id + Vec3 n; // normal vector +}; + +bool operator == (const FaceVert &a, const FaceVert &b) { + return (a.p == b.p) && (a.t == b.t) && fuzzy_equal(&a.n[0], &b.n[0]); +} + +std::size_t hash_value(const FaceVert &b) { + std::size_t seed = 0; + boost::hash_combine(seed, b.p); + boost::hash_combine(seed, b.t); + boost::hash_combine(seed, uint32(b.n[0] * 1E4)); + boost::hash_combine(seed, uint32(b.n[1] * 1E4)); + boost::hash_combine(seed, uint32(b.n[2] * 1E4)); + return seed; +} + void ModelNode_NWN_ASCII::processMesh(Mesh &mesh) { - loadTextures(mesh.textures); - if (!createFaces(mesh.faceCount)) + if ((mesh.vCount == 0) || (mesh.tCount == 0) || (mesh.faceCount == 0)) return; + loadTextures(mesh.textures); + const uint32 textureCount = mesh.textures.size(); if (textureCount > 1) warning("ModelNode_NWN_ASCII::processMesh(): textureCount == %d", textureCount); - for (uint32 i = 0; i < mesh.faceCount; i++) { - const uint32 v1 = mesh.vIA[i]; - const uint32 v2 = mesh.vIB[i]; - const uint32 v3 = mesh.vIC[i]; - - // Vertex coordinates - _vX[3 * i + 0] = v1 < mesh.vCount ? mesh.vX[v1] : 0.0; - _vY[3 * i + 0] = v1 < mesh.vCount ? mesh.vY[v1] : 0.0; - _vZ[3 * i + 0] = v1 < mesh.vCount ? mesh.vZ[v1] : 0.0; - _boundBox.add(_vX[3 * i + 0], _vY[3 * i + 0], _vZ[3 * i + 0]); - - _vX[3 * i + 1] = v2 < mesh.vCount ? mesh.vX[v2] : 0.0; - _vY[3 * i + 1] = v2 < mesh.vCount ? mesh.vY[v2] : 0.0; - _vZ[3 * i + 1] = v2 < mesh.vCount ? mesh.vZ[v2] : 0.0; - _boundBox.add(_vX[3 * i + 1], _vY[3 * i + 1], _vZ[3 * i + 1]); - - _vX[3 * i + 2] = v3 < mesh.vCount ? mesh.vX[v3] : 0.0; - _vY[3 * i + 2] = v3 < mesh.vCount ? mesh.vY[v3] : 0.0; - _vZ[3 * i + 2] = v3 < mesh.vCount ? mesh.vZ[v3] : 0.0; - _boundBox.add(_vX[3 * i + 2], _vY[3 * i + 2], _vZ[3 * i + 2]); - - const uint32 t1 = mesh.tIA[i]; - const uint32 t2 = mesh.tIB[i]; - const uint32 t3 = mesh.tIC[i]; - - // Texture coordinates - for (uint32 t = 0; t < textureCount; t++) { - _tX[3 * textureCount * i + 3 * t + 0] = t1 < mesh.tCount ? mesh.tX[t1] : 0.0; - _tY[3 * textureCount * i + 3 * t + 0] = t1 < mesh.tCount ? mesh.tY[t1] : 0.0; - - _tX[3 * textureCount * i + 3 * t + 1] = t2 < mesh.tCount ? mesh.tX[t2] : 0.0; - _tY[3 * textureCount * i + 3 * t + 1] = t2 < mesh.tCount ? mesh.tY[t2] : 0.0; - - _tX[3 * textureCount * i + 3 * t + 2] = t3 < mesh.tCount ? mesh.tX[t3] : 0.0; - _tY[3 * textureCount * i + 3 * t + 2] = t3 < mesh.tCount ? mesh.tY[t3] : 0.0; + + // Read faces + + assert(!_faceData); + + _faceCount = mesh.faceCount; + _faceSize = 3 * sizeof(uint32); + _faceType = GL_UNSIGNED_INT; + _faceData = std::malloc(_faceCount * _faceSize); + + boost::unordered_set verts; + typedef boost::unordered_set::iterator verts_set_it; + + uint32 vertexCount = 0; + uint32 *f = (uint32 *) _faceData; + for (uint32 i = 0; i < _faceCount; i++) { + const uint32 v[3] = {mesh.vIA[i], mesh.vIB[i], mesh.vIC[i]}; + const uint32 t[3] = {mesh.tIA[i], mesh.tIB[i], mesh.tIC[i]}; + + // Face normal + const Vec3 p1(mesh.vX[v[0]], mesh.vY[v[0]], mesh.vZ[v[0]]); + const Vec3 p2(mesh.vX[v[1]], mesh.vY[v[1]], mesh.vZ[v[1]]); + const Vec3 p3(mesh.vX[v[2]], mesh.vY[v[2]], mesh.vZ[v[2]]); + const Vec3 n = (p2 - p1).cross(p3 - p2).norm(); + + for (uint32 j = 0; j < 3; j++) { + FaceVert fv; + fv.i = vertexCount; + fv.p = v[j]; + fv.t = t[j]; + fv.n = n; + + std::pair it = verts.insert(fv); + if (it.second) + vertexCount++; + + *f++ = it.first->i; } + } + + + // Read vertices (interleaved) + assert(!_vertData); + + GLsizei vpsize = 3; + GLsizei vnsize = 3; + GLsizei vtsize = 2; + _vertSize = (vpsize + vnsize + vtsize * textureCount) * sizeof(float); + _vertCount = vertexCount; + _vertData = std::malloc(_vertCount * _vertSize); + + VertexAttrib vp; + vp.index = VPOSITION; + vp.size = vpsize; + vp.type = GL_FLOAT; + vp.stride = _vertSize; + vp.pointer = (float*) _vertData; + _vertDecl.push_back(vp); + + VertexAttrib vn; + vn.index = VNORMAL; + vn.size = vnsize; + vn.type = GL_FLOAT; + vn.stride = _vertSize; + vn.pointer = (float*) _vertData + vpsize; + _vertDecl.push_back(vn); + + for (uint16 t = 0; t < textureCount; t++) { + VertexAttrib vt; + vt.index = VTCOORD + t; + vt.size = vtsize; + vt.type = GL_FLOAT; + vt.stride = _vertSize; + vt.pointer = (float*) _vertData + vpsize + vnsize + vtsize * t; + _vertDecl.push_back(vt); + } + + for (verts_set_it i = verts.begin(); i != verts.end(); i++) { + float *v = (float*) _vertData + i->i * _vertSize / sizeof(float); + + // Position + *v++ = mesh.vX[i->p]; + *v++ = mesh.vY[i->p]; + *v++ = mesh.vZ[i->p]; + + // Normal + *v++ = i->n[0]; + *v++ = i->n[1]; + *v++ = i->n[2]; + + // TexCoord + if (i->t < mesh.tCount) { + *v++ = mesh.tX[i->t]; + *v++ = mesh.tY[i->t]; + } else { + *v++ = 0.0; + *v++ = 0.0; + } + for (uint16 t = 1; t < textureCount; t++) { + *v++ = 0.0; + *v++ = 0.0; + } } - createCenter(); + createBound(); } } // End of namespace Aurora diff --git a/src/graphics/aurora/model_nwn2.cpp b/src/graphics/aurora/model_nwn2.cpp index ae3ee4a224..090fea979a 100644 --- a/src/graphics/aurora/model_nwn2.cpp +++ b/src/graphics/aurora/model_nwn2.cpp @@ -203,78 +203,79 @@ bool ModelNode_NWN2::loadRigid(Model_NWN2::ParserContext &ctx) { std::vector textures; textures.push_back(diffuseMap); - uint32 textureCount = textures.size(); - - loadTextures(textures); - if (!createFaces(faceCount)) - return false; - - - // Read vertex coordinates - - std::vector vX, vY, vZ; - vX.resize(vertexCount); - vY.resize(vertexCount); - vZ.resize(vertexCount); - - std::vector tX, tY, tZ; - tX.resize(vertexCount); - tY.resize(vertexCount); - tZ.resize(vertexCount); + // Read vertices (interleaved) + + assert(!_vertData); + + GLsizei vpsize = 3; + GLsizei vnsize = 3; + GLsizei vtsize = 2; + _vertSize = (vpsize + vnsize + vtsize) * sizeof(float); + _vertCount = vertexCount; + _vertData = std::malloc(_vertCount * _vertSize); + + VertexAttrib vp; + vp.index = VPOSITION; + vp.size = vpsize; + vp.type = GL_FLOAT; + vp.stride = _vertSize; + vp.pointer = (float*) _vertData; + _vertDecl.push_back(vp); + + VertexAttrib vn; + vn.index = VNORMAL; + vn.size = vnsize; + vn.type = GL_FLOAT; + vn.stride = _vertSize; + vn.pointer = (float*) _vertData + vpsize; + _vertDecl.push_back(vn); + + VertexAttrib vt; + vt.index = VTCOORD; + vt.size = vtsize; + vt.type = GL_FLOAT; + vt.stride = _vertSize; + vt.pointer = (float*) _vertData + vpsize + vnsize + vtsize; + _vertDecl.push_back(vt); + + float *v = (float *) _vertData; for (uint32 i = 0; i < vertexCount; i++) { - vX[i] = ctx.mdb->readIEEEFloatLE(); - vY[i] = ctx.mdb->readIEEEFloatLE(); - vZ[i] = ctx.mdb->readIEEEFloatLE(); - - ctx.mdb->skip(3 * 4); // Normals - ctx.mdb->skip(3 * 4); // Tangents - ctx.mdb->skip(3 * 4); // Binormals - - tX[i] = ctx.mdb->readIEEEFloatLE(); - tY[i] = ctx.mdb->readIEEEFloatLE(); - tZ[i] = ctx.mdb->readIEEEFloatLE(); + // Position + *v++ = ctx.mdb->readIEEEFloatLE(); + *v++ = ctx.mdb->readIEEEFloatLE(); + *v++ = ctx.mdb->readIEEEFloatLE(); + + // Normal + *v++ = ctx.mdb->readIEEEFloatLE(); + *v++ = ctx.mdb->readIEEEFloatLE(); + *v++ = ctx.mdb->readIEEEFloatLE(); + + ctx.mdb->skip(3 * 4); // Tangent + ctx.mdb->skip(3 * 4); // Binormal + + // Texture Coords + *v++ = ctx.mdb->readIEEEFloatLE(); + *v++ = ctx.mdb->readIEEEFloatLE(); + //*v++ = ctx.mdb->readIEEEFloatLE(); + ctx.mdb->skip(4); // Third tcoord component } // Read faces - for (uint32 i = 0; i < faceCount; i++) { - const uint16 v1 = ctx.mdb->readUint16LE(); - const uint16 v2 = ctx.mdb->readUint16LE(); - const uint16 v3 = ctx.mdb->readUint16LE(); + assert(!_faceData); - // Vertex coordinates - _vX[3 * i + 0] = v1 < vX.size() ? vX[v1] : 0.0; - _vY[3 * i + 0] = v1 < vY.size() ? vY[v1] : 0.0; - _vZ[3 * i + 0] = v1 < vZ.size() ? vZ[v1] : 0.0; - _boundBox.add(_vX[3 * i + 0], _vY[3 * i + 0], _vZ[3 * i + 0]); + _faceCount = faceCount; + _faceSize = 3 * sizeof(uint16); + _faceType = GL_UNSIGNED_SHORT; + _faceData = std::malloc(_faceCount * _faceSize); - _vX[3 * i + 1] = v2 < vX.size() ? vX[v2] : 0.0; - _vY[3 * i + 1] = v2 < vY.size() ? vY[v2] : 0.0; - _vZ[3 * i + 1] = v2 < vZ.size() ? vZ[v2] : 0.0; - _boundBox.add(_vX[3 * i + 1], _vY[3 * i + 1], _vZ[3 * i + 1]); + uint16 *f = (uint16 *) _faceData; + for (uint32 i = 0; i < _faceCount * 3; i++) + f[i] = ctx.mdb->readUint16LE(); - _vX[3 * i + 2] = v3 < vX.size() ? vX[v3] : 0.0; - _vY[3 * i + 2] = v3 < vY.size() ? vY[v3] : 0.0; - _vZ[3 * i + 2] = v3 < vZ.size() ? vZ[v3] : 0.0; - _boundBox.add(_vX[3 * i + 2], _vY[3 * i + 2], _vZ[3 * i + 2]); - - // Texture coordinates - for (uint32 t = 0; t < textureCount; t++) { - _tX[3 * textureCount * i + 3 * t + 0] = v1 < tX.size() ? tX[v1] : 0.0; - _tY[3 * textureCount * i + 3 * t + 0] = v1 < tY.size() ? tY[v1] : 0.0; - - _tX[3 * textureCount * i + 3 * t + 1] = v2 < tX.size() ? tX[v2] : 0.0; - _tY[3 * textureCount * i + 3 * t + 1] = v2 < tY.size() ? tY[v2] : 0.0; - - _tX[3 * textureCount * i + 3 * t + 2] = v3 < tX.size() ? tX[v3] : 0.0; - _tY[3 * textureCount * i + 3 * t + 2] = v3 < tY.size() ? tY[v3] : 0.0; - } - - } - - createCenter(); + createBound(); _render = true; @@ -322,41 +323,64 @@ bool ModelNode_NWN2::loadSkin(Model_NWN2::ParserContext &ctx) { std::vector textures; textures.push_back(diffuseMap); - uint32 textureCount = textures.size(); - loadTextures(textures); - if (!createFaces(faceCount)) - return false; - - - // Read vertex coordinates - - std::vector vX, vY, vZ; - vX.resize(vertexCount); - vY.resize(vertexCount); - vZ.resize(vertexCount); - - std::vector tX, tY, tZ; - tX.resize(vertexCount); - tY.resize(vertexCount); - tZ.resize(vertexCount); - - for (uint32 i = 0; i < vertexCount; i++) { - vX[i] = ctx.mdb->readIEEEFloatLE(); - vY[i] = ctx.mdb->readIEEEFloatLE(); - vZ[i] = ctx.mdb->readIEEEFloatLE(); - - ctx.mdb->skip(3 * 4); // Normals + // Read vertices (interleaved) + + assert(!_vertData); + + GLsizei vpsize = 3; + GLsizei vnsize = 3; + GLsizei vtsize = 2; + _vertSize = (vpsize + vnsize + vtsize) * sizeof(float); + _vertCount = vertexCount; + _vertData = std::malloc(_vertCount * _vertSize); + + VertexAttrib vp; + vp.index = VPOSITION; + vp.size = vpsize; + vp.type = GL_FLOAT; + vp.stride = _vertSize; + vp.pointer = (float*) _vertData; + _vertDecl.push_back(vp); + + VertexAttrib vn; + vn.index = VNORMAL; + vn.size = vnsize; + vn.type = GL_FLOAT; + vn.stride = _vertSize; + vn.pointer = (float*) _vertData + vpsize; + _vertDecl.push_back(vn); + + VertexAttrib vt; + vt.index = VTCOORD; + vt.size = vtsize; + vt.type = GL_FLOAT; + vt.stride = _vertSize; + vt.pointer = (float*) _vertData + vpsize + vnsize + vtsize; + _vertDecl.push_back(vt); + + float *v = (float *) _vertData; + for (uint32 i = 0; i < _vertCount; i++) { + // Position + *v++ = ctx.mdb->readIEEEFloatLE(); + *v++ = ctx.mdb->readIEEEFloatLE(); + *v++ = ctx.mdb->readIEEEFloatLE(); + + // Normal + *v++ = ctx.mdb->readIEEEFloatLE(); + *v++ = ctx.mdb->readIEEEFloatLE(); + *v++ = ctx.mdb->readIEEEFloatLE(); ctx.mdb->skip(4 * 4); // Bone weights ctx.mdb->skip(4 * 1); // Bone indices + ctx.mdb->skip(3 * 4); // Tangent + ctx.mdb->skip(3 * 4); // Binormal - ctx.mdb->skip(3 * 4); // Tangents - ctx.mdb->skip(3 * 4); // Binormals - - tX[i] = ctx.mdb->readIEEEFloatLE(); - tY[i] = ctx.mdb->readIEEEFloatLE(); - tZ[i] = ctx.mdb->readIEEEFloatLE(); + // TexCoords + *v++ = ctx.mdb->readIEEEFloatLE(); + *v++ = ctx.mdb->readIEEEFloatLE(); + //*v++ = ctx.mdb->readIEEEFloatLE(); + ctx.mdb->skip(4); // Third tcoord component ctx.mdb->skip(4); // Bone count } @@ -364,42 +388,18 @@ bool ModelNode_NWN2::loadSkin(Model_NWN2::ParserContext &ctx) { // Read faces - for (uint32 i = 0; i < faceCount; i++) { - const uint16 v1 = ctx.mdb->readUint16LE(); - const uint16 v2 = ctx.mdb->readUint16LE(); - const uint16 v3 = ctx.mdb->readUint16LE(); - - // Vertex coordinates - _vX[3 * i + 0] = v1 < vX.size() ? vX[v1] : 0.0; - _vY[3 * i + 0] = v1 < vY.size() ? vY[v1] : 0.0; - _vZ[3 * i + 0] = v1 < vZ.size() ? vZ[v1] : 0.0; - _boundBox.add(_vX[3 * i + 0], _vY[3 * i + 0], _vZ[3 * i + 0]); - - _vX[3 * i + 1] = v2 < vX.size() ? vX[v2] : 0.0; - _vY[3 * i + 1] = v2 < vY.size() ? vY[v2] : 0.0; - _vZ[3 * i + 1] = v2 < vZ.size() ? vZ[v2] : 0.0; - _boundBox.add(_vX[3 * i + 1], _vY[3 * i + 1], _vZ[3 * i + 1]); - - _vX[3 * i + 2] = v3 < vX.size() ? vX[v3] : 0.0; - _vY[3 * i + 2] = v3 < vY.size() ? vY[v3] : 0.0; - _vZ[3 * i + 2] = v3 < vZ.size() ? vZ[v3] : 0.0; - _boundBox.add(_vX[3 * i + 2], _vY[3 * i + 2], _vZ[3 * i + 2]); + assert(!_faceData); - // Texture coordinates - for (uint32 t = 0; t < textureCount; t++) { - _tX[3 * textureCount * i + 3 * t + 0] = v1 < tX.size() ? tX[v1] : 0.0; - _tY[3 * textureCount * i + 3 * t + 0] = v1 < tY.size() ? tY[v1] : 0.0; + _faceCount = faceCount; + _faceSize = 3 * sizeof(uint16); + _faceType = GL_UNSIGNED_SHORT; + _faceData = std::malloc(_faceCount * _faceSize); - _tX[3 * textureCount * i + 3 * t + 1] = v2 < tX.size() ? tX[v2] : 0.0; - _tY[3 * textureCount * i + 3 * t + 1] = v2 < tY.size() ? tY[v2] : 0.0; - - _tX[3 * textureCount * i + 3 * t + 2] = v3 < tX.size() ? tX[v3] : 0.0; - _tY[3 * textureCount * i + 3 * t + 2] = v3 < tY.size() ? tY[v3] : 0.0; - } - - } + uint16 *f = (uint16 *) _faceData; + for (uint32 i = 0; i < _faceCount * 3; i++) + f[i] = ctx.mdb->readUint16LE(); - createCenter(); + createBound(); _render = true; diff --git a/src/graphics/aurora/model_witcher.cpp b/src/graphics/aurora/model_witcher.cpp index 8dadc379c9..1512a0f5ea 100644 --- a/src/graphics/aurora/model_witcher.cpp +++ b/src/graphics/aurora/model_witcher.cpp @@ -390,100 +390,98 @@ void ModelNode_Witcher::readMesh(Model_Witcher::ParserContext &ctx) { readTextures(ctx, texture[0], textures); loadTextures(textures); - uint32 textureCount = textures.size(); - if (!createFaces(facesCount)) { - ctx.mdb->seekTo(endPos); - return; - } - - - - // Read vertex coordinates + // Read vertices + + assert(!_vertData); + + GLsizei vpsize = 3; + GLsizei vnsize = 3; + GLsizei vtsize = 2; + _vertSize = (vpsize + vnsize + vtsize) * sizeof(float); + _vertCount = verticesCount; + _vertData = std::malloc(_vertCount * _vertSize); + + VertexAttrib vp; + vp.index = VPOSITION; + vp.size = vpsize; + vp.type = GL_FLOAT; + vp.stride = 0; + vp.pointer = (float*) _vertData; + _vertDecl.push_back(vp); + + VertexAttrib vn; + vn.index = VNORMAL; + vn.size = vnsize; + vn.type = GL_FLOAT; + vn.stride = 0; + vn.pointer = (float*) _vertData + vpsize * _vertCount; + _vertDecl.push_back(vn); + + VertexAttrib vt; + vt.index = VTCOORD; + vt.size = vtsize; + vt.type = GL_FLOAT; + vt.stride = 0; + vt.pointer = (float*) _vertData + (vpsize + vnsize) * _vertCount; + _vertDecl.push_back(vt); + + // Read vertex position ctx.mdb->seekTo(ctx.offRawData + verticesOffset); - - std::vector vX, vY, vZ; - vX.resize(verticesCount); - vY.resize(verticesCount); - vZ.resize(verticesCount); - + float *v = (float *) vp.pointer; for (uint32 i = 0; i < verticesCount; i++) { - vX[i] = ctx.mdb->readIEEEFloatLE(); - vY[i] = ctx.mdb->readIEEEFloatLE(); - vZ[i] = ctx.mdb->readIEEEFloatLE(); + *v++ = ctx.mdb->readIEEEFloatLE(); + *v++ = ctx.mdb->readIEEEFloatLE(); + *v++ = ctx.mdb->readIEEEFloatLE(); } + // Read vertex normals + assert(normalsCount == verticesCount); + ctx.mdb->seekTo(ctx.offRawData + normalsOffset); + v = (float *) vn.pointer; + for (uint32 i = 0; i < normalsCount; i++) { + *v++ = ctx.mdb->readIEEEFloatLE(); + *v++ = ctx.mdb->readIEEEFloatLE(); + *v++ = ctx.mdb->readIEEEFloatLE(); + } // Read texture coordinates - + assert(tVerts0Count == verticesCount); ctx.mdb->seekTo(ctx.offRawData + tVerts0Offset); - - std::vector tX, tY; - tX.resize(tVerts0Count); - tY.resize(tVerts0Count); - + v = (float *) vt.pointer; for (uint32 i = 0; i < tVerts0Count; i++) { - tX[i] = ctx.mdb->readIEEEFloatLE(); - tY[i] = ctx.mdb->readIEEEFloatLE(); + *v++ = ctx.mdb->readIEEEFloatLE(); + *v++ = ctx.mdb->readIEEEFloatLE(); } // Read faces - ctx.mdb->seekTo(ctx.offRawData + facesOffset); + assert(!_faceData); - for (uint32 i = 0; i < facesCount; i++) { + _faceCount = facesCount; + _faceSize = 3 * sizeof(uint32); + _faceType = GL_UNSIGNED_INT; + _faceData = std::malloc(_faceCount * _faceSize); + + ctx.mdb->seekTo(ctx.offRawData + facesOffset); + uint32 *f = (uint32 *) _faceData; + for (uint32 i = 0; i < _faceCount; i++) { ctx.mdb->skip(4 * 4 + 4); if (ctx.fileVersion == 133) ctx.mdb->skip(3 * 4); // Vertex indices - const uint32 v1 = ctx.mdb->readUint32LE(); - const uint32 v2 = ctx.mdb->readUint32LE(); - const uint32 v3 = ctx.mdb->readUint32LE(); - - // Vertex coordinates - _vX[3 * i + 0] = v1 < vX.size() ? vX[v1] : 0.0; - _vY[3 * i + 0] = v1 < vY.size() ? vY[v1] : 0.0; - _vZ[3 * i + 0] = v1 < vZ.size() ? vZ[v1] : 0.0; - _boundBox.add(_vX[3 * i + 0], _vY[3 * i + 0], _vZ[3 * i + 0]); - - _vX[3 * i + 1] = v2 < vX.size() ? vX[v2] : 0.0; - _vY[3 * i + 1] = v2 < vY.size() ? vY[v2] : 0.0; - _vZ[3 * i + 1] = v2 < vZ.size() ? vZ[v2] : 0.0; - _boundBox.add(_vX[3 * i + 1], _vY[3 * i + 1], _vZ[3 * i + 1]); - - _vX[3 * i + 2] = v3 < vX.size() ? vX[v3] : 0.0; - _vY[3 * i + 2] = v3 < vY.size() ? vY[v3] : 0.0; - _vZ[3 * i + 2] = v3 < vZ.size() ? vZ[v3] : 0.0; - _boundBox.add(_vX[3 * i + 2], _vY[3 * i + 2], _vZ[3 * i + 2]); - - const float tX1 = v1 < tX.size() ? tX[v1] : 0.0; - const float tY1 = v1 < tY.size() ? tY[v1] : 0.0; - - const float tX2 = v2 < tX.size() ? tX[v2] : 0.0; - const float tY2 = v2 < tY.size() ? tY[v2] : 0.0; - - const float tX3 = v3 < tX.size() ? tX[v3] : 0.0; - const float tY3 = v3 < tY.size() ? tY[v3] : 0.0; - - for (uint32 t = 0; t < textureCount; t++) { - _tX[3 * textureCount * i + 3 * t + 0] = tX1; - _tY[3 * textureCount * i + 3 * t + 0] = tY1; - - _tX[3 * textureCount * i + 3 * t + 1] = tX2; - _tY[3 * textureCount * i + 3 * t + 1] = tY2; - - _tX[3 * textureCount * i + 3 * t + 2] = tX3; - _tY[3 * textureCount * i + 3 * t + 2] = tY3; - } + *f++ = ctx.mdb->readUint32LE(); + *f++ = ctx.mdb->readUint32LE(); + *f++ = ctx.mdb->readUint32LE(); if (ctx.fileVersion == 133) ctx.mdb->skip(4); } - createCenter(); + createBound(); ctx.mdb->seekTo(endPos); } diff --git a/src/graphics/aurora/modelnode.cpp b/src/graphics/aurora/modelnode.cpp index a277c9d70b..b1be791a1f 100644 --- a/src/graphics/aurora/modelnode.cpp +++ b/src/graphics/aurora/modelnode.cpp @@ -47,11 +47,74 @@ static bool nodeComp(ModelNode *a, ModelNode *b) { return a->isInFrontOf(*b); } +// OpenGL < 2 vertex attribute helper functions + +static void EnableVertexPos(const VertexAttrib & va) { + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(va.size, va.type, va.stride, va.pointer); +} + +static void EnableVertexNorm(const VertexAttrib & va) { + assert(va.size == 3); + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(va.type, va.stride, va.pointer); +} + +static void EnableVertexCol(const VertexAttrib & va) { + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(va.size, va.type, va.stride, va.pointer); +} + +static void EnableVertexTex(const VertexAttrib & va) { + glClientActiveTexture(GL_TEXTURE0 + va.index - VTCOORD); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(va.size, va.type, va.stride, va.pointer); +} + +static void DisableVertexPos(const VertexAttrib & va) { + glDisableClientState(GL_VERTEX_ARRAY); +} + +static void DisableVertexNorm(const VertexAttrib & va) { + glDisableClientState(GL_NORMAL_ARRAY); +} + +static void DisableVertexCol(const VertexAttrib & va) { + glDisableClientState(GL_COLOR_ARRAY); +} + +static void DisableVertexTex(const VertexAttrib & va) { + glClientActiveTexture(GL_TEXTURE0 + va.index - VTCOORD); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); +} + +static void EnableVertexAttrib(const VertexAttrib & va) { + if (va.index == VPOSITION) + EnableVertexPos(va); + else if (va.index == VNORMAL) + EnableVertexNorm(va); + else if (va.index == VCOLOR) + EnableVertexCol(va); + else if (va.index >= VTCOORD) + EnableVertexTex(va); +} + +static void DisableVertexAttrib(const VertexAttrib & va) { + if (va.index == VPOSITION) + DisableVertexPos(va); + else if (va.index == VNORMAL) + DisableVertexNorm(va); + else if (va.index == VCOLOR) + DisableVertexCol(va); + else if (va.index >= VTCOORD) + DisableVertexTex(va); +} ModelNode::ModelNode(Model &model) : _model(&model), _parent(0), _level(0), - _faceCount(0), _coords(0), _smoothGroups(0), _material(0), _isTransparent(false), - _render(false), _hasTransparencyHint(false) { + _vertCount(0), _vertSize(0), _vertData(0), + _faceCount(0), _faceSize(0), _faceType(0), _faceData(0), + _isTransparent(false), _render(false), _hasTransparencyHint(false) { _position[0] = 0.0; _position[1] = 0.0; _position[2] = 0.0; _rotation[0] = 0.0; _rotation[1] = 0.0; _rotation[2] = 0.0; @@ -63,9 +126,8 @@ ModelNode::ModelNode(Model &model) : } ModelNode::~ModelNode() { - delete[] _material; - delete[] _smoothGroups; - delete[] _coords; + std::free(_vertData); + std::free(_faceData); } ModelNode *ModelNode::getParent() { @@ -200,21 +262,28 @@ void ModelNode::inheritOrientation(ModelNode &node) const { } void ModelNode::inheritGeometry(ModelNode &node) const { + assert(!node._vertData); + assert(!node._faceData); + node._textures = _textures; node._render = _render; node._isTransparent = _isTransparent; - if (!node.createFaces(_faceCount)) - return; + node._vertDecl = _vertDecl; + node._vertCount = _vertCount; + node._vertSize = _vertSize; + node._vertData = std::malloc(_vertCount * _vertSize); + memcpy(node._vertData, _vertData, _vertCount * _vertSize); - memcpy(node._coords, _coords, - (3 * 3 * _faceCount + 2 * 3 * _faceCount * _textures.size()) * sizeof(float)); + node._faceCount = _faceCount; + node._faceSize = _faceSize; + node._faceType = _faceType; + node._faceData = std::malloc(_faceCount * _faceSize); + memcpy(node._faceData, _faceData, _faceCount * _faceSize); - memcpy(node._smoothGroups, _smoothGroups, _faceCount * sizeof(uint32)); - memcpy(node._material , _material , _faceCount * sizeof(uint32)); - - node.createBound(); + memcpy(node._center, _center, 3 * sizeof(float)); + node._boundBox = _boundBox; } void ModelNode::reparent(ModelNode &parent) { @@ -332,35 +401,15 @@ void ModelNode::loadTextures(const std::vector &textures) { _render = false; } -bool ModelNode::createFaces(uint32 count) { - assert(!_coords); - - if (count == 0) - return false; - - const uint32 textureCount = _textures.size(); - - _faceCount = count; - - _coords = new float[3 * 3 * _faceCount + 2 * 3 * _faceCount * textureCount]; - - _vX = _coords + 0 * 3 * _faceCount; - _vY = _coords + 1 * 3 * _faceCount; - _vZ = _coords + 2 * 3 * _faceCount; - - _tX = _coords + 3 * 3 * _faceCount + 0 * 3 * _faceCount * textureCount; - _tY = _coords + 3 * 3 * _faceCount + 1 * 3 * _faceCount * textureCount; - - _smoothGroups = new uint32[_faceCount]; - _material = new uint32[_faceCount]; - - return true; -} - void ModelNode::createBound() { - uint32 count = 3 * _faceCount; - for (uint32 v = 0; v < count; v++) - _boundBox.add(_vX[v], _vY[v], _vZ[v]); + assert(_vertDecl[0].index == VPOSITION); + assert(_vertDecl[0].type == GL_FLOAT); + uint32 stride = MAX(_vertDecl[0].size, _vertDecl[0].stride / sizeof(float)); + float *vX = (float *) _vertDecl[0].pointer; + float *vY = vX + 1; + float *vZ = vY + 1; + for (uint32 v = 0; v < _vertCount; v++) + _boundBox.add(vX[v * stride], vY[v * stride], vZ[v * stride]); createCenter(); } @@ -425,45 +474,15 @@ void ModelNode::renderGeometry() { TextureMan.set(_textures[t]); } - // Render the node's faces - const uint32 textureCount = _textures.size(); - const float *vX = _vX; - const float *vY = _vY; - const float *vZ = _vZ; - const float *tX = _tX; - const float *tY = _tY; - - glBegin(GL_TRIANGLES); - for (uint32 f = 0; f < _faceCount; f++, vX += 3, vY += 3, vZ += 3, - tX += 3 * textureCount, tY += 3 * textureCount) { - - // Texture vertex A - for (uint32 t = 0; t < textureCount; t++) - TextureMan.textureCoord2f(t, tX[3 * t + 0], tY[3 * t + 0]); - - // Geometry vertex A - glVertex3f(vX[0], vY[0], vZ[0]); - + for (uint32 i = 0; i < _vertDecl.size(); i++) + EnableVertexAttrib(_vertDecl[i]); - // Texture vertex B - for (uint32 t = 0; t < textureCount; t++) - TextureMan.textureCoord2f(t, tX[3 * t + 1], tY[3 * t + 1]); - - // Geometry vertex B - glVertex3f(vX[1], vY[1], vZ[1]); - - - // Texture vertex C - for (uint32 t = 0; t < textureCount; t++) - TextureMan.textureCoord2f(t, tX[3 * t + 2], tY[3 * t + 2]); - - // Geometry vertex C - glVertex3f(vX[2], vY[2], vZ[2]); - } - glEnd(); + glDrawElements(GL_TRIANGLES, _faceCount * 3, _faceType, _faceData); + for (uint32 i = 0; i < _vertDecl.size(); i++) + DisableVertexAttrib(_vertDecl[i]); // Disable the texture units again for (uint32 i = 0; i < _textures.size(); i++) { diff --git a/src/graphics/aurora/modelnode.h b/src/graphics/aurora/modelnode.h index 411c2328ca..4c9261004b 100644 --- a/src/graphics/aurora/modelnode.h +++ b/src/graphics/aurora/modelnode.h @@ -63,6 +63,23 @@ struct QuaternionKeyFrame { float q; }; +/** Vertex attribute data index enum, hardcoded for now */ +enum VertexAttribIdEnum { + VPOSITION = 0, ///< Vertex position + VNORMAL, ///< Vertex normal + VCOLOR, ///< Vertex color + VTCOORD ///< Vertex texture coordinates, VTCOORDi = VTCOORD + i +}; + +/** Generic vertex attribute data */ +struct VertexAttrib { + GLuint index; ///< Index of the vertex attribute (see VertexAttribIdEnum) + GLint size; ///< Number of components per vertex attribute, must be 1, 2, 3, 4 + GLenum type; ///< Data type of each attribute component in the array + GLsizei stride; ///< Byte offset between consecutive vertex attributes + const GLvoid *pointer; ///< Offset of the first component of the first generic vertex attribute +}; + class ModelNode { public: ModelNode(Model &model); @@ -116,21 +133,15 @@ class ModelNode { Common::UString _name; ///< The node's name. - uint32 _faceCount; ///< Number of faces + std::vector _vertDecl; ///< Vertex declaration + uint32 _vertCount; ///< Number of vertices + uint32 _vertSize; ///< Vertex attributes size sum in bytes (cached) + GLvoid *_vertData; ///< Vertex attributes data - float *_coords; ///< Coordinates pool. - - // Vertex coordinates - float *_vX; ///< Vertex coordinates, X. - float *_vY; ///< Vertex coordinates, Y. - float *_vZ; ///< Vertex coordinates, Z. - - // Texture cordinates - float *_tX; ///< Texture cordinates, X. - float *_tY; ///< Texture cordinates, Y. - - uint32 *_smoothGroups; ///< Face smooth groups. - uint32 *_material; ///< Face materials. + uint32 _faceCount; ///< Number of faces + uint32 _faceSize; ///< Face indices size in bytes + GLenum _faceType; ///< Face indices type (GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, ...) + GLvoid *_faceData; ///< Face indices data float _center [3]; ///< The node's center. float _position [3]; ///< Position of the node. @@ -187,7 +198,6 @@ class ModelNode { // Loading helpers void loadTextures(const std::vector &textures); - bool createFaces(uint32 count); void createBound(); void createCenter();