Load BSTriShape NIF nodes

revert-6246b479
alekulyn 1 year ago committed by psi29a
parent fb7ba40385
commit 74aa7b947a

@ -0,0 +1,11 @@
#ifndef OPENMW_COMPONENTS_MISC_FLOAT16_HPP
#define OPENMW_COMPONENTS_MISC_FLOAT16_HPP
#include <cstdint>
namespace Misc
{
using float16_t = std::uint16_t;
}
#endif

@ -372,9 +372,21 @@ namespace Nif
void NiSkinPartition::read(NIFStream* nif) void NiSkinPartition::read(NIFStream* nif)
{ {
unsigned int num = nif->getUInt(); nif->read(mPartitionNum);
data.resize(num); mPartitions.resize(mPartitionNum);
for (auto& partition : data)
if (nif->getBethVersion() == NIFFile::BethVersion::BETHVER_SSE)
{
nif->read(mDataSize);
nif->read(mVertexSize);
mVertexDesc.read(nif);
mVertexData.resize(mDataSize / mVertexSize);
for (auto& vertexData : mVertexData)
vertexData.read(nif, mVertexDesc.mFlags);
}
for (auto& partition : mPartitions)
partition.read(nif); partition.read(nif);
} }
@ -426,6 +438,12 @@ namespace Nif
nif->getChar(); // LOD level nif->getChar(); // LOD level
nif->getBoolean(); // Global VB nif->getBoolean(); // Global VB
} }
if (nif->getBethVersion() == NIFFile::BethVersion::BETHVER_SSE)
{
mVertexDesc.read(nif);
nif->readVector(trueTriangles, numTriangles * 3);
}
} }
void NiMorphData::read(NIFStream* nif) void NiMorphData::read(NIFStream* nif)

@ -27,6 +27,7 @@
#include "nifkey.hpp" #include "nifkey.hpp"
#include "niftypes.hpp" // Transformation #include "niftypes.hpp" // Transformation
#include "recordptr.hpp" #include "recordptr.hpp"
#include <components/nif/node.hpp>
namespace Nif namespace Nif
{ {
@ -218,10 +219,18 @@ namespace Nif
std::vector<float> weights; std::vector<float> weights;
std::vector<std::vector<unsigned short>> strips; std::vector<std::vector<unsigned short>> strips;
std::vector<unsigned short> triangles; std::vector<unsigned short> triangles;
std::vector<unsigned short> trueTriangles;
std::vector<char> boneIndices; std::vector<char> boneIndices;
BSVertexDesc mVertexDesc;
void read(NIFStream* nif); void read(NIFStream* nif);
}; };
std::vector<Partition> data; unsigned int mPartitionNum;
std::vector<Partition> mPartitions;
unsigned int mDataSize;
unsigned int mVertexSize;
BSVertexDesc mVertexDesc;
std::vector<BSVertexData> mVertexData;
void read(NIFStream* nif) override; void read(NIFStream* nif) override;
}; };

@ -191,6 +191,7 @@ namespace Nif
{ "BSMultiBoundOBB", &construct<BSMultiBoundOBB, RC_BSMultiBoundOBB> }, { "BSMultiBoundOBB", &construct<BSMultiBoundOBB, RC_BSMultiBoundOBB> },
{ "BSMultiBoundSphere", &construct<BSMultiBoundSphere, RC_BSMultiBoundSphere> }, { "BSMultiBoundSphere", &construct<BSMultiBoundSphere, RC_BSMultiBoundSphere> },
{ "BSInvMarker", &construct<BSInvMarker, RC_BSInvMarker> }, { "BSInvMarker", &construct<BSInvMarker, RC_BSInvMarker> },
{ "BSTriShape", &construct<BSTriShape, RC_BSTriShape> },
}; };
} }

@ -28,7 +28,9 @@ namespace Nif
{ {
BETHVER_FO3 = 34, // Fallout 3 BETHVER_FO3 = 34, // Fallout 3
BETHVER_SKY = 83, // Skyrim BETHVER_SKY = 83, // Skyrim
BETHVER_FO4 = 130 // Fallout 4 BETHVER_SSE = 100, // Skyrim SE
BETHVER_FO4 = 130, // Fallout 4
BETHVER_F76 = 155 // Fallout 76
}; };
/// File version, user version, Bethesda version /// File version, user version, Bethesda version

