BulletNifLoader: Handle NiSkinPartition

Add NiSkinPartition recovery helper method
macos_ci_fix
Alexei Kotov 1 year ago
parent 6e7661ca87
commit b93291840e

@ -53,6 +53,7 @@ namespace Nif::Testing
{ {
value.mData = NiSkinDataPtr(nullptr); value.mData = NiSkinDataPtr(nullptr);
value.mRoot = NiAVObjectPtr(nullptr); value.mRoot = NiAVObjectPtr(nullptr);
value.mPartitions = NiSkinPartitionPtr(nullptr);
} }
inline void init(NiTimeController& value) inline void init(NiTimeController& value)

@ -290,6 +290,17 @@ namespace Nif
} }
} }
const Nif::NiSkinPartition* NiSkinInstance::getPartitions() const
{
const Nif::NiSkinPartition* partitions = nullptr;
if (!mPartitions.empty())
partitions = mPartitions.getPtr();
else if (!mData.empty() && !mData->mPartitions.empty())
partitions = mData->mPartitions.getPtr();
return partitions;
}
void BSDismemberSkinInstance::read(NIFStream* nif) void BSDismemberSkinInstance::read(NIFStream* nif)
{ {
NiSkinInstance::read(nif); NiSkinInstance::read(nif);

@ -208,6 +208,8 @@ namespace Nif
void read(NIFStream* nif) override; void read(NIFStream* nif) override;
void post(Reader& nif) override; void post(Reader& nif) override;
const Nif::NiSkinPartition* getPartitions() const;
}; };
struct BSDismemberSkinInstance : public NiSkinInstance struct BSDismemberSkinInstance : public NiSkinInstance

@ -27,6 +27,37 @@ namespace
mesh.preallocateIndices(static_cast<int>(data.mNumTriangles) * 3); mesh.preallocateIndices(static_cast<int>(data.mNumTriangles) * 3);
} }
void trianglesToBtTriangleMesh(btTriangleMesh& mesh, const std::vector<unsigned short>& triangles)
{
for (std::size_t i = 0; i < triangles.size(); i += 3)
mesh.addTriangleIndices(triangles[i + 0], triangles[i + 1], triangles[i + 2]);
}
void stripsToBtTriangleMesh(btTriangleMesh& mesh, const std::vector<std::vector<unsigned short>>& strips)
{
for (const auto& strip : strips)
{
if (strip.size() < 3)
continue;
unsigned short a;
unsigned short b = strip[0];
unsigned short c = strip[1];
for (size_t i = 2; i < strip.size(); i++)
{
a = b;
b = c;
c = strip[i];
if (a == b || b == c || a == c)
continue;
if (i % 2 == 0)
mesh.addTriangleIndices(a, b, c);
else
mesh.addTriangleIndices(a, c, b);
}
}
}
} }
namespace Nif namespace Nif
@ -243,15 +274,33 @@ namespace Nif
if (mData.empty() || mData->mVertices.empty()) if (mData.empty() || mData->mVertices.empty())
return nullptr; return nullptr;
std::vector<const std::vector<unsigned short>*> triangleLists;
std::vector<const std::vector<std::vector<unsigned short>>*> stripsLists;
auto data = static_cast<const NiTriShapeData*>(mData.getPtr()); auto data = static_cast<const NiTriShapeData*>(mData.getPtr());
if (data->mNumTriangles == 0 || data->mTriangles.empty()) const Nif::NiSkinPartition* partitions = nullptr;
return nullptr; if (!mSkin.empty())
partitions = mSkin->getPartitions();
if (partitions)
{
triangleLists.reserve(partitions->mPartitions.size());
stripsLists.reserve(partitions->mPartitions.size());
for (auto& partition : partitions->mPartitions)
{
triangleLists.push_back(&partition.mTrueTriangles);
stripsLists.push_back(&partition.mTrueStrips);
}
}
else if (data->mNumTriangles != 0)
triangleLists.push_back(&data->mTriangles);
// This makes a perhaps dangerous assumption that NiSkinPartition will never have more than 65536 triangles.
auto mesh = std::make_unique<btTriangleMesh>(); auto mesh = std::make_unique<btTriangleMesh>();
triBasedGeomToBtTriangleMesh(*mesh, *data); triBasedGeomToBtTriangleMesh(*mesh, *data);
const std::vector<unsigned short>& triangles = data->mTriangles; for (const auto triangles : triangleLists)
for (std::size_t i = 0; i < triangles.size(); i += 3) trianglesToBtTriangleMesh(*mesh, *triangles);
mesh->addTriangleIndices(triangles[i + 0], triangles[i + 1], triangles[i + 2]); for (const auto strips : stripsLists)
stripsToBtTriangleMesh(*mesh, *strips);
if (mesh->getNumTriangles() == 0) if (mesh->getNumTriangles() == 0)
return nullptr; return nullptr;
@ -267,33 +316,32 @@ namespace Nif
if (mData.empty() || mData->mVertices.empty()) if (mData.empty() || mData->mVertices.empty())
return nullptr; return nullptr;
std::vector<const std::vector<unsigned short>*> triangleLists;
std::vector<const std::vector<std::vector<unsigned short>>*> stripsLists;
auto data = static_cast<const NiTriStripsData*>(mData.getPtr()); auto data = static_cast<const NiTriStripsData*>(mData.getPtr());
if (data->mNumTriangles == 0 || data->mStrips.empty()) const Nif::NiSkinPartition* partitions = nullptr;
return nullptr; if (!mSkin.empty())
partitions = mSkin->getPartitions();
auto mesh = std::make_unique<btTriangleMesh>(); if (partitions)
triBasedGeomToBtTriangleMesh(*mesh, *data);
for (const std::vector<unsigned short>& strip : data->mStrips)
{ {
if (strip.size() < 3) triangleLists.reserve(partitions->mPartitions.size());
continue; stripsLists.reserve(partitions->mPartitions.size());
for (auto& partition : partitions->mPartitions)
unsigned short a;
unsigned short b = strip[0];
unsigned short c = strip[1];
for (size_t i = 2; i < strip.size(); i++)
{ {
a = b; triangleLists.push_back(&partition.mTrueTriangles);
b = c; stripsLists.push_back(&partition.mTrueStrips);
c = strip[i];
if (a == b || b == c || a == c)
continue;
if (i % 2 == 0)
mesh->addTriangleIndices(a, b, c);
else
mesh->addTriangleIndices(a, c, b);
} }
} }
else if (data->mNumTriangles != 0)
stripsLists.push_back(&data->mStrips);
auto mesh = std::make_unique<btTriangleMesh>();
triBasedGeomToBtTriangleMesh(*mesh, *data);
for (const auto triangles : triangleLists)
trianglesToBtTriangleMesh(*mesh, *triangles);
for (const auto strips : stripsLists)
stripsToBtTriangleMesh(*mesh, *strips);
if (mesh->getNumTriangles() == 0) if (mesh->getNumTriangles() == 0)
return nullptr; return nullptr;

@ -277,7 +277,6 @@ namespace NifBullet
if (!niGeometry.mSkin.empty()) if (!niGeometry.mSkin.empty())
args.mAnimated = false; args.mAnimated = false;
// TODO: handle NiSkinPartition
std::unique_ptr<btCollisionShape> childShape = niGeometry.getCollisionShape(); std::unique_ptr<btCollisionShape> childShape = niGeometry.getCollisionShape();
if (childShape == nullptr) if (childShape == nullptr)

@ -1381,17 +1381,7 @@ namespace NifOsg
if (!niGeometry->mSkin.empty()) if (!niGeometry->mSkin.empty())
{ {
const Nif::NiSkinInstance* skin = niGeometry->mSkin.getPtr(); const Nif::NiSkinInstance* skin = niGeometry->mSkin.getPtr();
const Nif::NiSkinData* data = nullptr; const Nif::NiSkinPartition* partitions = skin->getPartitions();
const Nif::NiSkinPartition* partitions = nullptr;
if (!skin->mData.empty())
{
data = skin->mData.getPtr();
if (!data->mPartitions.empty())
partitions = data->mPartitions.getPtr();
}
if (!partitions && !skin->mPartitions.empty())
partitions = skin->mPartitions.getPtr();
hasPartitions = partitions != nullptr; hasPartitions = partitions != nullptr;
if (hasPartitions) if (hasPartitions)
{ {

Loading…
Cancel
Save