From 3f252eab5d3cb7986a5393f72c7149e5db9b5689 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sun, 16 Jul 2023 03:06:00 +0300 Subject: [PATCH] Copy triangle data from NiSkinPartition --- components/nif/data.cpp | 33 +++++++ components/nif/data.hpp | 3 + components/nifbullet/bulletnifloader.cpp | 1 + components/nifosg/nifloader.cpp | 106 ++++++++++++++++------- 4 files changed, 110 insertions(+), 33 deletions(-) diff --git a/components/nif/data.cpp b/components/nif/data.cpp index cba34d9a6d..018e9fc603 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -446,6 +446,39 @@ namespace Nif } } + std::vector NiSkinPartition::Partition::getTrueTriangles() const + { + if (!trueTriangles.empty()) + return trueTriangles; + + std::vector remappedTriangles; + if (vertexMap.empty() || triangles.empty()) + return remappedTriangles; + + remappedTriangles = triangles; + + for (unsigned short& index : remappedTriangles) + index = vertexMap[index]; + return remappedTriangles; + } + + std::vector> NiSkinPartition::Partition::getTrueStrips() const + { + if (!trueTriangles.empty()) + return {}; + + std::vector> remappedStrips; + if (vertexMap.empty() || strips.empty()) + return remappedStrips; + + remappedStrips = strips; + for (auto& strip : remappedStrips) + for (auto& index : strip) + index = vertexMap[index]; + + return remappedStrips; + } + void NiMorphData::read(NIFStream* nif) { int morphCount = nif->getInt(); diff --git a/components/nif/data.hpp b/components/nif/data.hpp index ef02889d60..6f0ca25237 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -222,7 +222,10 @@ namespace Nif std::vector trueTriangles; std::vector boneIndices; BSVertexDesc mVertexDesc; + void read(NIFStream* nif); + std::vector getTrueTriangles() const; + std::vector> getTrueStrips() const; }; unsigned int mPartitionNum; std::vector mPartitions; diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index b3837fc4c9..251795eb21 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -385,6 +385,7 @@ namespace NifBullet if (!niGeometry.skin.empty()) args.mAnimated = false; + // TODO: handle NiSkinPartition std::unique_ptr childMesh = makeChildMesh(niGeometry); if (childMesh == nullptr || childMesh->getNumTriangles() == 0) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 98cc25f90d..3d7d4aedd8 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1376,45 +1376,85 @@ namespace NifOsg 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 || nifNode->recType == Nif::RC_BSLODTriShape) - { - 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 (niGeometry->recType == Nif::RC_NiTriStrips) + bool hasPartitions = false; + if (!niGeometry->skin.empty()) { - if (niGeometryData->recType != Nif::RC_NiTriStripsData) - return; - auto data = static_cast(niGeometryData); - bool hasGeometry = false; - for (const auto& strip : data->strips) + const Nif::NiSkinInstance* skin = niGeometry->skin.getPtr(); + const Nif::NiSkinData* data = nullptr; + const Nif::NiSkinPartition* partitions = nullptr; + if (!skin->data.empty()) { - if (strip.size() < 3) - continue; - geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, - strip.size(), reinterpret_cast(strip.data()))); - hasGeometry = true; + data = skin->data.getPtr(); + if (!data->partitions.empty()) + partitions = data->partitions.getPtr(); + } + if (!partitions && !skin->partitions.empty()) + partitions = skin->partitions.getPtr(); + + hasPartitions = partitions != nullptr; + if (hasPartitions) + { + std::vector trueTriangles; + for (const Nif::NiSkinPartition::Partition& partition : partitions->mPartitions) + { + trueTriangles = partition.getTrueTriangles(); + if (!trueTriangles.empty()) + { + geometry->addPrimitiveSet(new osg::DrawElementsUShort( + osg::PrimitiveSet::TRIANGLES, trueTriangles.size(), trueTriangles.data())); + } + const std::vector> trueStrips = partition.getTrueStrips(); + for (const auto& strip : trueStrips) + { + geometry->addPrimitiveSet(new osg::DrawElementsUShort( + osg::PrimitiveSet::TRIANGLE_STRIP, strip.size(), strip.data())); + } + } } - if (!hasGeometry) - return; } - else if (niGeometry->recType == Nif::RC_NiLines) + + const Nif::NiGeometryData* niGeometryData = niGeometry->data.getPtr(); + if (!hasPartitions) { - 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(), reinterpret_cast(line.data()))); + if (niGeometry->recType == Nif::RC_NiTriShape || nifNode->recType == Nif::RC_BSLODTriShape) + { + 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 (niGeometry->recType == Nif::RC_NiTriStrips) + { + if (niGeometryData->recType != Nif::RC_NiTriStripsData) + return; + auto data = static_cast(niGeometryData); + bool hasGeometry = false; + for (const auto& strip : data->strips) + { + if (strip.size() < 3) + continue; + geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, + strip.size(), reinterpret_cast(strip.data()))); + hasGeometry = true; + } + if (!hasGeometry) + return; + } + else if (niGeometry->recType == Nif::RC_NiLines) + { + 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(), reinterpret_cast(line.data()))); + } } handleNiGeometryData(geometry, niGeometryData, boundTextures, nifNode->name);