@ -12,6 +12,7 @@
#include <components/files/istreamptr.hpp> #include <components/files/istreamptr.hpp>
#include <components/misc/endianness.hpp> #include <components/misc/endianness.hpp>
#include <components/misc/float16.hpp>
#include <osg/Quat> #include <osg/Quat>
#include <osg/Vec3f> #include <osg/Vec3f>
@ -24,10 +25,16 @@ namespace Nif
class Reader; class Reader;
template <class T>
struct is_arithmetic
: std::integral_constant<bool, std::is_arithmetic_v<T> || std::is_same<T, Misc::float16_t>::value>
{
};
template <std::size_t numInstances, typename T> template <std::size_t numInstances, typename T>
inline void readLittleEndianBufferOfType(Files::IStreamPtr& pIStream, T* dest) inline void readLittleEndianBufferOfType(Files::IStreamPtr& pIStream, T* dest)
{ {
static_assert(std::is_arithmetic_v<T>, "Buffer element type is not arithmetic"); static_assert(is_arithmetic<T>(), "Buffer element type is not arithmetic");
pIStream->read((char*)dest, numInstances * sizeof(T)); pIStream->read((char*)dest, numInstances * sizeof(T));
if (pIStream->bad()) if (pIStream->bad())
throw std::runtime_error("Failed to read little endian typed (" + std::string(typeid(T).name()) throw std::runtime_error("Failed to read little endian typed (" + std::string(typeid(T).name())
@ -40,7 +47,7 @@ namespace Nif
template <typename T> template <typename T>
inline void readLittleEndianDynamicBufferOfType(Files::IStreamPtr& pIStream, T* dest, std::size_t numInstances) inline void readLittleEndianDynamicBufferOfType(Files::IStreamPtr& pIStream, T* dest, std::size_t numInstances)
{ {
static_assert(std::is_arithmetic_v<T>, "Buffer element type is not arithmetic"); static_assert(is_arithmetic<T>(), "Buffer element type is not arithmetic");
pIStream->read((char*)dest, numInstances * sizeof(T)); pIStream->read((char*)dest, numInstances * sizeof(T));
if (pIStream->bad()) if (pIStream->bad())
throw std::runtime_error( throw std::runtime_error(
@ -81,6 +88,8 @@ namespace Nif
data = readLittleEndianType<T>(inp); data = readLittleEndianType<T>(inp);
} }
void read(osg::Vec3f& data) { readLittleEndianBufferOfType<3, float>(inp, data._v); }
template <class T> template <class T>
T get() T get()
{ {
@ -125,6 +134,7 @@ namespace Nif
return vec; return vec;
} }
// DEPRECATED: Use read() whenever relevant
osg::Vec3f getVector3() osg::Vec3f getVector3()
{ {
osg::Vec3f vec; osg::Vec3f vec;

@ -1,6 +1,7 @@
#include "node.hpp" #include "node.hpp"
#include <components/misc/strings/algorithm.hpp> #include <components/misc/strings/algorithm.hpp>
#include <cstdint>
#include "data.hpp" #include "data.hpp"
#include "exception.hpp" #include "exception.hpp"
@ -18,8 +19,7 @@ namespace Nif
break; break;
case SPHERE_BV: case SPHERE_BV:
{ {
sphere.center = nif->getVector3(); sphere.read(nif);
sphere.radius = nif->getFloat();
break; break;
} }
case BOX_BV: case BOX_BV:
@ -334,4 +334,153 @@ namespace Nif
NiNode::post(nif); NiNode::post(nif);
mMultiBound.post(nif); mMultiBound.post(nif);
} }
void BSTriShape::read(NIFStream* nif)
{
Node::read(nif);
mBoundingSphere.read(nif);
if (nif->getBethVersion() == NIFFile::BethVersion::BETHVER_F76)
{
nif->readVector(mBoundMinMax, 6);
}
mSkin.read(nif);
mShaderProperty.read(nif);
mAlphaProperty.read(nif);
mVertDesc.read(nif);
unsigned int triNum;
if (nif->getBethVersion() < NIFFile::BethVersion::BETHVER_FO4)
{
triNum = nif->get<unsigned short>();
}
else
{
nif->read(triNum);
}
unsigned short vertNum;
nif->read(vertNum);
nif->read(mDataSize);
if (nif->getBethVersion() == NIFFile::BethVersion::BETHVER_SSE)
{
mVertData.resize(vertNum);
for (auto& vertex : mVertData)
vertex.read(nif, mVertDesc.mFlags);
}
else if (nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_FO4)
{
throw Nif::Exception("FO4 BSTriShape is not supported yet: ", nif->getFile().getFilename());
}
if (mDataSize > 0)
{
mTriangles.resize(triNum * 3);
nif->readVector(mTriangles, triNum * 3);
}
if (nif->getBethVersion() == NIFFile::BethVersion::BETHVER_SSE)
{
nif->read(mParticleDataSize);
if (mParticleDataSize > 0)
{
throw Nif::Exception("Unhandled Particle Data in BSTriShape: ", nif->getFile().getFilename());
}
}
}
void BSTriShape::post(Reader& nif)
{
Node::post(nif);
mSkin.post(nif);
mShaderProperty.post(nif);
mAlphaProperty.post(nif);
}
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;
}
void NiBoundingVolume::NiSphereBV::read(NIFStream* nif)
{
nif->read(center);
nif->read(radius);
}
void BSVertexData::read(NIFStream* nif, uint16_t flags)
{
uint16_t vertexFlag = flags & BSVertexDesc::VertexAttribute::Vertex;
uint16_t tangentsFlag = flags & BSVertexDesc::VertexAttribute::Tangents;
uint16_t UVsFlag = flags & BSVertexDesc::VertexAttribute::UVs;
uint16_t normalsFlag = flags & BSVertexDesc::VertexAttribute::Normals;
if (vertexFlag == BSVertexDesc::VertexAttribute::Vertex)
{
nif->read(mVertex);
}
if ((vertexFlag | tangentsFlag)
== (BSVertexDesc::VertexAttribute::Vertex | BSVertexDesc::VertexAttribute::Tangents))
{
nif->read(mBitangentX);
}
if ((vertexFlag | tangentsFlag) == BSVertexDesc::VertexAttribute::Vertex)
{
nif->read(mUnusedW);
}
if (UVsFlag == BSVertexDesc::VertexAttribute::UVs)
{
nif->readArray(mUV);
}
if (normalsFlag)
{
nif->readArray(mNormal);
nif->read(mBitangentY);
}
if ((normalsFlag | tangentsFlag)
== (BSVertexDesc::VertexAttribute::Normals | BSVertexDesc::VertexAttribute::Tangents))
{
nif->readArray(mTangent);
nif->read(mBitangentZ);
}
if (flags & BSVertexDesc::VertexAttribute::Vertex_Colors)
{
nif->readArray(mVertColors);
}
if (flags & BSVertexDesc::VertexAttribute::Skinned)
{
nif->readArray(mBoneWeights);
nif->readArray(mBoneIndices);
}
if (flags & BSVertexDesc::VertexAttribute::Eye_Data)
{
throw Nif::Exception("Unhandled Eye Data in BSTriShape: ", nif->getFile().getFilename());
nif->read(mEyeData);
}
}
} }

@ -1,6 +1,7 @@
#ifndef OPENMW_COMPONENTS_NIF_NODE_HPP #ifndef OPENMW_COMPONENTS_NIF_NODE_HPP
#define OPENMW_COMPONENTS_NIF_NODE_HPP #define OPENMW_COMPONENTS_NIF_NODE_HPP
#include <array>
#include <unordered_map> #include <unordered_map>
#include <osg/Plane> #include <osg/Plane>
@ -29,6 +30,7 @@ namespace Nif
{ {
osg::Vec3f center; osg::Vec3f center;
float radius{ 0.f }; float radius{ 0.f };
void read(NIFStream* nif);
}; };
struct NiBoxBV struct NiBoxBV
@ -300,5 +302,80 @@ namespace Nif
void post(Reader& nif) override; void post(Reader& nif) override;
}; };
struct BSVertexDesc
{
unsigned char mVertexDataSize;
unsigned char mDynamicVertexSize;
unsigned char mUV1Offset;
unsigned char mUV2Offset;
unsigned char mNormalOffset;
unsigned char mTangentOffset;
unsigned char mColorOffset;
unsigned char mSkinningDataOffset;
unsigned char mLandscapeDataOffset;
unsigned char mEyeDataOffset;
unsigned short mFlags;
enum VertexAttribute
{
Vertex = 0x0001,
UVs = 0x0002,
UVs_2 = 0x0004,
Normals = 0x0008,
Tangents = 0x0010,
Vertex_Colors = 0x0020,
Skinned = 0x0040,
Land_Data = 0x0080,
Eye_Data = 0x0100,
Instance = 0x0200,
Full_Precision = 0x0400,
};
void read(NIFStream* nif);
};
struct BSVertexData
{
osg::Vec3f mVertex;
float mBitangentX;
unsigned int mUnusedW;
std::array<Misc::float16_t, 2> mUV;
std::array<char, 3> mNormal;
char mBitangentY;
std::array<char, 3> mTangent;
char mBitangentZ;
std::array<char, 4> mVertColors;
std::array<Misc::float16_t, 4> mBoneWeights;
std::array<char, 4> mBoneIndices;
float mEyeData;
void read(NIFStream* nif, uint16_t flags);
};
struct BSTriShape : Node
{
NiBoundingVolume::NiSphereBV mBoundingSphere;
std::vector<float> mBoundMinMax;
NiSkinInstancePtr mSkin;
BSShaderPropertyPtr mShaderProperty;
NiAlphaPropertyPtr mAlphaProperty;
BSVertexDesc mVertDesc;
unsigned int mDataSize;
unsigned int mParticleDataSize;
std::vector<BSVertexData> mVertData;
std::vector<unsigned short> mTriangles;
std::vector<unsigned short> mParticleTriangles;
std::vector<osg::Vec3f> mParticleVerts;
std::vector<osg::Vec3f> mParticleNormals;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
} // Namespace } // Namespace
#endif #endif

@ -163,6 +163,7 @@ namespace Nif
RC_BSMultiBoundOBB, RC_BSMultiBoundOBB,
RC_BSMultiBoundSphere, RC_BSMultiBoundSphere,
RC_BSInvMarker, RC_BSInvMarker,
RC_BSTriShape,
}; };
/// Base class for all records /// Base class for all records

Loading…
Cancel
Save