From 8fd45d85ec0ae1c209c51dab942bcfba7d8be14e Mon Sep 17 00:00:00 2001 From: Alexei Dobrohotov Date: Sun, 13 Dec 2020 03:16:05 +0300 Subject: [PATCH] Unify NiGeometry/NiGeometryData handling --- .../nifloader/testbulletnifloader.cpp | 22 ++- components/nif/node.hpp | 139 +++++------------- components/nif/recordptr.hpp | 10 +- components/nifbullet/bulletnifloader.cpp | 51 ++++--- components/nifosg/nifloader.cpp | 81 +++++----- 5 files changed, 124 insertions(+), 179 deletions(-) diff --git a/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp b/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp index 3a854bf5c9..5769b1d0a8 100644 --- a/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp +++ b/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp @@ -259,14 +259,19 @@ namespace value.isBone = false; } - void init(Nif::NiTriShape& value) + void init(Nif::NiGeometry& value) { init(static_cast(value)); - value.recType = Nif::RC_NiTriShape; - value.data = Nif::NiTriShapeDataPtr(nullptr); + value.data = Nif::NiGeometryDataPtr(nullptr); value.skin = Nif::NiSkinInstancePtr(nullptr); } + void init(Nif::NiTriShape& value) + { + init(static_cast(value)); + value.recType = Nif::RC_NiTriShape; + } + void init(Nif::NiSkinInstance& value) { value.data = Nif::NiSkinDataPtr(nullptr); @@ -361,13 +366,15 @@ namespace init(mNiStringExtraData2); init(mController); + mNiTriShapeData.recType = Nif::RC_NiTriShapeData; mNiTriShapeData.vertices = {osg::Vec3f(0, 0, 0), osg::Vec3f(1, 0, 0), osg::Vec3f(1, 1, 0)}; mNiTriShapeData.triangles = {0, 1, 2}; - mNiTriShape.data = Nif::NiTriShapeDataPtr(&mNiTriShapeData); + mNiTriShape.data = Nif::NiGeometryDataPtr(&mNiTriShapeData); + mNiTriShapeData2.recType = Nif::RC_NiTriShapeData; mNiTriShapeData2.vertices = {osg::Vec3f(0, 0, 1), osg::Vec3f(1, 0, 1), osg::Vec3f(1, 1, 1)}; mNiTriShapeData2.triangles = {0, 1, 2}; - mNiTriShape2.data = Nif::NiTriShapeDataPtr(&mNiTriShapeData2); + mNiTriShape2.data = Nif::NiGeometryDataPtr(&mNiTriShapeData2); } }; @@ -873,7 +880,7 @@ namespace TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_empty_data_should_return_shape_with_null_collision_shape) { - mNiTriShape.data = Nif::NiTriShapeDataPtr(nullptr); + mNiTriShape.data = Nif::NiGeometryDataPtr(nullptr); mNiNode.children = Nif::NodeList(std::vector({Nif::NodePtr(&mNiTriShape)})); EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); @@ -888,7 +895,8 @@ namespace TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_empty_data_triangles_should_return_shape_with_null_collision_shape) { - mNiTriShape.data->triangles.clear(); + auto data = static_cast(mNiTriShape.data.getPtr()); + data->triangles.clear(); mNiNode.children = Nif::NodeList(std::vector({Nif::NodePtr(&mNiTriShape)})); EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 58397bdca4..3106e368bb 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -240,43 +240,6 @@ struct NiNode : Node }; struct NiGeometry : Node -{ - struct MaterialData - { - std::vector materialNames; - std::vector materialExtraData; - unsigned int activeMaterial{0}; - bool materialNeedsUpdate{false}; - void read(NIFStream *nif) - { - if (nif->getVersion() <= NIFStream::generateVersion(10,0,1,0)) - return; - unsigned int numMaterials = 0; - if (nif->getVersion() <= NIFStream::generateVersion(20,1,0,3)) - numMaterials = nif->getBoolean(); // Has Shader - else if (nif->getVersion() >= NIFStream::generateVersion(20,2,0,5)) - numMaterials = nif->getUInt(); - if (numMaterials) - { - nif->getStrings(materialNames, numMaterials); - nif->getInts(materialExtraData, numMaterials); - } - if (nif->getVersion() >= NIFStream::generateVersion(20,2,0,5)) - activeMaterial = nif->getUInt(); - if (nif->getVersion() >= NIFFile::NIFVersion::VER_BGS) - { - materialNeedsUpdate = nif->getBoolean(); - if (nif->getVersion() == NIFFile::NIFVersion::VER_BGS && nif->getBethVersion() > NIFFile::BethVersion::BETHVER_FO3) - nif->skip(8); - } - } - }; - - NiSkinInstancePtr skin; - MaterialData materialData; -}; - -struct NiTriShape : NiGeometry { /* Possible flags: 0x40 - mesh has no vertex normals ? @@ -285,14 +248,45 @@ struct NiTriShape : NiGeometry been observed so far. */ - NiTriShapeDataPtr data; + struct MaterialData + { + std::vector names; + std::vector extra; + unsigned int active{0}; + bool needsUpdate{false}; + void read(NIFStream *nif) + { + if (nif->getVersion() <= NIFStream::generateVersion(10,0,1,0)) + return; + unsigned int num = 0; + if (nif->getVersion() <= NIFStream::generateVersion(20,1,0,3)) + num = nif->getBoolean(); // Has Shader + else if (nif->getVersion() >= NIFStream::generateVersion(20,2,0,5)) + num = nif->getUInt(); + if (num) + { + nif->getStrings(names, num); + nif->getInts(extra, num); + } + if (nif->getVersion() >= NIFStream::generateVersion(20,2,0,5)) + active = nif->getUInt(); + if (nif->getVersion() >= NIFFile::NIFVersion::VER_BGS) + needsUpdate = nif->getBoolean(); + } + }; + + NiGeometryDataPtr data; + NiSkinInstancePtr skin; + MaterialData material; void read(NIFStream *nif) override { Node::read(nif); data.read(nif); skin.read(nif); - materialData.read(nif); + material.read(nif); + if (nif->getVersion() == NIFFile::NIFVersion::VER_BGS && nif->getBethVersion() > NIFFile::BethVersion::BETHVER_FO3) + nif->skip(8); } void post(NIFFile *nif) override @@ -300,53 +294,15 @@ struct NiTriShape : NiGeometry Node::post(nif); data.post(nif); skin.post(nif); - if (!skin.empty()) + if (recType != RC_NiParticles && !skin.empty()) nif->setUseSkinning(true); } }; -struct NiTriStrips : NiGeometry -{ - NiTriStripsDataPtr data; - - void read(NIFStream *nif) override - { - Node::read(nif); - data.read(nif); - skin.read(nif); - materialData.read(nif); - } - - void post(NIFFile *nif) override - { - Node::post(nif); - data.post(nif); - skin.post(nif); - if (!skin.empty()) - nif->setUseSkinning(true); - } -}; - -struct NiLines : NiGeometry -{ - NiLinesDataPtr data; - - void read(NIFStream *nif) override - { - Node::read(nif); - data.read(nif); - skin.read(nif); - } - - void post(NIFFile *nif) override - { - Node::post(nif); - data.post(nif); - skin.post(nif); - if (!skin.empty()) - nif->setUseSkinning(true); - } -}; +struct NiTriShape : NiGeometry {}; +struct NiTriStrips : NiGeometry {}; +struct NiLines : NiGeometry {}; +struct NiParticles : NiGeometry { }; struct NiCamera : Node { @@ -401,25 +357,6 @@ struct NiCamera : Node } }; -struct NiParticles : NiGeometry -{ - NiParticlesDataPtr data; - void read(NIFStream *nif) override - { - Node::read(nif); - data.read(nif); - skin.read(nif); - materialData.read(nif); - } - - void post(NIFFile *nif) override - { - Node::post(nif); - data.post(nif); - skin.post(nif); - } -}; - // A node used as the base to switch between child nodes, such as for LOD levels. struct NiSwitchNode : public NiNode { diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index 0f5615a687..dd6e357084 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -134,20 +134,18 @@ struct NiMorphData; class NiPixelData; class NiColorData; struct NiKeyframeData; -class NiTriShapeData; class NiTriStripsData; class NiSkinInstance; class NiSourceTexture; -class NiParticlesData; class NiPalette; struct NiParticleModifier; -struct NiLinesData; struct NiBoolData; struct NiSkinPartition; struct NiFloatInterpolator; struct NiPoint3Interpolator; struct NiTransformInterpolator; struct BSShaderTextureSet; +struct NiGeometryData; using NodePtr = RecordPtrT; using ExtraPtr = RecordPtrT; @@ -162,12 +160,8 @@ using NiPixelDataPtr = RecordPtrT; using NiFloatDataPtr = RecordPtrT; using NiColorDataPtr = RecordPtrT; using NiKeyframeDataPtr = RecordPtrT; -using NiTriShapeDataPtr = RecordPtrT; -using NiTriStripsDataPtr = RecordPtrT; -using NiLinesDataPtr = RecordPtrT; using NiSkinInstancePtr = RecordPtrT; using NiSourceTexturePtr = RecordPtrT; -using NiParticlesDataPtr = RecordPtrT; using NiPalettePtr = RecordPtrT; using NiParticleModifierPtr = RecordPtrT; using NiBoolDataPtr = RecordPtrT; @@ -176,12 +170,14 @@ using NiFloatInterpolatorPtr = RecordPtrT; using NiPoint3InterpolatorPtr = RecordPtrT; using NiTransformInterpolatorPtr = RecordPtrT; using BSShaderTextureSetPtr = RecordPtrT; +using NiGeometryDataPtr = RecordPtrT; using NodeList = RecordListT; using PropertyList = RecordListT; using ExtraList = RecordListT; using NiSourceTextureList = RecordListT; using NiFloatInterpolatorList = RecordListT; +using NiTriStripsDataList = RecordListT; } // Namespace #endif diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index b24d08fd8c..a14672636a 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -34,11 +34,10 @@ bool pathFileNameStartsWithX(const std::string& path) void fillTriangleMesh(btTriangleMesh& mesh, const Nif::NiTriShapeData& data, const osg::Matrixf &transform) { - mesh.preallocateVertices(static_cast(data.vertices.size())); - mesh.preallocateIndices(static_cast(data.triangles.size())); - const std::vector &vertices = data.vertices; const std::vector &triangles = data.triangles; + mesh.preallocateVertices(static_cast(vertices.size())); + mesh.preallocateIndices(static_cast(triangles.size())); for (std::size_t i = 0; i < triangles.size(); i += 3) { @@ -54,8 +53,6 @@ void fillTriangleMesh(btTriangleMesh& mesh, const Nif::NiTriStripsData& data, co { const std::vector &vertices = data.vertices; const std::vector> &strips = data.strips; - if (vertices.empty() || strips.empty()) - return; mesh.preallocateVertices(static_cast(vertices.size())); int numTriangles = 0; for (const std::vector& strip : strips) @@ -102,12 +99,12 @@ void fillTriangleMesh(btTriangleMesh& mesh, const Nif::NiTriStripsData& data, co } } -void fillTriangleMesh(btTriangleMesh& mesh, const Nif::Node* nifNode, const osg::Matrixf &transform = osg::Matrixf()) +void fillTriangleMesh(btTriangleMesh& mesh, const Nif::NiGeometry* geometry, const osg::Matrixf &transform = osg::Matrixf()) { - if (nifNode->recType == Nif::RC_NiTriShape) - fillTriangleMesh(mesh, static_cast(nifNode)->data.get(), transform); - else if (nifNode->recType == Nif::RC_NiTriStrips) - fillTriangleMesh(mesh, static_cast(nifNode)->data.get(), transform); + if (geometry->recType == Nif::RC_NiTriShape) + fillTriangleMesh(mesh, static_cast(geometry->data.get()), transform); + else if (geometry->recType == Nif::RC_NiTriStrips) + fillTriangleMesh(mesh, static_cast(geometry->data.get()), transform); } } @@ -341,23 +338,31 @@ void BulletNifLoader::handleNiTriShape(const Nif::Node *nifNode, int flags, cons if ((flags & 0x800)) return; - if (nifNode->recType == Nif::RC_NiTriShape) + auto niGeometry = static_cast(nifNode); + if (niGeometry->data.empty() || niGeometry->data->vertices.empty()) + return; + + if (niGeometry->recType == Nif::RC_NiTriShape) { - const Nif::NiTriShape* shape = static_cast(nifNode); - if (!shape->skin.empty()) - isAnimated = false; - if (shape->data.empty() || shape->data->triangles.empty()) + if (niGeometry->data->recType != Nif::RC_NiTriShapeData) + return; + + auto data = static_cast(niGeometry->data.getPtr()); + if (data->triangles.empty()) return; } - else + else if (niGeometry->recType == Nif::RC_NiTriStrips) { - const Nif::NiTriStrips* shape = static_cast(nifNode); - if (!shape->skin.empty()) - isAnimated = false; - if (shape->data.empty() || shape->data->strips.empty()) + if (niGeometry->data->recType != Nif::RC_NiTriStripsData) + return; + + auto data = static_cast(niGeometry->data.getPtr()); + if (data->strips.empty()) return; } + if (!niGeometry->skin.empty()) + isAnimated = false; if (isAnimated) { @@ -366,7 +371,7 @@ void BulletNifLoader::handleNiTriShape(const Nif::Node *nifNode, int flags, cons std::unique_ptr childMesh(new btTriangleMesh); - fillTriangleMesh(*childMesh, nifNode); + fillTriangleMesh(*childMesh, niGeometry); std::unique_ptr childShape(new Resource::TriangleMeshShape(childMesh.get(), true)); childMesh.release(); @@ -394,7 +399,7 @@ void BulletNifLoader::handleNiTriShape(const Nif::Node *nifNode, int flags, cons if (!mAvoidStaticMesh) mAvoidStaticMesh.reset(new btTriangleMesh(false)); - fillTriangleMesh(*mAvoidStaticMesh, nifNode, transform); + fillTriangleMesh(*mAvoidStaticMesh, niGeometry, transform); } else { @@ -402,7 +407,7 @@ void BulletNifLoader::handleNiTriShape(const Nif::Node *nifNode, int flags, cons mStaticMesh.reset(new btTriangleMesh(false)); // Static shape, just transform all vertices into position - fillTriangleMesh(*mStaticMesh, nifNode, transform); + fillTriangleMesh(*mStaticMesh, niGeometry, transform); } } diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 3120b0d748..7ebb9bf8d4 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -939,11 +939,11 @@ namespace NifOsg // Load the initial state of the particle system, i.e. the initial particles and their positions, velocity and colors. void handleParticleInitialState(const Nif::Node* nifNode, osgParticle::ParticleSystem* partsys, const Nif::NiParticleSystemController* partctrl) { - const auto particleNode = static_cast(nifNode); - if (particleNode->data.empty()) + auto particleNode = static_cast(nifNode); + if (particleNode->data.empty() || particleNode->data->recType != Nif::RC_NiParticlesData) return; - const Nif::NiParticlesData* particledata = particleNode->data.getPtr(); + auto particledata = static_cast(particleNode->data.getPtr()); osg::BoundingBox box; @@ -1173,51 +1173,50 @@ namespace NifOsg void handleNiGeometry(const Nif::Node *nifNode, osg::Geometry *geometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) { - const Nif::NiGeometryData* niGeometryData = nullptr; - if (nifNode->recType == Nif::RC_NiTriShape) + const Nif::NiGeometry* niGeometry = static_cast(nifNode); + if (niGeometry->data.empty()) + return; + const Nif::NiGeometryData* niGeometryData = niGeometry->data.getPtr(); + + if (niGeometry->recType == Nif::RC_NiTriShape) { - const Nif::NiTriShape* triShape = static_cast(nifNode); - if (!triShape->data.empty()) - { - const Nif::NiTriShapeData* data = triShape->data.getPtr(); - niGeometryData = static_cast(data); - if (!data->triangles.empty()) - geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, data->triangles.size(), - (unsigned short*)data->triangles.data())); - } + if (niGeometryData->recType != Nif::RC_NiTriShapeData) + return; + auto triangles = static_cast(niGeometryData)->triangles; + if (triangles.empty()) + return; + geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, triangles.size(), + (unsigned short*)triangles.data())); } - else if (nifNode->recType == Nif::RC_NiTriStrips) + else if (niGeometry->recType == Nif::RC_NiTriStrips) { - const Nif::NiTriStrips* triStrips = static_cast(nifNode); - if (!triStrips->data.empty()) + if (niGeometryData->recType != Nif::RC_NiTriStripsData) + return; + auto data = static_cast(niGeometryData); + bool hasGeometry = false; + for (const auto& strip : data->strips) { - const Nif::NiTriStripsData* data = triStrips->data.getPtr(); - niGeometryData = static_cast(data); - if (!data->strips.empty()) - { - for (const auto& strip : data->strips) - { - if (strip.size() >= 3) - geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, strip.size(), - (unsigned short*)strip.data())); - } - } + if (strip.size() < 3) + continue; + geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, strip.size(), + (unsigned short*)strip.data())); + hasGeometry = true; } + if (!hasGeometry) + return; } - else if (nifNode->recType == Nif::RC_NiLines) + else if (niGeometry->recType == Nif::RC_NiLines) { - const Nif::NiLines* lines = static_cast(nifNode); - if (!lines->data.empty()) - { - const Nif::NiLinesData* data = lines->data.getPtr(); - niGeometryData = static_cast(data); - const auto& line = data->lines; - if (!line.empty()) - geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::LINES, line.size(), (unsigned short*)line.data())); - } + if (niGeometryData->recType != Nif::RC_NiLinesData) + return; + auto data = static_cast(niGeometryData); + const auto& line = data->lines; + if (line.empty()) + return; + geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::LINES, line.size(), + (unsigned short*)line.data())); } - if (niGeometryData) - handleNiGeometryData(geometry, niGeometryData, boundTextures, nifNode->name); + handleNiGeometryData(geometry, niGeometryData, boundTextures, nifNode->name); // osg::Material properties are handled here for two reasons: // - if there are no vertex colors, we need to disable colorMode. @@ -1225,7 +1224,7 @@ namespace NifOsg // above the actual renderable would be tedious. std::vector drawableProps; collectDrawableProperties(nifNode, drawableProps); - applyDrawableProperties(parentNode, drawableProps, composite, niGeometryData && !niGeometryData->colors.empty(), animflags); + applyDrawableProperties(parentNode, drawableProps, composite, !niGeometryData->colors.empty(), animflags); } void handleGeometry(const Nif::Node* nifNode, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags)