1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-19 19:53:53 +00:00
openmw/components/nif/node.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

785 lines
23 KiB
C++
Raw Normal View History

2022-07-21 11:51:34 +00:00
#include "node.hpp"
2023-07-09 10:14:27 +00:00
#include <cstdint>
2022-07-21 11:51:34 +00:00
#include <BulletCollision/CollisionShapes/btTriangleMesh.h>
#include <components/misc/convert.hpp>
2023-09-14 09:06:52 +00:00
#include <components/misc/strings/algorithm.hpp>
#include <components/resource/bulletshape.hpp>
2023-09-14 09:06:52 +00:00
2022-07-21 11:51:34 +00:00
#include "data.hpp"
#include "exception.hpp"
2022-07-21 11:51:34 +00:00
#include "physics.hpp"
#include "property.hpp"
namespace
{
void triBasedGeomToBtTriangleMesh(btTriangleMesh& mesh, const Nif::NiTriBasedGeomData& data)
{
// FIXME: copying vertices/indices individually is unreasonable
const std::vector<osg::Vec3f>& vertices = data.mVertices;
mesh.preallocateVertices(static_cast<int>(vertices.size()));
for (const osg::Vec3f& vertex : vertices)
mesh.findOrAddVertex(Misc::Convert::toBullet(vertex), false);
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);
}
}
}
}
2022-07-21 11:51:34 +00:00
namespace Nif
{
2023-09-14 09:06:52 +00:00
void BoundingVolume::read(NIFStream* nif)
2022-07-21 11:51:34 +00:00
{
2023-09-14 09:39:44 +00:00
nif->read(mType);
switch (mType)
2022-07-21 11:51:34 +00:00
{
case BASE_BV:
break;
case SPHERE_BV:
{
2023-09-14 09:06:52 +00:00
nif->read(mSphere);
2022-07-21 11:51:34 +00:00
break;
}
case BOX_BV:
{
2023-09-14 09:39:44 +00:00
nif->read(mBox.mCenter);
nif->read(mBox.mAxes);
nif->read(mBox.mExtents);
2022-07-21 11:51:34 +00:00
break;
}
case CAPSULE_BV:
{
2023-09-14 09:06:52 +00:00
nif->read(mCapsule.mCenter);
nif->read(mCapsule.mAxis);
nif->read(mCapsule.mExtent);
nif->read(mCapsule.mRadius);
2022-07-21 11:51:34 +00:00
break;
}
case LOZENGE_BV:
{
2023-09-14 09:06:52 +00:00
nif->read(mLozenge.mRadius);
2022-07-21 11:51:34 +00:00
if (nif->getVersion() >= NIFStream::generateVersion(4, 2, 1, 0))
{
2023-09-14 09:06:52 +00:00
nif->read(mLozenge.mExtent0);
nif->read(mLozenge.mExtent1);
2022-07-21 11:51:34 +00:00
}
2023-09-14 09:06:52 +00:00
nif->read(mLozenge.mCenter);
nif->read(mLozenge.mAxis0);
nif->read(mLozenge.mAxis1);
2022-07-21 11:51:34 +00:00
break;
}
case UNION_BV:
{
2023-09-14 09:06:52 +00:00
mChildren.resize(nif->get<uint32_t>());
for (BoundingVolume& child : mChildren)
2022-07-21 11:51:34 +00:00
child.read(nif);
break;
}
case HALFSPACE_BV:
{
2023-09-14 09:06:52 +00:00
mHalfSpace.mPlane = osg::Plane(nif->get<osg::Vec4f>());
2022-07-21 11:51:34 +00:00
if (nif->getVersion() >= NIFStream::generateVersion(4, 2, 1, 0))
2023-09-14 09:06:52 +00:00
nif->read(mHalfSpace.mOrigin);
2022-07-21 11:51:34 +00:00
break;
}
default:
{
throw Nif::Exception(
"Unhandled BoundingVolume type: " + std::to_string(mType), nif->getFile().getFilename());
2022-07-21 11:51:34 +00:00
}
}
}
void NiAVObject::read(NIFStream* nif)
2022-07-21 11:51:34 +00:00
{
NiObjectNET::read(nif);
2022-07-21 11:51:34 +00:00
if (nif->getBethVersion() <= 26)
mFlags = nif->get<uint16_t>();
else
nif->read(mFlags);
nif->read(mTransform.mTranslation);
nif->read(mTransform.mRotation);
nif->read(mTransform.mScale);
2022-07-21 11:51:34 +00:00
if (nif->getVersion() <= NIFStream::generateVersion(4, 2, 2, 0))
nif->read(mVelocity);
2022-07-21 11:51:34 +00:00
if (nif->getBethVersion() <= NIFFile::BethVersion::BETHVER_FO3)
readRecordList(nif, mProperties);
if (nif->getVersion() <= NIFStream::generateVersion(4, 2, 2, 0) && nif->get<bool>())
mBounds.read(nif);
2022-07-21 11:51:34 +00:00
if (nif->getVersion() >= NIFStream::generateVersion(10, 0, 1, 0))
mCollision.read(nif);
2022-07-21 11:51:34 +00:00
}
void NiAVObject::post(Reader& nif)
2022-07-21 11:51:34 +00:00
{
NiObjectNET::post(nif);
postRecordList(nif, mProperties);
mCollision.post(nif);
2022-07-21 11:51:34 +00:00
}
void NiAVObject::setBone()
2022-07-21 11:51:34 +00:00
{
mIsBone = true;
2022-07-21 11:51:34 +00:00
}
void NiNode::read(NIFStream* nif)
{
NiAVObject::read(nif);
readRecordList(nif, mChildren);
2022-07-21 11:51:34 +00:00
if (nif->getBethVersion() < NIFFile::BethVersion::BETHVER_FO4)
readRecordList(nif, mEffects);
2022-07-21 11:51:34 +00:00
// FIXME: stopgap solution until we figure out what Oblivion does if it does anything
if (nif->getVersion() > NIFFile::NIFVersion::VER_MW && nif->getVersion() < NIFFile::NIFVersion::VER_BGS)
return;
2022-07-21 11:51:34 +00:00
// Discard transformations for the root node, otherwise some meshes
// occasionally get wrong orientation. Only for NiNode-s for now, but
// can be expanded if needed.
// FIXME: if node 0 is *not* the only root node, this must not happen.
// FIXME: doing this here is awful.
// We want to do this on world scene graph level rather than local scene graph level.
if (recIndex == 0 && !Misc::StringUtils::ciEqual(mName, "bip01"))
2022-07-21 11:51:34 +00:00
{
mTransform = Nif::NiTransform::getIdentity();
2022-07-21 11:51:34 +00:00
}
}
void NiNode::post(Reader& nif)
2022-07-21 11:51:34 +00:00
{
NiAVObject::post(nif);
postRecordList(nif, mChildren);
postRecordList(nif, mEffects);
2022-07-21 11:51:34 +00:00
for (auto& child : mChildren)
2022-07-21 11:51:34 +00:00
{
// Why would a unique list of children contain empty refs?
if (!child.empty())
child->mParents.push_back(this);
2022-07-21 11:51:34 +00:00
}
}
void NiGeometry::MaterialData::read(NIFStream* nif)
{
2023-02-08 10:46:54 +00:00
if (nif->getVersion() < NIFStream::generateVersion(10, 0, 1, 0))
2022-07-21 11:51:34 +00:00
return;
if (nif->getVersion() >= NIFStream::generateVersion(20, 2, 0, 5))
2023-09-14 09:06:52 +00:00
mNames.resize(nif->get<uint32_t>());
else if (nif->getVersion() <= NIFStream::generateVersion(20, 1, 0, 3))
mNames.resize(nif->get<bool>());
nif->readVector(mNames, mNames.size());
nif->readVector(mExtra, mNames.size());
if (nif->getVersion() >= NIFStream::generateVersion(20, 2, 0, 5))
nif->read(mActive);
2022-07-21 11:51:34 +00:00
if (nif->getVersion() >= NIFFile::NIFVersion::VER_BGS)
2023-09-14 09:06:52 +00:00
nif->read(mNeedsUpdate);
2022-07-21 11:51:34 +00:00
}
void NiGeometry::read(NIFStream* nif)
{
NiAVObject::read(nif);
2023-09-14 09:06:52 +00:00
mData.read(nif);
if (nif->getVersion() >= NIFStream::generateVersion(3, 3, 0, 13))
mSkin.read(nif);
2023-09-14 09:06:52 +00:00
mMaterial.read(nif);
2022-07-21 11:51:34 +00:00
if (nif->getVersion() == NIFFile::NIFVersion::VER_BGS
&& nif->getBethVersion() > NIFFile::BethVersion::BETHVER_FO3)
{
mShaderProperty.read(nif);
mAlphaProperty.read(nif);
2022-07-21 11:51:34 +00:00
}
}
void NiGeometry::post(Reader& nif)
2022-07-21 11:51:34 +00:00
{
NiAVObject::post(nif);
2023-09-14 09:06:52 +00:00
mData.post(nif);
mSkin.post(nif);
mShaderProperty.post(nif);
mAlphaProperty.post(nif);
if (recType != RC_NiParticles && !mSkin.empty())
nif.setUseSkinning(true);
if (!mData.empty())
{
switch (recType)
{
case RC_NiTriShape:
case RC_BSLODTriShape:
2023-09-25 11:47:37 +00:00
case RC_BSSegmentedTriShape:
if (mData->recType != RC_NiTriShapeData)
mData = NiGeometryDataPtr(nullptr);
break;
case RC_NiTriStrips:
if (mData->recType != RC_NiTriStripsData)
mData = NiGeometryDataPtr(nullptr);
break;
case RC_NiParticles:
if (mData->recType != RC_NiParticlesData)
mData = NiGeometryDataPtr(nullptr);
break;
case RC_NiLines:
if (mData->recType != RC_NiLinesData)
mData = NiGeometryDataPtr(nullptr);
break;
default:
break;
}
}
2022-07-21 11:51:34 +00:00
}
std::unique_ptr<btCollisionShape> NiTriShape::getCollisionShape() const
{
if (mData.empty() || mData->mVertices.empty())
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());
const Nif::NiSkinPartition* partitions = 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>();
triBasedGeomToBtTriangleMesh(*mesh, *data);
for (const auto triangles : triangleLists)
trianglesToBtTriangleMesh(*mesh, *triangles);
for (const auto strips : stripsLists)
stripsToBtTriangleMesh(*mesh, *strips);
if (mesh->getNumTriangles() == 0)
return nullptr;
auto shape = std::make_unique<Resource::TriangleMeshShape>(mesh.get(), true);
std::ignore = mesh.release();
return shape;
}
std::unique_ptr<btCollisionShape> NiTriStrips::getCollisionShape() const
{
if (mData.empty() || mData->mVertices.empty())
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());
const Nif::NiSkinPartition* partitions = 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)
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)
return nullptr;
auto shape = std::make_unique<Resource::TriangleMeshShape>(mesh.get(), true);
std::ignore = mesh.release();
return shape;
}
std::unique_ptr<btCollisionShape> NiLines::getCollisionShape() const
{
return nullptr;
}
std::unique_ptr<btCollisionShape> NiParticles::getCollisionShape() const
{
return nullptr;
}
void BSSegmentedTriShape::SegmentData::read(NIFStream* nif)
{
nif->read(mFlags);
nif->read(mStartIndex);
nif->read(mNumTriangles);
}
2023-09-25 11:47:37 +00:00
void BSSegmentedTriShape::read(NIFStream* nif)
{
NiTriShape::read(nif);
mSegments.resize(nif->get<uint32_t>());
for (SegmentData& segment : mSegments)
segment.read(nif);
2023-09-25 11:47:37 +00:00
}
2022-07-21 11:51:34 +00:00
void BSLODTriShape::read(NIFStream* nif)
{
NiTriBasedGeom::read(nif);
2023-09-14 09:06:52 +00:00
nif->readArray(mLOD);
2022-07-21 11:51:34 +00:00
}
2023-09-14 09:06:52 +00:00
void NiCamera::read(NIFStream* nif)
2022-07-21 11:51:34 +00:00
{
2023-09-14 09:06:52 +00:00
NiAVObject::read(nif);
2022-07-21 11:51:34 +00:00
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0))
2023-09-14 09:06:52 +00:00
nif->read(mCameraFlags);
nif->read(mLeft);
nif->read(mRight);
nif->read(mTop);
nif->read(mBottom);
nif->read(mNearDist);
nif->read(mFarDist);
2022-07-21 11:51:34 +00:00
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0))
2023-09-14 09:06:52 +00:00
nif->read(mOrthographic);
nif->read(mVLeft);
nif->read(mVRight);
nif->read(mVTop);
nif->read(mVBottom);
nif->read(mLODAdjust);
mScene.read(nif);
nif->skip(4); // Unused
if (nif->getVersion() >= NIFStream::generateVersion(4, 2, 1, 0))
nif->skip(4); // Unused
2022-07-21 11:51:34 +00:00
}
2023-09-14 09:06:52 +00:00
void NiCamera::post(Reader& nif)
2022-07-21 11:51:34 +00:00
{
2023-09-14 09:06:52 +00:00
NiAVObject::post(nif);
2022-07-21 11:51:34 +00:00
2023-09-14 09:06:52 +00:00
mScene.post(nif);
2022-07-21 11:51:34 +00:00
}
void NiSwitchNode::read(NIFStream* nif)
{
NiNode::read(nif);
2023-09-14 09:06:52 +00:00
2022-07-21 11:51:34 +00:00
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0))
2023-09-14 09:29:49 +00:00
nif->read(mSwitchFlags);
nif->read(mInitialIndex);
2022-07-21 11:51:34 +00:00
}
void NiLODNode::read(NIFStream* nif)
{
NiSwitchNode::read(nif);
2023-09-14 09:06:52 +00:00
if (nif->getVersion() > NIFStream::generateVersion(10, 0, 1, 0))
2022-07-21 11:51:34 +00:00
{
nif->skip(4); // NiLODData, unsupported at the moment
return;
}
2023-09-14 09:06:52 +00:00
if (nif->getVersion() >= NIFFile::NIFVersion::VER_MW)
2023-09-14 09:29:49 +00:00
nif->read(mLODCenter);
2023-09-14 09:06:52 +00:00
2023-09-14 09:29:49 +00:00
mLODLevels.resize(nif->get<uint32_t>());
for (LODRange& level : mLODLevels)
2022-07-21 11:51:34 +00:00
{
2023-09-14 09:29:49 +00:00
nif->read(level.mMinRange);
nif->read(level.mMaxRange);
2022-07-21 11:51:34 +00:00
}
}
void NiFltAnimationNode::read(NIFStream* nif)
{
NiSwitchNode::read(nif);
2023-09-14 09:06:52 +00:00
nif->read(mDuration);
2022-07-21 11:51:34 +00:00
}
void NiSortAdjustNode::read(NIFStream* nif)
{
NiNode::read(nif);
2023-09-14 09:06:52 +00:00
mMode = static_cast<SortingMode>(nif->get<uint32_t>());
2022-07-21 11:51:34 +00:00
if (nif->getVersion() <= NIFStream::generateVersion(20, 0, 0, 3))
mSubSorter.read(nif);
}
void NiSortAdjustNode::post(Reader& nif)
2022-07-21 11:51:34 +00:00
{
NiNode::post(nif);
2023-09-14 09:06:52 +00:00
2022-07-21 11:51:34 +00:00
mSubSorter.post(nif);
}
2022-08-31 19:12:13 +00:00
void NiBillboardNode::read(NIFStream* nif)
{
NiNode::read(nif);
2023-09-14 09:06:52 +00:00
2022-08-31 19:12:13 +00:00
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0))
2023-09-14 09:06:52 +00:00
mMode = nif->get<uint16_t>() & 0x7;
2022-08-31 19:12:13 +00:00
else
mMode = (mFlags >> 5) & 0x3;
2022-08-31 19:12:13 +00:00
}
2023-02-08 11:34:10 +00:00
void NiDefaultAVObjectPalette::read(NIFStream* nif)
{
mScene.read(nif);
2023-09-14 09:06:52 +00:00
uint32_t numObjects;
nif->read(numObjects);
for (uint32_t i = 0; i < numObjects; i++)
2023-02-08 11:34:10 +00:00
mObjects[nif->getSizedString()].read(nif);
}
void NiDefaultAVObjectPalette::post(Reader& nif)
{
mScene.post(nif);
for (auto& object : mObjects)
object.second.post(nif);
}
2023-05-21 15:15:27 +00:00
void BSTreeNode::read(NIFStream* nif)
{
NiNode::read(nif);
2023-09-14 09:06:52 +00:00
2023-05-21 15:15:27 +00:00
readRecordList(nif, mBones1);
readRecordList(nif, mBones2);
}
void BSTreeNode::post(Reader& nif)
{
NiNode::post(nif);
2023-09-14 09:06:52 +00:00
2023-05-21 15:15:27 +00:00
postRecordList(nif, mBones1);
postRecordList(nif, mBones2);
}
2023-05-22 19:28:05 +00:00
void BSMultiBoundNode::read(NIFStream* nif)
{
NiNode::read(nif);
2023-09-14 09:06:52 +00:00
2023-05-22 19:28:05 +00:00
mMultiBound.read(nif);
if (nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_SKY)
mCullingType = static_cast<BSCPCullingType>(nif->get<uint32_t>());
2023-05-22 19:28:05 +00:00
}
void BSMultiBoundNode::post(Reader& nif)
{
NiNode::post(nif);
2023-09-14 09:06:52 +00:00
2023-05-22 19:28:05 +00:00
mMultiBound.post(nif);
}
2023-07-09 10:14:27 +00:00
void BSTriShape::read(NIFStream* nif)
{
NiAVObject::read(nif);
2023-07-09 10:14:27 +00:00
2023-09-14 09:06:52 +00:00
nif->read(mBoundingSphere);
if (nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_F76)
2023-07-26 02:36:52 +00:00
nif->readArray(mBoundMinMax);
2023-07-09 10:14:27 +00:00
mSkin.read(nif);
mShaderProperty.read(nif);
mAlphaProperty.read(nif);
mVertDesc.read(nif);
2023-09-14 09:06:52 +00:00
if (nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_FO4)
mTriangles.resize(nif->get<uint32_t>() * 3);
2023-07-09 10:14:27 +00:00
else
2023-09-14 09:06:52 +00:00
mTriangles.resize(nif->get<uint16_t>() * 3);
mVertData.resize(nif->get<uint16_t>());
2023-07-09 10:14:27 +00:00
nif->read(mDataSize);
2023-09-14 09:06:52 +00:00
if (mDataSize > 0)
2023-07-09 10:14:27 +00:00
{
for (auto& vertex : mVertData)
vertex.read(nif, mVertDesc.mFlags);
2023-09-14 09:06:52 +00:00
nif->readVector(mTriangles, mTriangles.size());
2023-07-09 10:14:27 +00:00
}
if (nif->getBethVersion() == NIFFile::BethVersion::BETHVER_SSE)
{
nif->read(mParticleDataSize);
if (mParticleDataSize > 0)
{
2023-09-14 09:06:52 +00:00
nif->readVector(mParticleVerts, mVertData.size() * 3);
nif->readVector(mParticleNormals, mVertData.size() * 3);
nif->readVector(mParticleTriangles, mTriangles.size());
2023-07-09 10:14:27 +00:00
}
}
}
void BSTriShape::post(Reader& nif)
{
NiAVObject::post(nif);
2023-09-14 09:06:52 +00:00
2023-07-09 10:14:27 +00:00
mSkin.post(nif);
mShaderProperty.post(nif);
mAlphaProperty.post(nif);
if (!mSkin.empty())
nif.setUseSkinning(true);
2023-07-09 10:14:27 +00:00
}
void BSDynamicTriShape::read(NIFStream* nif)
{
BSTriShape::read(nif);
nif->read(mDynamicDataSize);
// nifly style.
// Consider complaining if mDynamicDataSize * 16 != mVertData.size()?
nif->readVector(mDynamicData, mVertData.size());
}
void BSMeshLODTriShape::read(NIFStream* nif)
{
BSTriShape::read(nif);
nif->readArray(mLOD);
}
void BSSubIndexTriShape::SubSegment::read(NIFStream* nif)
{
nif->read(mStartIndex);
nif->read(mNumPrimitives);
nif->read(mArrayIndex);
nif->skip(4); // Unknown
}
void BSSubIndexTriShape::Segment::read(NIFStream* nif)
{
nif->read(mStartIndex);
nif->read(mNumPrimitives);
nif->read(mParentArrayIndex);
mSubSegments.resize(nif->get<uint32_t>());
for (SubSegment& subsegment : mSubSegments)
subsegment.read(nif);
}
void BSSubIndexTriShape::SubSegmentDataRecord::read(NIFStream* nif)
{
nif->read(mUserSlotID);
nif->read(mMaterial);
nif->readVector(mExtraData, nif->get<uint32_t>());
}
void BSSubIndexTriShape::SubSegmentData::read(NIFStream* nif)
{
uint32_t numArrayIndices;
nif->read(numArrayIndices);
mDataRecords.resize(nif->get<uint32_t>());
nif->readVector(mArrayIndices, numArrayIndices);
for (SubSegmentDataRecord& dataRecord : mDataRecords)
dataRecord.read(nif);
mSSFFile = nif->getSizedString(nif->get<uint16_t>());
}
void BSSubIndexTriShape::Segmentation::read(NIFStream* nif)
{
nif->read(mNumPrimitives);
mSegments.resize(nif->get<uint32_t>());
nif->read(mNumTotalSegments);
for (Segment& segment : mSegments)
segment.read(nif);
if (mSegments.size() < mNumTotalSegments)
mSubSegmentData.read(nif);
}
void BSSubIndexTriShape::read(NIFStream* nif)
{
BSTriShape::read(nif);
if (nif->getBethVersion() == NIFFile::BethVersion::BETHVER_SSE)
{
mSegments.resize(nif->get<uint32_t>());
for (BSSegmentedTriShape::SegmentData& segment : mSegments)
segment.read(nif);
}
else if (nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_FO4 && mDataSize > 0)
mSegmentation.read(nif);
}
2023-07-09 10:14:27 +00:00
void BSVertexDesc::read(NIFStream* nif)
{
uint64_t data;
nif->read(data);
mVertexDataSize = (data & 0xF) >> 0x00;
mDynamicVertexSize = (data & 0xF0) >> 0x04;
mUV1Offset = (data & 0xF00) >> 0x08;
mUV2Offset = (data & 0xF000) >> 0x0C;
mNormalOffset = (data & 0xF0000) >> 0x10;
mTangentOffset = (data & 0xF00000) >> 0x14;
mColorOffset = (data & 0xF000000) >> 0x18;
mSkinningDataOffset = (data & 0xF0000000) >> 0x1C;
mLandscapeDataOffset = (data & 0xF00000000) >> 0x20;
mEyeDataOffset = (data & 0xF000000000) >> 0x24;
mFlags = (data & 0xFFF00000000000) >> 0x2C;
2023-09-27 15:41:06 +00:00
if (nif->getBethVersion() == NIFFile::BethVersion::BETHVER_SSE)
mFlags |= BSVertexDesc::VertexAttribute::Full_Precision;
2023-07-09 10:14:27 +00:00
}
void BSVertexData::read(NIFStream* nif, uint16_t flags)
{
2023-09-27 13:28:04 +00:00
bool fullPrecision = flags & BSVertexDesc::VertexAttribute::Full_Precision;
bool hasVertex = flags & BSVertexDesc::VertexAttribute::Vertex;
bool hasTangent = flags & BSVertexDesc::VertexAttribute::Tangents;
bool hasUV = flags & BSVertexDesc::VertexAttribute::UVs;
bool hasNormal = flags & BSVertexDesc::VertexAttribute::Normals;
bool hasVertexColor = flags & BSVertexDesc::VertexAttribute::Vertex_Colors;
bool hasSkinData = flags & BSVertexDesc::VertexAttribute::Skinned;
bool hasEyeData = flags & BSVertexDesc::VertexAttribute::Eye_Data;
if (hasVertex)
2023-07-09 10:14:27 +00:00
{
if (fullPrecision)
nif->read(mVertex);
else
nif->readArray(mHalfVertex);
2023-07-09 10:14:27 +00:00
}
if (hasUV)
2023-07-09 10:14:27 +00:00
nif->readArray(mUV);
if (hasNormal)
2023-07-09 10:14:27 +00:00
{
nif->readArray(mNormal);
if (hasTangent)
nif->readArray(mTangent);
2023-07-09 10:14:27 +00:00
}
if (hasVertexColor)
nif->readArray(mVertColor);
2023-07-09 10:14:27 +00:00
if (hasSkinData)
2023-07-09 10:14:27 +00:00
{
nif->readArray(mBoneWeights);
nif->readArray(mBoneIndices);
}
if (hasEyeData)
2023-09-14 09:06:52 +00:00
nif->read(mEyeData);
2023-07-09 10:14:27 +00:00
}
2023-07-10 22:27:05 +00:00
void BSValueNode::read(NIFStream* nif)
{
NiNode::read(nif);
2023-09-14 09:06:52 +00:00
2023-07-10 22:27:05 +00:00
nif->read(mValue);
nif->read(mValueFlags);
}
void BSOrderedNode::read(NIFStream* nif)
{
NiNode::read(nif);
2023-09-14 09:06:52 +00:00
2023-07-10 22:27:05 +00:00
nif->read(mAlphaSortBound);
nif->read(mStaticBound);
}
2023-07-20 01:04:49 +00:00
void BSRangeNode::read(NIFStream* nif)
{
NiNode::read(nif);
2023-09-14 09:06:52 +00:00
2023-07-20 01:04:49 +00:00
nif->read(mMin);
nif->read(mMax);
nif->read(mCurrent);
}
2023-09-14 09:06:52 +00:00
2024-09-18 19:49:14 +00:00
void BSResourceID::read(NIFStream* nif)
{
nif->read(mFileHash);
nif->readArray(mExtension);
nif->read(mDirectoryHash);
}
void BSDistantObjectInstance::read(NIFStream* nif)
{
mResourceID.read(nif);
nif->skip(12 * nif->get<uint32_t>()); // Unknown data
mTransforms.resize(nif->get<uint32_t>());
for (osg::Matrixf& transform : mTransforms)
{
std::array<float, 16> mat;
nif->readArray(mat);
transform.set(mat.data());
}
}
void BSShaderTextureArray::read(NIFStream* nif)
{
nif->skip(1); // Unknown
mTextureArrays.resize(nif->get<uint32_t>());
for (std::vector<std::string>& textureArray : mTextureArrays)
nif->getSizedStrings(textureArray, nif->get<uint32_t>());
}
void BSDistantObjectInstancedNode::read(NIFStream* nif)
{
BSMultiBoundNode::read(nif);
mInstances.resize(nif->get<uint32_t>());
for (BSDistantObjectInstance& instance : mInstances)
instance.read(nif);
for (BSShaderTextureArray& textureArray : mShaderTextureArrays)
textureArray.read(nif);
}
2022-07-21 11:51:34 +00:00
}