From 7fc3153f62718e17c00c0f4478d3b33380e1d419 Mon Sep 17 00:00:00 2001 From: capostrophic Date: Thu, 8 Aug 2019 19:26:50 +0300 Subject: [PATCH] Reduce code duplication further --- components/nif/data.cpp | 1 - components/nifbullet/bulletnifloader.cpp | 71 +++-------- components/nifosg/nifloader.cpp | 147 ++++++++--------------- 3 files changed, 68 insertions(+), 151 deletions(-) diff --git a/components/nif/data.cpp b/components/nif/data.cpp index 485a2ddf8..3ed7d5c3c 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -96,7 +96,6 @@ void NiTriStripsData::read(NIFStream *nif) // Every strip with n points defines n-2 triangles, so this should be unnecessary. /*int tris =*/ nif->getUShort(); - // Number of triangle strips int numStrips = nif->getUShort(); // Number of points in each strip diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 40a9134f3..93429ef93 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -58,28 +58,17 @@ void fillTriangleMeshWithTransform(btTriangleMesh& mesh, const Nif::NiTriStripsD { const std::vector &vertices = data.vertices; const std::vector> &strips = data.strips; - if (vertices.empty() || strips.empty()) + // Can't make a triangle from less than three vertices. All strips have the same size. + if (vertices.empty() || strips.empty() || strips[0].size() < 3) return; - - // Assume every strip has the same size - const int singleStripSize = static_cast(strips[0].size()); - // Can't make a triangle from less than three vertices. - if (singleStripSize < 3) - return; - mesh.preallocateVertices(static_cast(data.vertices.size())); - // There are N+2*M vertex indices in sum in all strips - // where N is the number of triangles and M is the number of strips - mesh.preallocateIndices(static_cast((strips.size()-2) * singleStripSize)); + // There are N+2*M vertex indices overall, so we must substract 2*M (N triangles, M strips) + mesh.preallocateIndices(static_cast((strips.size()-2) * strips[0].size())); // It's triangulation time. Totally not a NifSkope spell ripoff. for (const std::vector& strip : strips) { - unsigned short a = strip[0]; - unsigned short b = strip[0]; - unsigned short c = strip[1]; - bool flip = false; - + unsigned short a = strip[0], b = strip[0], c = strip[1]; for (int i = 2; i < static_cast(strip.size()); i++) { a = b; @@ -87,24 +76,26 @@ void fillTriangleMeshWithTransform(btTriangleMesh& mesh, const Nif::NiTriStripsD c = strip[i]; if (a != b && b != c && a != c) { - if (!flip) + if (i%2==0) mesh.addTriangle(getbtVector(vertices[a]), getbtVector(vertices[b]), getbtVector(vertices[c])); else mesh.addTriangle(getbtVector(vertices[a]), getbtVector(vertices[c]), getbtVector(vertices[b])); } - flip = !flip; } } } -void fillTriangleMesh(btTriangleMesh& mesh, const Nif::NiTriShapeData& data) +void fillTriangleMeshWithTransform(btTriangleMesh& mesh, const Nif::Node* nifNode, const osg::Matrixf &transform) { - fillTriangleMeshWithTransform(mesh, data, osg::Matrixf()); + if (nifNode->recType == Nif::RC_NiTriShape) + fillTriangleMeshWithTransform(mesh, static_cast(nifNode)->data.get(), transform); + else // if (nifNode->recType == Nif::RC_NiTriStrips) + fillTriangleMeshWithTransform(mesh, static_cast(nifNode)->data.get(), transform); } -void fillTriangleMesh(btTriangleMesh& mesh, const Nif::NiTriStripsData& data) +void fillTriangleMesh(btTriangleMesh& mesh, const Nif::Node* node) { - fillTriangleMeshWithTransform(mesh, data, osg::Matrixf()); + fillTriangleMeshWithTransform(mesh, node, osg::Matrixf()); } } @@ -326,9 +317,7 @@ void BulletNifLoader::handleNiTriShape(const Nif::Node *nifNode, int flags, cons const Nif::NiTriShape* shape = static_cast(nifNode); if (!shape->skin.empty()) isAnimated = false; - if (shape->data.empty()) - return; - if (shape->data->triangles.empty()) + if (shape->data.empty() || shape->data->triangles.empty()) return; } else @@ -336,9 +325,7 @@ void BulletNifLoader::handleNiTriShape(const Nif::Node *nifNode, int flags, cons const Nif::NiTriStrips* shape = static_cast(nifNode); if (!shape->skin.empty()) isAnimated = false; - if (shape->data.empty()) - return; - if (shape->data->strips.empty()) + if (shape->data.empty() || shape->data->strips.empty()) return; } @@ -350,10 +337,7 @@ void BulletNifLoader::handleNiTriShape(const Nif::Node *nifNode, int flags, cons std::unique_ptr childMesh(new btTriangleMesh); - if (nifNode->recType == Nif::RC_NiTriShape) - fillTriangleMesh(*childMesh, static_cast(nifNode)->data.get()); - else - fillTriangleMesh(*childMesh, static_cast(nifNode)->data.get()); + fillTriangleMesh(*childMesh, nifNode); std::unique_ptr childShape(new Resource::TriangleMeshShape(childMesh.get(), true)); childMesh.release(); @@ -381,16 +365,7 @@ void BulletNifLoader::handleNiTriShape(const Nif::Node *nifNode, int flags, cons if (!mAvoidStaticMesh) mAvoidStaticMesh.reset(new btTriangleMesh(false)); - if (nifNode->recType == Nif::RC_NiTriShape) - { - const Nif::NiTriShape* shape = static_cast(nifNode); - fillTriangleMeshWithTransform(*mAvoidStaticMesh, shape->data.get(), transform); - } - else - { - const Nif::NiTriStrips* shape = static_cast(nifNode); - fillTriangleMeshWithTransform(*mAvoidStaticMesh, shape->data.get(), transform); - } + fillTriangleMeshWithTransform(*mAvoidStaticMesh, nifNode, transform); } else { @@ -398,17 +373,7 @@ void BulletNifLoader::handleNiTriShape(const Nif::Node *nifNode, int flags, cons mStaticMesh.reset(new btTriangleMesh(false)); // Static shape, just transform all vertices into position - - if (nifNode->recType == Nif::RC_NiTriShape) - { - const Nif::NiTriShape* shape = static_cast(nifNode); - fillTriangleMeshWithTransform(*mStaticMesh, shape->data.get(), transform); - } - else - { - const Nif::NiTriStrips* shape = static_cast(nifNode); - fillTriangleMeshWithTransform(*mStaticMesh, shape->data.get(), transform); - } + fillTriangleMeshWithTransform(*mStaticMesh, nifNode, transform); } } diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index f5f36a36d..77e9688c7 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -576,8 +576,7 @@ namespace NifOsg node->setDataVariance(osg::Object::DYNAMIC); } - // Same thing for animated shapes - if ((nifNode->recType == Nif::RC_NiTriShape || nifNode->recType == Nif::RC_NiTriStrips) && isAnimated) + if ((nifNode->recType == Nif::RC_NiTriShape || nifNode->recType == Nif::RC_NiTriStrips) && isAnimated) // Same thing for animated shapes { node->setDataVariance(osg::Object::DYNAMIC); } @@ -1038,85 +1037,55 @@ namespace NifOsg } } - void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) + void triCommonToGeometry(osg::Geometry *geometry, const std::vector& vertices, const std::vector& normals, const std::vector>& uvlist, const std::vector& colors, const std::vector& boundTextures, const std::string& name) { - const Nif::NiTriShapeData* data = triShape->data.getPtr(); - - if (!data->vertices.empty()) - geometry->setVertexArray(new osg::Vec3Array(data->vertices.size(), data->vertices.data())); - if (!data->normals.empty()) - geometry->setNormalArray(new osg::Vec3Array(data->normals.size(), data->normals.data()), osg::Array::BIND_PER_VERTEX); - - int textureStage = 0; - for (std::vector::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it,++textureStage) - { - int uvSet = *it; - if (uvSet >= (int)data->uvlist.size()) - { - Log(Debug::Verbose) << "Out of bounds UV set " << uvSet << " on TriShape \"" << triShape->name << "\" in " << mFilename; - if (!data->uvlist.empty()) - geometry->setTexCoordArray(textureStage, new osg::Vec2Array(data->uvlist[0].size(), data->uvlist[0].data()), osg::Array::BIND_PER_VERTEX); - continue; - } - - geometry->setTexCoordArray(textureStage, new osg::Vec2Array(data->uvlist[uvSet].size(), data->uvlist[uvSet].data()), osg::Array::BIND_PER_VERTEX); - } - - if (!data->colors.empty()) - geometry->setColorArray(new osg::Vec4Array(data->colors.size(), data->colors.data()), osg::Array::BIND_PER_VERTEX); - - if (!data->triangles.empty()) - geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, - data->triangles.size(), - (unsigned short*)data->triangles.data())); - - // osg::Material properties are handled here for two reasons: - // - if there are no vertex colors, we need to disable colorMode. - // - there are 3 "overlapping" nif properties that all affect the osg::Material, handling them - // above the actual renderable would be tedious. - std::vector drawableProps; - collectDrawableProperties(triShape, drawableProps); - applyDrawableProperties(parentNode, drawableProps, composite, !data->colors.empty(), animflags, false); - } - - void triStripsToGeometry(const Nif::NiTriStrips *triStrips, osg::Geometry *geometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) - { - const Nif::NiTriStripsData* data = triStrips->data.getPtr(); - - if (!data->vertices.empty()) - geometry->setVertexArray(new osg::Vec3Array(data->vertices.size(), data->vertices.data())); - if (!data->normals.empty()) - geometry->setNormalArray(new osg::Vec3Array(data->normals.size(), data->normals.data()), osg::Array::BIND_PER_VERTEX); + if (!vertices.empty()) + geometry->setVertexArray(new osg::Vec3Array(vertices.size(), vertices.data())); + if (!normals.empty()) + geometry->setNormalArray(new osg::Vec3Array(normals.size(), normals.data()), osg::Array::BIND_PER_VERTEX); + if (!colors.empty()) + geometry->setColorArray(new osg::Vec4Array(colors.size(), colors.data()), osg::Array::BIND_PER_VERTEX); int textureStage = 0; for (const int uvSet : boundTextures) { - if (uvSet >= (int)data->uvlist.size()) + if (uvSet >= (int)uvlist.size()) { - Log(Debug::Verbose) << "Out of bounds UV set " << uvSet << " on TriStrips \"" << triStrips->name << "\" in " << mFilename; - if (!data->uvlist.empty()) - geometry->setTexCoordArray(textureStage, new osg::Vec2Array(data->uvlist[0].size(), data->uvlist[0].data()), osg::Array::BIND_PER_VERTEX); + Log(Debug::Verbose) << "Out of bounds UV set " << uvSet << " on shape \"" << name << "\" in " << mFilename; + if (!uvlist.empty()) + geometry->setTexCoordArray(textureStage, new osg::Vec2Array(uvlist[0].size(), uvlist[0].data()), osg::Array::BIND_PER_VERTEX); continue; } - geometry->setTexCoordArray(textureStage, new osg::Vec2Array(data->uvlist[uvSet].size(), data->uvlist[uvSet].data()), osg::Array::BIND_PER_VERTEX); + geometry->setTexCoordArray(textureStage, new osg::Vec2Array(uvlist[uvSet].size(), uvlist[uvSet].data()), osg::Array::BIND_PER_VERTEX); textureStage++; } + } - if (!data->colors.empty()) - geometry->setColorArray(new osg::Vec4Array(data->colors.size(), data->colors.data()), osg::Array::BIND_PER_VERTEX); - - if (!data->strips.empty()) + void triShapeToGeometry(const Nif::Node *nifNode, osg::Geometry *geometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) + { + bool vertexColorsPresent = false; + if (nifNode->recType == Nif::RC_NiTriShape) { - for (const std::vector& strip : data->strips) - { - // Can't make a triangle from less than three vertices. - // All strips have the same size. - if (strip.size() < 3) - break; - geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, - strip.size(), (unsigned short*)strip.data())); - } + const Nif::NiTriShape* triShape = static_cast(nifNode); + const Nif::NiTriShapeData* data = triShape->data.getPtr(); + vertexColorsPresent = !data->colors.empty(); + triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triShape->name); + if (!data->triangles.empty()) + geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, data->triangles.size(), + (unsigned short*)data->triangles.data())); + } + else + { + const Nif::NiTriStrips* triStrips = static_cast(nifNode); + const Nif::NiTriStripsData* data = triStrips->data.getPtr(); + vertexColorsPresent = !data->colors.empty(); + triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triStrips->name); + // Can't make a triangle from less than three vertices. All strips have the same size. + if (!data->strips.empty() && data->strips[0].size() < 3) + for (const std::vector& strip : data->strips) + geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, strip.size(), + (unsigned short*)strip.data())); } // osg::Material properties are handled here for two reasons: @@ -1124,34 +1093,26 @@ namespace NifOsg // - there are 3 "overlapping" nif properties that all affect the osg::Material, handling them // above the actual renderable would be tedious. std::vector drawableProps; - collectDrawableProperties(triStrips, drawableProps); - applyDrawableProperties(parentNode, drawableProps, composite, !data->colors.empty(), animflags, false); + collectDrawableProperties(nifNode, drawableProps); + applyDrawableProperties(parentNode, drawableProps, composite, vertexColorsPresent, animflags, false); } void handleTriShape(const Nif::Node* nifNode, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) { assert(nifNode->recType == Nif::RC_NiTriShape || nifNode->recType == Nif::RC_NiTriStrips); - osg::ref_ptr drawable; osg::ref_ptr geom (new osg::Geometry); + triShapeToGeometry(nifNode, geom, parentNode, composite, boundTextures, animflags); + Nif::ControllerPtr ctrl; if (nifNode->recType == Nif::RC_NiTriShape) - { - const Nif::NiTriShape* triShape = static_cast(nifNode); - triShapeToGeometry(triShape, geom, parentNode, composite, boundTextures, animflags); - handleMorphController(triShape->controller, drawable, geom, parentNode, composite, boundTextures, animflags); - } + ctrl = static_cast(nifNode)->controller; else - { - const Nif::NiTriStrips* triStrips = static_cast(nifNode); - triStripsToGeometry(triStrips, geom, parentNode, composite, boundTextures, animflags); - handleMorphController(triStrips->controller, drawable, geom, parentNode, composite, boundTextures, animflags); - } + ctrl = static_cast(nifNode)->controller; + handleMorphController(ctrl, drawable, geom, parentNode, composite, boundTextures, animflags); if (!drawable.get()) drawable = geom; - drawable->setName(nifNode->name); - parentNode->addChild(drawable); } @@ -1193,21 +1154,8 @@ namespace NifOsg const std::vector& boundTextures, int animflags) { assert(nifNode->recType == Nif::RC_NiTriShape || nifNode->recType == Nif::RC_NiTriStrips); - osg::ref_ptr geometry (new osg::Geometry); - Nif::NiSkinInstancePtr skinPtr; - if (nifNode->recType == Nif::RC_NiTriShape) - { - const Nif::NiTriShape* triShape = static_cast(nifNode); - triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); - skinPtr = triShape->skin; - } - else - { - const Nif::NiTriStrips* triStrips = static_cast(nifNode); - triStripsToGeometry(triStrips, geometry, parentNode, composite, boundTextures, animflags); - skinPtr = triStrips->skin; - } + triShapeToGeometry(nifNode, geometry, parentNode, composite, boundTextures, animflags); osg::ref_ptr rig(new SceneUtil::RigGeometry); rig->setSourceGeometry(geometry); rig->setName(nifNode->name); @@ -1215,6 +1163,11 @@ namespace NifOsg // Assign bone weights osg::ref_ptr map (new SceneUtil::RigGeometry::InfluenceMap); + Nif::NiSkinInstancePtr skinPtr; + if (nifNode->recType == Nif::RC_NiTriShape) + skinPtr = static_cast(nifNode)->skin; + else + skinPtr = static_cast(nifNode)->skin; const Nif::NiSkinInstance *skin = skinPtr.getPtr(); const Nif::NiSkinData *data = skin->data.getPtr(); const Nif::NodeList &bones = skin->bones;