1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-10 03:39:55 +00:00

Merge branch 'nif' into 'master'

Modernize NIF loader, part 3

See merge request OpenMW/openmw!3418
This commit is contained in:
psi29a 2023-09-12 08:34:46 +00:00
commit 42b77342c5
27 changed files with 606 additions and 644 deletions

View File

@ -6,9 +6,9 @@
namespace Nif::Testing
{
inline void init(Transformation& value)
inline void init(NiTransform& value)
{
value = Transformation::getIdentity();
value = NiTransform::getIdentity();
}
inline void init(Extra& value)
@ -16,25 +16,23 @@ namespace Nif::Testing
value.mNext = ExtraPtr(nullptr);
}
inline void init(Named& value)
inline void init(NiObjectNET& value)
{
value.extra = ExtraPtr(nullptr);
value.extralist = ExtraList();
value.controller = ControllerPtr(nullptr);
value.mExtra = ExtraPtr(nullptr);
value.mExtraList = ExtraList();
value.mController = ControllerPtr(nullptr);
}
inline void init(Node& value)
inline void init(NiAVObject& value)
{
init(static_cast<Named&>(value));
value.flags = 0;
init(value.trafo);
value.hasBounds = false;
value.isBone = false;
init(static_cast<NiObjectNET&>(value));
value.mFlags = 0;
init(value.mTransform);
}
inline void init(NiGeometry& value)
{
init(static_cast<Node&>(value));
init(static_cast<NiAVObject&>(value));
value.data = NiGeometryDataPtr(nullptr);
value.skin = NiSkinInstancePtr(nullptr);
}
@ -54,7 +52,7 @@ namespace Nif::Testing
inline void init(NiSkinInstance& value)
{
value.mData = NiSkinDataPtr(nullptr);
value.mRoot = NodePtr(nullptr);
value.mRoot = NiAVObjectPtr(nullptr);
}
inline void init(Controller& value)
@ -65,7 +63,7 @@ namespace Nif::Testing
value.phase = 0;
value.timeStart = 0;
value.timeStop = 0;
value.target = NamedPtr(nullptr);
value.target = NiObjectNETPtr(nullptr);
}
}

View File

@ -274,19 +274,19 @@ namespace
using namespace Nif::Testing;
using NifBullet::BulletNifLoader;
void copy(const btTransform& src, Nif::Transformation& dst)
void copy(const btTransform& src, Nif::NiTransform& dst)
{
dst.pos = osg::Vec3f(src.getOrigin().x(), src.getOrigin().y(), src.getOrigin().z());
dst.mTranslation = osg::Vec3f(src.getOrigin().x(), src.getOrigin().y(), src.getOrigin().z());
for (int row = 0; row < 3; ++row)
for (int column = 0; column < 3; ++column)
dst.rotation.mValues[row][column] = src.getBasis().getRow(row)[column];
dst.mRotation.mValues[row][column] = src.getBasis().getRow(row)[column];
}
struct TestBulletNifLoader : Test
{
BulletNifLoader mLoader;
Nif::Node mNode;
Nif::Node mNode2;
Nif::NiAVObject mNode;
Nif::NiAVObject mNode2;
Nif::NiNode mNiNode;
Nif::NiNode mNiNode2;
Nif::NiNode mNiNode3;
@ -414,11 +414,10 @@ namespace
TEST_F(
TestBulletNifLoader, for_root_nif_node_with_bounding_box_should_return_shape_with_compound_shape_and_box_inside)
{
mNode.hasBounds = true;
mNode.flags |= Nif::Node::Flag_BBoxCollision;
mNode.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
mNode.bounds.box.extents = osg::Vec3f(1, 2, 3);
mNode.bounds.box.center = osg::Vec3f(-1, -2, -3);
mNode.mFlags |= Nif::NiAVObject::Flag_BBoxCollision;
mNode.mBounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
mNode.mBounds.box.extents = osg::Vec3f(1, 2, 3);
mNode.mBounds.box.center = osg::Vec3f(-1, -2, -3);
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNode);
@ -439,13 +438,12 @@ namespace
TEST_F(TestBulletNifLoader, for_child_nif_node_with_bounding_box)
{
mNode.hasBounds = true;
mNode.flags |= Nif::Node::Flag_BBoxCollision;
mNode.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
mNode.bounds.box.extents = osg::Vec3f(1, 2, 3);
mNode.bounds.box.center = osg::Vec3f(-1, -2, -3);
mNode.parents.push_back(&mNiNode);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNode) }));
mNode.mFlags |= Nif::NiAVObject::Flag_BBoxCollision;
mNode.mBounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
mNode.mBounds.box.extents = osg::Vec3f(1, 2, 3);
mNode.mBounds.box.center = osg::Vec3f(-1, -2, -3);
mNode.mParents.push_back(&mNiNode);
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNode) };
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNiNode);
@ -467,18 +465,16 @@ namespace
TEST_F(TestBulletNifLoader,
for_root_and_child_nif_node_with_bounding_box_but_root_without_flag_should_use_child_bounds)
{
mNode.hasBounds = true;
mNode.flags |= Nif::Node::Flag_BBoxCollision;
mNode.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
mNode.bounds.box.extents = osg::Vec3f(1, 2, 3);
mNode.bounds.box.center = osg::Vec3f(-1, -2, -3);
mNode.parents.push_back(&mNiNode);
mNode.mFlags |= Nif::NiAVObject::Flag_BBoxCollision;
mNode.mBounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
mNode.mBounds.box.extents = osg::Vec3f(1, 2, 3);
mNode.mBounds.box.center = osg::Vec3f(-1, -2, -3);
mNode.mParents.push_back(&mNiNode);
mNiNode.hasBounds = true;
mNiNode.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
mNiNode.bounds.box.extents = osg::Vec3f(4, 5, 6);
mNiNode.bounds.box.center = osg::Vec3f(-4, -5, -6);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNode) }));
mNiNode.mBounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
mNiNode.mBounds.box.extents = osg::Vec3f(4, 5, 6);
mNiNode.mBounds.box.center = osg::Vec3f(-4, -5, -6);
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNode) };
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNiNode);
@ -500,24 +496,21 @@ namespace
TEST_F(TestBulletNifLoader,
for_root_and_two_children_where_both_with_bounds_but_only_first_with_flag_should_use_first_bounds)
{
mNode.hasBounds = true;
mNode.flags |= Nif::Node::Flag_BBoxCollision;
mNode.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
mNode.bounds.box.extents = osg::Vec3f(1, 2, 3);
mNode.bounds.box.center = osg::Vec3f(-1, -2, -3);
mNode.parents.push_back(&mNiNode);
mNode.mFlags |= Nif::NiAVObject::Flag_BBoxCollision;
mNode.mBounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
mNode.mBounds.box.extents = osg::Vec3f(1, 2, 3);
mNode.mBounds.box.center = osg::Vec3f(-1, -2, -3);
mNode.mParents.push_back(&mNiNode);
mNode2.hasBounds = true;
mNode2.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
mNode2.bounds.box.extents = osg::Vec3f(4, 5, 6);
mNode2.bounds.box.center = osg::Vec3f(-4, -5, -6);
mNode2.parents.push_back(&mNiNode);
mNode2.mBounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
mNode2.mBounds.box.extents = osg::Vec3f(4, 5, 6);
mNode2.mBounds.box.center = osg::Vec3f(-4, -5, -6);
mNode2.mParents.push_back(&mNiNode);
mNiNode.hasBounds = true;
mNiNode.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
mNiNode.bounds.box.extents = osg::Vec3f(7, 8, 9);
mNiNode.bounds.box.center = osg::Vec3f(-7, -8, -9);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNode), Nif::NodePtr(&mNode2) }));
mNiNode.mBounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
mNiNode.mBounds.box.extents = osg::Vec3f(7, 8, 9);
mNiNode.mBounds.box.center = osg::Vec3f(-7, -8, -9);
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNode), Nif::NiAVObjectPtr(&mNode2) };
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNiNode);
@ -539,24 +532,21 @@ namespace
TEST_F(TestBulletNifLoader,
for_root_and_two_children_where_both_with_bounds_but_only_second_with_flag_should_use_second_bounds)
{
mNode.hasBounds = true;
mNode.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
mNode.bounds.box.extents = osg::Vec3f(1, 2, 3);
mNode.bounds.box.center = osg::Vec3f(-1, -2, -3);
mNode.parents.push_back(&mNiNode);
mNode.mBounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
mNode.mBounds.box.extents = osg::Vec3f(1, 2, 3);
mNode.mBounds.box.center = osg::Vec3f(-1, -2, -3);
mNode.mParents.push_back(&mNiNode);
mNode2.hasBounds = true;
mNode2.flags |= Nif::Node::Flag_BBoxCollision;
mNode2.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
mNode2.bounds.box.extents = osg::Vec3f(4, 5, 6);
mNode2.bounds.box.center = osg::Vec3f(-4, -5, -6);
mNode2.parents.push_back(&mNiNode);
mNode2.mFlags |= Nif::NiAVObject::Flag_BBoxCollision;
mNode2.mBounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
mNode2.mBounds.box.extents = osg::Vec3f(4, 5, 6);
mNode2.mBounds.box.center = osg::Vec3f(-4, -5, -6);
mNode2.mParents.push_back(&mNiNode);
mNiNode.hasBounds = true;
mNiNode.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
mNiNode.bounds.box.extents = osg::Vec3f(7, 8, 9);
mNiNode.bounds.box.center = osg::Vec3f(-7, -8, -9);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNode), Nif::NodePtr(&mNode2) }));
mNiNode.mBounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
mNiNode.mBounds.box.extents = osg::Vec3f(7, 8, 9);
mNiNode.mBounds.box.center = osg::Vec3f(-7, -8, -9);
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNode), Nif::NiAVObjectPtr(&mNode2) };
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNiNode);
@ -578,10 +568,9 @@ namespace
TEST_F(TestBulletNifLoader,
for_root_nif_node_with_bounds_but_without_flag_should_return_shape_with_bounds_but_with_null_collision_shape)
{
mNode.hasBounds = true;
mNode.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
mNode.bounds.box.extents = osg::Vec3f(1, 2, 3);
mNode.bounds.box.center = osg::Vec3f(-1, -2, -3);
mNode.mBounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
mNode.mBounds.box.extents = osg::Vec3f(1, 2, 3);
mNode.mBounds.box.center = osg::Vec3f(-1, -2, -3);
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNode);
@ -619,10 +608,9 @@ namespace
TEST_F(TestBulletNifLoader,
for_tri_shape_root_node_with_bounds_should_return_static_shape_with_bounds_but_with_null_collision_shape)
{
mNiTriShape.hasBounds = true;
mNiTriShape.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
mNiTriShape.bounds.box.extents = osg::Vec3f(1, 2, 3);
mNiTriShape.bounds.box.center = osg::Vec3f(-1, -2, -3);
mNiTriShape.mBounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
mNiTriShape.mBounds.box.extents = osg::Vec3f(1, 2, 3);
mNiTriShape.mBounds.box.center = osg::Vec3f(-1, -2, -3);
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNiTriShape);
@ -639,8 +627,8 @@ namespace
TEST_F(TestBulletNifLoader, for_tri_shape_child_node_should_return_static_shape)
{
mNiTriShape.parents.push_back(&mNiNode);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
mNiTriShape.mParents.push_back(&mNiNode);
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape) };
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNiNode);
@ -662,10 +650,10 @@ namespace
TEST_F(TestBulletNifLoader, for_nested_tri_shape_child_should_return_static_shape)
{
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiNode2) }));
mNiNode2.parents.push_back(&mNiNode);
mNiNode2.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
mNiTriShape.parents.push_back(&mNiNode2);
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiNode2) };
mNiNode2.mParents.push_back(&mNiNode);
mNiNode2.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape) };
mNiTriShape.mParents.push_back(&mNiNode2);
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNiNode);
@ -687,10 +675,9 @@ namespace
TEST_F(TestBulletNifLoader, for_two_tri_shape_children_should_return_static_shape_with_all_meshes)
{
mNiTriShape.parents.push_back(&mNiNode);
mNiTriShape2.parents.push_back(&mNiNode);
mNiNode.children
= Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape), Nif::NodePtr(&mNiTriShape2) }));
mNiTriShape.mParents.push_back(&mNiNode);
mNiTriShape2.mParents.push_back(&mNiNode);
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape), Nif::NiAVObjectPtr(&mNiTriShape2) };
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNiNode);
@ -717,8 +704,8 @@ namespace
for_tri_shape_child_node_and_filename_starting_with_x_and_not_empty_skin_should_return_static_shape)
{
mNiTriShape.skin = Nif::NiSkinInstancePtr(&mNiSkinInstance);
mNiTriShape.parents.push_back(&mNiNode);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
mNiTriShape.mParents.push_back(&mNiNode);
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape) };
Nif::NIFFile file("xtest.nif");
file.mRoots.push_back(&mNiNode);
@ -739,8 +726,8 @@ namespace
TEST_F(TestBulletNifLoader, for_tri_shape_root_node_and_filename_starting_with_x_should_return_animated_shape)
{
copy(mTransform, mNiTriShape.trafo);
mNiTriShape.trafo.scale = 3;
copy(mTransform, mNiTriShape.mTransform);
mNiTriShape.mTransform.mScale = 3;
Nif::NIFFile file("xtest.nif");
file.mRoots.push_back(&mNiTriShape);
@ -763,11 +750,11 @@ namespace
TEST_F(TestBulletNifLoader, for_tri_shape_child_node_and_filename_starting_with_x_should_return_animated_shape)
{
copy(mTransform, mNiTriShape.trafo);
mNiTriShape.trafo.scale = 3;
mNiTriShape.parents.push_back(&mNiNode);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
mNiNode.trafo.scale = 4;
copy(mTransform, mNiTriShape.mTransform);
mNiTriShape.mTransform.mScale = 3;
mNiTriShape.mParents.push_back(&mNiNode);
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape) };
mNiNode.mTransform.mScale = 4;
Nif::NIFFile file("xtest.nif");
file.mRoots.push_back(&mNiNode);
@ -791,18 +778,15 @@ namespace
TEST_F(
TestBulletNifLoader, for_two_tri_shape_children_nodes_and_filename_starting_with_x_should_return_animated_shape)
{
copy(mTransform, mNiTriShape.trafo);
mNiTriShape.trafo.scale = 3;
mNiTriShape.parents.push_back(&mNiNode);
copy(mTransform, mNiTriShape.mTransform);
mNiTriShape.mTransform.mScale = 3;
mNiTriShape.mParents.push_back(&mNiNode);
copy(mTransform, mNiTriShape2.trafo);
mNiTriShape2.trafo.scale = 3;
mNiTriShape2.parents.push_back(&mNiNode);
copy(mTransform, mNiTriShape2.mTransform);
mNiTriShape2.mTransform.mScale = 3;
mNiTriShape2.mParents.push_back(&mNiNode);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({
Nif::NodePtr(&mNiTriShape),
Nif::NodePtr(&mNiTriShape2),
}));
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape), Nif::NiAVObjectPtr(&mNiTriShape2) };
Nif::NIFFile file("xtest.nif");
file.mRoots.push_back(&mNiNode);
@ -834,12 +818,12 @@ namespace
{
mController.recType = Nif::RC_NiKeyframeController;
mController.flags |= Nif::Controller::Flag_Active;
copy(mTransform, mNiTriShape.trafo);
mNiTriShape.trafo.scale = 3;
mNiTriShape.parents.push_back(&mNiNode);
mNiTriShape.controller = Nif::ControllerPtr(&mController);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
mNiNode.trafo.scale = 4;
copy(mTransform, mNiTriShape.mTransform);
mNiTriShape.mTransform.mScale = 3;
mNiTriShape.mParents.push_back(&mNiNode);
mNiTriShape.mController = Nif::ControllerPtr(&mController);
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape) };
mNiNode.mTransform.mScale = 4;
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNiNode);
@ -864,18 +848,18 @@ namespace
{
mController.recType = Nif::RC_NiKeyframeController;
mController.flags |= Nif::Controller::Flag_Active;
copy(mTransform, mNiTriShape.trafo);
mNiTriShape.trafo.scale = 3;
mNiTriShape.parents.push_back(&mNiNode);
copy(mTransform, mNiTriShape2.trafo);
mNiTriShape2.trafo.scale = 3;
mNiTriShape2.parents.push_back(&mNiNode);
mNiTriShape2.controller = Nif::ControllerPtr(&mController);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({
Nif::NodePtr(&mNiTriShape),
Nif::NodePtr(&mNiTriShape2),
}));
mNiNode.trafo.scale = 4;
copy(mTransform, mNiTriShape.mTransform);
mNiTriShape.mTransform.mScale = 3;
mNiTriShape.mParents.push_back(&mNiNode);
copy(mTransform, mNiTriShape2.mTransform);
mNiTriShape2.mTransform.mScale = 3;
mNiTriShape2.mParents.push_back(&mNiNode);
mNiTriShape2.mController = Nif::ControllerPtr(&mController);
mNiNode.mChildren = Nif::NiAVObjectList{
Nif::NiAVObjectPtr(&mNiTriShape),
Nif::NiAVObjectPtr(&mNiTriShape2),
};
mNiNode.mTransform.mScale = 4;
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNiNode);
@ -905,8 +889,8 @@ namespace
TEST_F(TestBulletNifLoader, should_add_static_mesh_to_existing_compound_mesh)
{
mNiTriShape.parents.push_back(&mNiNode);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
mNiTriShape.mParents.push_back(&mNiNode);
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape) };
Nif::NIFFile file("xtest.nif");
file.mRoots.push_back(&mNiNode);
@ -936,8 +920,8 @@ namespace
TEST_F(
TestBulletNifLoader, for_root_avoid_node_and_tri_shape_child_node_should_return_shape_with_null_collision_shape)
{
mNiTriShape.parents.push_back(&mNiNode);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
mNiTriShape.mParents.push_back(&mNiNode);
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape) };
mNiNode.recType = Nif::RC_AvoidNode;
Nif::NIFFile file("test.nif");
@ -960,8 +944,8 @@ namespace
TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_empty_data_should_return_shape_with_null_collision_shape)
{
mNiTriShape.data = Nif::NiGeometryDataPtr(nullptr);
mNiTriShape.parents.push_back(&mNiNode);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
mNiTriShape.mParents.push_back(&mNiNode);
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape) };
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNiNode);
@ -979,8 +963,8 @@ namespace
{
auto data = static_cast<Nif::NiTriShapeData*>(mNiTriShape.data.getPtr());
data->mTriangles.clear();
mNiTriShape.parents.push_back(&mNiNode);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
mNiTriShape.mParents.push_back(&mNiNode);
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape) };
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNiNode);
@ -998,9 +982,9 @@ namespace
{
mNiStringExtraData.mData = "NCC__";
mNiStringExtraData.recType = Nif::RC_NiStringExtraData;
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
mNiTriShape.parents.push_back(&mNiNode);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
mNiTriShape.mExtra = Nif::ExtraPtr(&mNiStringExtraData);
mNiTriShape.mParents.push_back(&mNiNode);
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape) };
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNiNode);
@ -1027,9 +1011,9 @@ namespace
mNiStringExtraData.mNext = Nif::ExtraPtr(&mNiStringExtraData2);
mNiStringExtraData2.mData = "NCC__";
mNiStringExtraData2.recType = Nif::RC_NiStringExtraData;
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
mNiTriShape.parents.push_back(&mNiNode);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
mNiTriShape.mExtra = Nif::ExtraPtr(&mNiStringExtraData);
mNiTriShape.mParents.push_back(&mNiNode);
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape) };
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNiNode);
@ -1054,9 +1038,9 @@ namespace
{
mNiStringExtraData.mData = "NC___";
mNiStringExtraData.recType = Nif::RC_NiStringExtraData;
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
mNiTriShape.parents.push_back(&mNiNode);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
mNiTriShape.mExtra = Nif::ExtraPtr(&mNiStringExtraData);
mNiTriShape.mParents.push_back(&mNiNode);
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape) };
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNiNode);
@ -1082,9 +1066,9 @@ namespace
mNiStringExtraData.mNext = Nif::ExtraPtr(&mNiStringExtraData2);
mNiStringExtraData2.mData = "NC___";
mNiStringExtraData2.recType = Nif::RC_NiStringExtraData;
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
mNiTriShape.parents.push_back(&mNiNode);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
mNiTriShape.mExtra = Nif::ExtraPtr(&mNiStringExtraData);
mNiTriShape.mParents.push_back(&mNiNode);
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape) };
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNiNode);
@ -1112,13 +1096,13 @@ namespace
init(emptyCollisionNode);
niTriShape.data = Nif::NiGeometryDataPtr(&mNiTriShapeData);
niTriShape.parents.push_back(&mNiNode);
niTriShape.mParents.push_back(&mNiNode);
emptyCollisionNode.recType = Nif::RC_RootCollisionNode;
emptyCollisionNode.parents.push_back(&mNiNode);
emptyCollisionNode.mParents.push_back(&mNiNode);
mNiNode.children = Nif::NodeList(
std::vector<Nif::NodePtr>({ Nif::NodePtr(&niTriShape), Nif::NodePtr(&emptyCollisionNode) }));
mNiNode.mChildren
= Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&niTriShape), Nif::NiAVObjectPtr(&emptyCollisionNode) };
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNiNode);
@ -1143,9 +1127,9 @@ namespace
{
mNiStringExtraData.mData = "MRK";
mNiStringExtraData.recType = Nif::RC_NiStringExtraData;
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
mNiTriShape.parents.push_back(&mNiNode);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
mNiTriShape.mExtra = Nif::ExtraPtr(&mNiStringExtraData);
mNiTriShape.mParents.push_back(&mNiNode);
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape) };
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNiNode);
@ -1162,10 +1146,10 @@ namespace
{
mNiIntegerExtraData.mData = 32; // BSX flag "editor marker"
mNiIntegerExtraData.recType = Nif::RC_BSXFlags;
mNiTriShape.extralist.push_back(Nif::ExtraPtr(&mNiIntegerExtraData));
mNiTriShape.parents.push_back(&mNiNode);
mNiTriShape.name = "EditorMarker";
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
mNiTriShape.mExtraList.push_back(Nif::ExtraPtr(&mNiIntegerExtraData));
mNiTriShape.mParents.push_back(&mNiNode);
mNiTriShape.mName = "EditorMarker";
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape) };
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNiNode);
@ -1183,12 +1167,12 @@ namespace
{
mNiStringExtraData.mData = "MRK";
mNiStringExtraData.recType = Nif::RC_NiStringExtraData;
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
mNiTriShape.parents.push_back(&mNiNode2);
mNiNode2.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
mNiTriShape.mExtra = Nif::ExtraPtr(&mNiStringExtraData);
mNiTriShape.mParents.push_back(&mNiNode2);
mNiNode2.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape) };
mNiNode2.recType = Nif::RC_RootCollisionNode;
mNiNode2.parents.push_back(&mNiNode);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiNode2) }));
mNiNode2.mParents.push_back(&mNiNode);
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiNode2) };
mNiNode.recType = Nif::RC_NiNode;
Nif::NIFFile file("test.nif");
@ -1290,8 +1274,8 @@ namespace
TEST_F(TestBulletNifLoader, for_avoid_collision_mesh_should_ignore_tri_strips_data_with_less_than_3_strips)
{
mNiTriShape.parents.push_back(&mNiNode);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
mNiTriShape.mParents.push_back(&mNiNode);
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape) };
mNiNode.recType = Nif::RC_AvoidNode;
mNiTriStripsData.mStrips.front() = { 0, 1 };
@ -1309,8 +1293,8 @@ namespace
TEST_F(TestBulletNifLoader, for_animated_mesh_should_ignore_tri_strips_data_with_less_than_3_strips)
{
mNiTriStripsData.mStrips.front() = { 0, 1 };
mNiTriStrips.parents.push_back(&mNiNode);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriStrips) }));
mNiTriStrips.mParents.push_back(&mNiNode);
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriStrips) };
Nif::NIFFile file("xtest.nif");
file.mRoots.push_back(&mNiNode);
@ -1326,8 +1310,8 @@ namespace
TEST_F(TestBulletNifLoader, should_not_add_static_mesh_with_no_triangles_to_compound_shape)
{
mNiTriStripsData.mStrips.front() = { 0, 1 };
mNiTriShape.parents.push_back(&mNiNode);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
mNiTriShape.mParents.push_back(&mNiNode);
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape) };
Nif::NIFFile file("xtest.nif");
file.mRoots.push_back(&mNiNode);
@ -1351,13 +1335,13 @@ namespace
TEST_F(TestBulletNifLoader, should_handle_node_with_multiple_parents)
{
copy(mTransform, mNiTriShape.trafo);
mNiTriShape.trafo.scale = 4;
mNiTriShape.parents = { &mNiNode, &mNiNode2 };
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
mNiNode.trafo.scale = 2;
mNiNode2.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
mNiNode2.trafo.scale = 3;
copy(mTransform, mNiTriShape.mTransform);
mNiTriShape.mTransform.mScale = 4;
mNiTriShape.mParents = { &mNiNode, &mNiNode2 };
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape) };
mNiNode.mTransform.mScale = 2;
mNiNode2.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape) };
mNiNode2.mTransform.mScale = 3;
Nif::NIFFile file("xtest.nif");
file.mRoots.push_back(&mNiNode);

View File

@ -66,7 +66,7 @@ namespace
TEST_F(NifOsgLoaderTest, shouldLoadFileWithDefaultNode)
{
Nif::Node node;
Nif::NiAVObject node;
init(node);
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&node);
@ -183,14 +183,14 @@ osg::Group {
TEST_P(NifOsgLoaderBSShaderPrefixTest, shouldAddShaderPrefix)
{
Nif::Node node;
Nif::NiAVObject node;
init(node);
Nif::BSShaderPPLightingProperty property;
property.recType = Nif::RC_BSShaderPPLightingProperty;
property.textureSet = nullptr;
property.controller = nullptr;
property.mController = nullptr;
property.type = GetParam().mShaderType;
node.props.push_back(Nif::RecordPtrT<Nif::Property>(&property));
node.mProperties.push_back(Nif::RecordPtrT<Nif::Property>(&property));
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&node);
auto result = Loader::load(file, &mImageManager);
@ -211,14 +211,14 @@ osg::Group {
TEST_P(NifOsgLoaderBSLightingShaderPrefixTest, shouldAddShaderPrefix)
{
Nif::Node node;
Nif::NiAVObject node;
init(node);
Nif::BSLightingShaderProperty property;
property.recType = Nif::RC_BSLightingShaderProperty;
property.mTextureSet = nullptr;
property.controller = nullptr;
property.mController = nullptr;
property.type = GetParam().mShaderType;
node.props.push_back(Nif::RecordPtrT<Nif::Property>(&property));
node.mProperties.push_back(Nif::RecordPtrT<Nif::Property>(&property));
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&node);
auto result = Loader::load(file, &mImageManager);

View File

@ -13,20 +13,28 @@ namespace Nif
}
}
void Named::read(NIFStream* nif)
void NiObjectNET::read(NIFStream* nif)
{
name = nif->getString();
nif->read(mName);
if (nif->getVersion() < NIFStream::generateVersion(10, 0, 1, 0))
extra.read(nif);
mExtra.read(nif);
else
readRecordList(nif, extralist);
controller.read(nif);
readRecordList(nif, mExtraList);
mController.read(nif);
}
void Named::post(Reader& nif)
void NiObjectNET::post(Reader& nif)
{
extra.post(nif);
postRecordList(nif, extralist);
controller.post(nif);
mExtra.post(nif);
postRecordList(nif, mExtraList);
mController.post(nif);
}
ExtraList NiObjectNET::getExtraList() const
{
ExtraList list = mExtraList;
for (ExtraPtr extra = mExtra; !extra.empty(); extra = extra->mNext)
list.emplace_back(extra);
return list;
}
}

View File

@ -40,7 +40,7 @@ namespace Nif
int flags;
float frequency, phase;
float timeStart, timeStop;
NamedPtr target;
NiObjectNETPtr target;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
@ -49,18 +49,20 @@ namespace Nif
ExtrapolationMode extrapolationMode() const { return static_cast<ExtrapolationMode>(flags & Mask); }
};
/// Has name, extra-data and controller
struct Named : public Record
/// Abstract object that has a name, extra data and controllers
struct NiObjectNET : public Record
{
std::string name;
ExtraPtr extra;
ExtraList extralist;
ControllerPtr controller;
std::string mName;
ExtraPtr mExtra;
ExtraList mExtraList;
ControllerPtr mController;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
using NiSequenceStreamHelper = Named;
} // Namespace
// Collect extra records attached to the object
ExtraList getExtraList() const;
};
}
#endif

View File

@ -308,7 +308,7 @@ namespace Nif
{
NiInterpController::read(nif);
size_t numTargets = nif->getUShort();
std::vector<NodePtr> targets;
std::vector<NiAVObjectPtr> targets;
targets.resize(numTargets);
for (size_t i = 0; i < targets.size(); i++)
targets[i].read(nif);

View File

@ -160,7 +160,7 @@ namespace Nif
osg::Vec3f offsetRandom;
NodePtr emitter;
NiAVObjectPtr emitter;
int numParticles;
int activeCount;
@ -211,7 +211,7 @@ namespace Nif
struct NiLookAtController : public Controller
{
NodePtr target;
NiAVObjectPtr target;
unsigned short lookAtFlags{ 0 };
void read(NIFStream* nif) override;
@ -237,7 +237,7 @@ namespace Nif
struct NiMultiTargetTransformController : public NiInterpController
{
NodeList mExtraTargets;
NiAVObjectList mExtraTargets;
void read(NIFStream* nif) override;
void post(Reader& nif) override;

View File

@ -347,9 +347,7 @@ namespace Nif
void NiSkinData::read(NIFStream* nif)
{
nif->read(mTransform.rotation);
nif->read(mTransform.pos);
nif->read(mTransform.scale);
nif->read(mTransform);
uint32_t numBones;
nif->read(numBones);
@ -366,9 +364,7 @@ namespace Nif
mBones.resize(numBones);
for (BoneInfo& bi : mBones)
{
nif->read(bi.mTransform.rotation);
nif->read(bi.mTransform.pos);
nif->read(bi.mTransform.scale);
nif->read(bi.mTransform);
nif->read(bi.mBoundSphere);
uint16_t numVertices;

View File

@ -1,33 +1,10 @@
/*
OpenMW - The completely unofficial reimplementation of Morrowind
Copyright (C) 2008-2010 Nicolay Korslund
Email: < korslund@gmail.com >
WWW: https://openmw.org/
This file (data.h) is part of the OpenMW package.
OpenMW is distributed as free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License
version 3, as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
version 3 along with this program. If not, see
https://www.gnu.org/licenses/ .
*/
#ifndef OPENMW_COMPONENTS_NIF_DATA_HPP
#define OPENMW_COMPONENTS_NIF_DATA_HPP
#include "nifkey.hpp"
#include "niftypes.hpp" // Transformation
#include "niftypes.hpp" // NiTransform
#include "node.hpp"
#include "recordptr.hpp"
#include <components/nif/node.hpp>
namespace Nif
{
@ -252,8 +229,8 @@ namespace Nif
{
NiSkinDataPtr mData;
NiSkinPartitionPtr mPartitions;
NodePtr mRoot;
NodeList mBones;
NiAVObjectPtr mRoot;
NiAVObjectList mBones;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
@ -278,12 +255,12 @@ namespace Nif
struct BoneInfo
{
Transformation mTransform;
NiTransform mTransform;
osg::BoundingSpheref mBoundSphere;
std::vector<VertWeight> mWeights;
};
Transformation mTransform;
NiTransform mTransform;
std::vector<BoneInfo> mBones;
NiSkinPartitionPtr mPartitions;
@ -413,5 +390,5 @@ namespace Nif
void read(NIFStream* nif) override;
};
} // Namespace
}
#endif

View File

@ -8,7 +8,7 @@ namespace Nif
void NiDynamicEffect::read(NIFStream* nif)
{
Node::read(nif);
NiAVObject::read(nif);
if (nif->getVersion() > NIFFile::VER_MW && nif->getVersion() < nif->generateVersion(10, 1, 0, 0))
return;

View File

@ -30,7 +30,7 @@ namespace Nif
{
// Abstract
struct NiDynamicEffect : public Node
struct NiDynamicEffect : public NiAVObject
{
bool mSwitchState{ true };
void read(NIFStream* nif) override;

View File

@ -25,13 +25,13 @@ namespace Nif
{
Reader::Reader(NIFFile& file)
: ver(file.mVersion)
, userVer(file.mUserVersion)
, bethVer(file.mBethVersion)
, filename(file.mPath)
, hash(file.mHash)
, records(file.mRecords)
, roots(file.mRoots)
: mVersion(file.mVersion)
, mUserVersion(file.mUserVersion)
, mBethVersion(file.mBethVersion)
, mFilename(file.mPath)
, mHash(file.mHash)
, mRecords(file.mRecords)
, mRoots(file.mRoots)
, mUseSkinning(file.mUseSkinning)
{
}
@ -315,7 +315,7 @@ namespace Nif
/// Make the factory map used for parsing the file
static const std::map<std::string, CreateRecord> factories = makeFactory();
std::string Reader::printVersion(unsigned int version)
std::string Reader::versionToString(std::uint32_t version)
{
int major = (version >> 24) & 0xFF;
int minor = (version >> 16) & 0xFF;
@ -329,8 +329,8 @@ namespace Nif
void Reader::parse(Files::IStreamPtr&& stream)
{
const std::array<std::uint64_t, 2> fileHash = Files::getHash(filename, *stream);
hash.append(reinterpret_cast<const char*>(fileHash.data()), fileHash.size() * sizeof(std::uint64_t));
const std::array<std::uint64_t, 2> fileHash = Files::getHash(mFilename, *stream);
mHash.append(reinterpret_cast<const char*>(fileHash.data()), fileHash.size() * sizeof(std::uint64_t));
NIFStream nif(*this, std::move(stream));
@ -343,151 +343,172 @@ namespace Nif
const bool supportedHeader = std::any_of(verStrings.begin(), verStrings.end(),
[&](const std::string& verString) { return head.starts_with(verString); });
if (!supportedHeader)
throw Nif::Exception("Invalid NIF header: " + head, filename);
throw Nif::Exception("Invalid NIF header: " + head, mFilename);
// Get BCD version
ver = nif.getUInt();
nif.read(mVersion);
// 4.0.0.0 is an older, practically identical version of the format.
// It's not used by Morrowind assets but Morrowind supports it.
static const std::array<uint32_t, 2> supportedVers = {
NIFStream::generateVersion(4, 0, 0, 0),
NIFFile::VER_MW,
};
const bool supportedVersion = std::find(supportedVers.begin(), supportedVers.end(), ver) != supportedVers.end();
const bool supportedVersion
= std::find(supportedVers.begin(), supportedVers.end(), mVersion) != supportedVers.end();
const bool writeDebugLog = sWriteNifDebugLog;
if (!supportedVersion)
{
if (!sLoadUnsupportedFiles)
throw Nif::Exception("Unsupported NIF version: " + printVersion(ver), filename);
throw Nif::Exception("Unsupported NIF version: " + versionToString(mVersion), mFilename);
if (writeDebugLog)
Log(Debug::Warning) << " NIFFile Warning: Unsupported NIF version: " << printVersion(ver)
<< ". Proceed with caution! File: " << filename;
Log(Debug::Warning) << " NIFFile Warning: Unsupported NIF version: " << versionToString(mVersion)
<< ". Proceed with caution! File: " << mFilename;
}
// NIF data endianness
if (ver >= NIFStream::generateVersion(20, 0, 0, 4))
const bool hasEndianness = mVersion >= NIFStream::generateVersion(20, 0, 0, 4);
const bool hasUserVersion = mVersion >= NIFStream::generateVersion(10, 0, 1, 8);
const bool hasRecTypeListings = mVersion >= NIFStream::generateVersion(5, 0, 0, 1);
const bool hasRecTypeHashes = mVersion == NIFStream::generateVersion(20, 3, 1, 2);
const bool hasRecordSizes = mVersion >= NIFStream::generateVersion(20, 2, 0, 5);
const bool hasGroups = mVersion >= NIFStream::generateVersion(5, 0, 0, 6);
const bool hasStringTable = mVersion >= NIFStream::generateVersion(20, 1, 0, 1);
const bool hasRecordSeparators
= mVersion >= NIFStream::generateVersion(10, 0, 0, 0) && mVersion < NIFStream::generateVersion(10, 2, 0, 0);
// Record type list
std::vector<std::string> recTypes;
// Record type mapping for each record
std::vector<std::uint16_t> recTypeIndices;
{
unsigned char endianness = nif.getChar();
std::uint8_t endianness = 1;
if (hasEndianness)
nif.read(endianness);
// TODO: find some big-endian files and investigate the difference
if (endianness == 0)
throw Nif::Exception("Big endian NIF files are unsupported", filename);
throw Nif::Exception("Big endian NIF files are unsupported", mFilename);
}
// User version
if (ver > NIFStream::generateVersion(10, 0, 1, 8))
userVer = nif.getUInt();
if (hasUserVersion)
nif.read(mUserVersion);
// Number of records
const std::size_t recNum = nif.getUInt();
records.resize(recNum);
mRecords.resize(nif.get<std::uint32_t>());
// Bethesda stream header
// It contains Bethesda format version and (useless) export information
if (ver == NIFFile::VER_OB_OLD
|| (userVer >= 3
&& ((ver == NIFFile::VER_OB || ver == NIFFile::VER_BGS)
|| (ver >= NIFStream::generateVersion(10, 1, 0, 0) && ver <= NIFStream::generateVersion(20, 0, 0, 4)
&& userVer <= 11))))
{
bethVer = nif.getUInt();
nif.getExportString(); // Author
if (bethVer > NIFFile::BETHVER_FO4)
nif.getUInt(); // Unknown
nif.getExportString(); // Process script
nif.getExportString(); // Export script
if (bethVer == NIFFile::BETHVER_FO4)
nif.getExportString(); // Max file path
}
std::vector<std::string> recTypes;
std::vector<unsigned short> recTypeIndices;
const bool hasRecTypeListings = ver >= NIFStream::generateVersion(5, 0, 0, 1);
if (hasRecTypeListings)
{
unsigned short recTypeNum = nif.getUShort();
// Record type list
nif.getSizedStrings(recTypes, recTypeNum);
// Record type mapping for each record
nif.readVector(recTypeIndices, recNum);
if (ver >= NIFStream::generateVersion(5, 0, 0, 6)) // Groups
bool hasBSStreamHeader = false;
if (mVersion == NIFFile::VER_OB_OLD)
hasBSStreamHeader = true;
else if (mUserVersion >= 3 && mVersion >= NIFStream::generateVersion(10, 1, 0, 0))
{
if (ver >= NIFStream::generateVersion(20, 1, 0, 1)) // String table
{
if (ver >= NIFStream::generateVersion(20, 2, 0, 5)) // Record sizes
{
std::vector<unsigned int> recSizes; // Currently unused
nif.readVector(recSizes, recNum);
}
const std::size_t stringNum = nif.getUInt();
nif.getUInt(); // Max string length
nif.getSizedStrings(strings, stringNum);
}
std::vector<unsigned int> groups; // Currently unused
unsigned int groupNum = nif.getUInt();
nif.readVector(groups, groupNum);
if (mVersion <= NIFFile::VER_OB || mVersion == NIFFile::VER_BGS)
hasBSStreamHeader = mUserVersion <= 11 || mVersion >= NIFFile::VER_OB;
}
if (hasBSStreamHeader)
{
nif.read(mBethVersion);
nif.getExportString(); // Author
if (mBethVersion >= 131)
nif.get<std::uint32_t>(); // Unknown
else
nif.getExportString(); // Process script
nif.getExportString(); // Export script
if (mBethVersion >= 103)
nif.getExportString(); // Max file path
}
}
const bool hasRecordSeparators
= ver >= NIFStream::generateVersion(10, 0, 0, 0) && ver < NIFStream::generateVersion(10, 2, 0, 0);
for (std::size_t i = 0; i < recNum; i++)
if (hasRecTypeListings)
{
// TODO: 20.3.1.2 uses DJB hashes instead of strings
if (hasRecTypeHashes)
throw Nif::Exception("Hashed record types are unsupported", mFilename);
else
{
nif.getSizedStrings(recTypes, nif.get<std::uint16_t>());
nif.readVector(recTypeIndices, mRecords.size());
}
}
if (hasRecordSizes) // Record sizes
{
std::vector<std::uint32_t> recSizes; // Currently unused
nif.readVector(recSizes, mRecords.size());
}
if (hasStringTable)
{
std::uint32_t stringNum, maxStringLength;
nif.read(stringNum);
nif.read(maxStringLength);
nif.getSizedStrings(mStrings, stringNum);
}
if (hasGroups)
{
std::vector<std::uint32_t> groups; // Currently unused
nif.readVector(groups, nif.get<std::uint32_t>());
}
for (std::size_t i = 0; i < mRecords.size(); i++)
{
std::unique_ptr<Record> r;
std::string rec = hasRecTypeListings ? recTypes[recTypeIndices[i]] : nif.getString();
std::string rec = hasRecTypeListings ? recTypes[recTypeIndices[i]] : nif.get<std::string>();
if (rec.empty())
{
std::stringstream error;
error << "Record type is blank (index " << i << ")";
throw Nif::Exception(error.str(), filename);
throw Nif::Exception(error.str(), mFilename);
}
// Record separator. Some Havok records in Oblivion do not have it.
if (hasRecordSeparators && !rec.starts_with("bhk"))
if (nif.getInt())
if (nif.get<int32_t>())
Log(Debug::Warning) << "NIFFile Warning: Record of type " << rec << ", index " << i
<< " is preceded by a non-zero separator. File: " << filename;
<< " is preceded by a non-zero separator. File: " << mFilename;
const auto entry = factories.find(rec);
if (entry == factories.end())
throw Nif::Exception("Unknown record type " + rec, filename);
throw Nif::Exception("Unknown record type " + rec, mFilename);
r = entry->second();
if (!supportedVersion && writeDebugLog)
Log(Debug::Verbose) << "NIF Debug: Reading record of type " << rec << ", index " << i << " ("
<< filename << ")";
<< mFilename << ")";
assert(r != nullptr);
assert(r->recType != RC_MISSING);
r->recName = rec;
r->recIndex = i;
r->read(&nif);
records[i] = std::move(r);
mRecords[i] = std::move(r);
}
const std::size_t rootNum = nif.getUInt();
roots.resize(rootNum);
// Determine which records are roots
for (std::size_t i = 0; i < rootNum; i++)
mRoots.resize(nif.get<uint32_t>());
for (std::size_t i = 0; i < mRoots.size(); i++)
{
int idx = nif.getInt();
if (idx >= 0 && static_cast<std::size_t>(idx) < records.size())
std::int32_t idx;
nif.read(idx);
if (idx >= 0 && static_cast<std::size_t>(idx) < mRecords.size())
{
roots[i] = records[idx].get();
mRoots[i] = mRecords[idx].get();
}
else
{
roots[i] = nullptr;
mRoots[i] = nullptr;
Log(Debug::Warning) << "NIFFile Warning: Root " << i + 1 << " does not point to a record: index " << idx
<< ". File: " << filename;
<< ". File: " << mFilename;
}
}
// Once parsing is done, do post-processing.
for (const auto& record : records)
for (const auto& record : mRecords)
record->post(*this);
}
@ -513,7 +534,7 @@ namespace Nif
{
if (index == std::numeric_limits<std::uint32_t>::max())
return std::string();
return strings.at(index);
return mStrings.at(index);
}
}

View File

@ -30,13 +30,14 @@ namespace Nif
BETHVER_SKY = 83, // Skyrim
BETHVER_SSE = 100, // Skyrim SE
BETHVER_FO4 = 130, // Fallout 4
BETHVER_F76 = 155 // Fallout 76
BETHVER_F76 = 155, // Fallout 76
BETHVER_STF = 172, // Starfield
};
/// File version, user version, Bethesda version
unsigned int mVersion = 0;
unsigned int mUserVersion = 0;
unsigned int mBethVersion = 0;
std::uint32_t mVersion = 0;
std::uint32_t mUserVersion = 0;
std::uint32_t mBethVersion = 0;
/// File name, used for error messages and opening the file
std::filesystem::path mPath;
@ -76,13 +77,13 @@ namespace Nif
const std::string& getHash() const { return mFile->mHash; }
/// Get the version of the NIF format used
unsigned int getVersion() const { return mFile->mVersion; }
std::uint32_t getVersion() const { return mFile->mVersion; }
/// Get the user version of the NIF format used
unsigned int getUserVersion() const { return mFile->mUserVersion; }
std::uint32_t getUserVersion() const { return mFile->mUserVersion; }
/// Get the Bethesda version of the NIF format used
unsigned int getBethVersion() const { return mFile->mBethVersion; }
std::uint32_t getBethVersion() const { return mFile->mBethVersion; }
bool getUseSkinning() const { return mFile->mUseSkinning; }
@ -93,22 +94,22 @@ namespace Nif
class Reader
{
/// File version, user version, Bethesda version
unsigned int& ver;
unsigned int& userVer;
unsigned int& bethVer;
std::uint32_t& mVersion;
std::uint32_t& mUserVersion;
std::uint32_t& mBethVersion;
/// File name, used for error messages and opening the file
std::filesystem::path& filename;
std::string& hash;
std::filesystem::path& mFilename;
std::string& mHash;
/// Record list
std::vector<std::unique_ptr<Record>>& records;
std::vector<std::unique_ptr<Record>>& mRecords;
/// Root list. This is a select portion of the pointers from records
std::vector<Record*>& roots;
std::vector<Record*>& mRoots;
/// String table
std::vector<std::string> strings;
std::vector<std::string> mStrings;
bool& mUseSkinning;
@ -117,7 +118,7 @@ namespace Nif
/// Get the file's version in a human readable form
///\returns A string containing a human readable NIF version number
std::string printVersion(unsigned int version);
std::string versionToString(std::uint32_t version);
public:
/// Open a NIF stream. The name is used for error messages.
@ -127,26 +128,26 @@ namespace Nif
void parse(Files::IStreamPtr&& stream);
/// Get a given record
Record* getRecord(size_t index) const { return records.at(index).get(); }
Record* getRecord(size_t index) const { return mRecords.at(index).get(); }
/// Get a given string from the file's string table
std::string getString(uint32_t index) const;
std::string getString(std::uint32_t index) const;
/// Set whether there is skinning contained in this NIF file.
/// @note This is just a hint for users of the NIF file and has no effect on the loading procedure.
void setUseSkinning(bool skinning);
/// Get the name of the file
std::filesystem::path getFilename() const { return filename; }
std::filesystem::path getFilename() const { return mFilename; }
/// Get the version of the NIF format used
unsigned int getVersion() const { return ver; }
std::uint32_t getVersion() const { return mVersion; }
/// Get the user version of the NIF format used
unsigned int getUserVersion() const { return userVer; }
std::uint32_t getUserVersion() const { return mUserVersion; }
/// Get the Bethesda version of the NIF format used
unsigned int getBethVersion() const { return bethVer; }
std::uint32_t getBethVersion() const { return mBethVersion; }
static void setLoadUnsupportedFiles(bool load);

View File

@ -130,11 +130,11 @@ namespace Nif
}
template <>
void NIFStream::read<Transformation>(Transformation& t)
void NIFStream::read<NiTransform>(NiTransform& transform)
{
read(t.pos);
read(t.rotation);
read(t.scale);
read(transform.mRotation);
read(transform.mTranslation);
read(transform.mScale);
}
template <>
@ -192,7 +192,7 @@ namespace Nif
}
template <>
void NIFStream::read<Transformation>(Transformation* dest, size_t size)
void NIFStream::read<NiTransform>(NiTransform* dest, size_t size)
{
readRange(*this, dest, size);
}

View File

@ -159,7 +159,6 @@ namespace Nif
osg::Vec4f getVector4() { return get<osg::Vec4f>(); }
Matrix3 getMatrix3() { return get<Matrix3>(); }
osg::Quat getQuaternion() { return get<osg::Quat>(); }
Transformation getTrafo() { return get<Transformation>(); }
bool getBoolean() { return get<bool>(); }
std::string getString() { return get<std::string>(); }
};
@ -177,7 +176,7 @@ namespace Nif
template <>
void NIFStream::read<osg::BoundingSpheref>(osg::BoundingSpheref& sphere);
template <>
void NIFStream::read<Transformation>(Transformation& t);
void NIFStream::read<NiTransform>(NiTransform& transform);
template <>
void NIFStream::read<bool>(bool& data);
template <>
@ -196,7 +195,7 @@ namespace Nif
template <>
void NIFStream::read<osg::BoundingSpheref>(osg::BoundingSpheref* dest, size_t size);
template <>
void NIFStream::read<Transformation>(Transformation* dest, size_t size);
void NIFStream::read<NiTransform>(NiTransform* dest, size_t size);
template <>
void NIFStream::read<bool>(bool* dest, size_t size);
template <>

View File

@ -53,29 +53,29 @@ namespace Nif
}
};
struct Transformation
struct NiTransform
{
osg::Vec3f pos;
Matrix3 rotation; // this can contain scale components too, including negative and nonuniform scales
float scale;
Matrix3 mRotation; // this can contain scale components too, including negative and nonuniform scales
osg::Vec3f mTranslation;
float mScale;
osg::Matrixf toMatrix() const
{
osg::Matrixf transform;
transform.setTrans(pos);
transform.setTrans(mTranslation);
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j)
transform(j, i) = rotation.mValues[i][j] * scale; // NB column/row major difference
transform(j, i) = mRotation.mValues[i][j] * mScale; // NB column/row major difference
return transform;
}
bool isIdentity() const { return pos == osg::Vec3f(0, 0, 0) && rotation.isIdentity() && scale == 1.f; }
bool isIdentity() const { return mRotation.isIdentity() && mTranslation == osg::Vec3f() && mScale == 1.f; }
static const Transformation& getIdentity()
static const NiTransform& getIdentity()
{
static const Transformation identity = { osg::Vec3f(), Matrix3(), 1.0f };
static const NiTransform identity = { Matrix3(), osg::Vec3f(), 1.0f };
return identity;
}
};

View File

@ -12,7 +12,7 @@ namespace Nif
{
void NiBoundingVolume::read(NIFStream* nif)
{
type = nif->getUInt();
nif->read(type);
switch (type)
{
case BASE_BV:
@ -75,48 +75,47 @@ namespace Nif
}
}
void Node::read(NIFStream* nif)
void NiAVObject::read(NIFStream* nif)
{
Named::read(nif);
NiObjectNET::read(nif);
flags = nif->getBethVersion() <= 26 ? nif->getUShort() : nif->getUInt();
trafo = nif->getTrafo();
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);
if (nif->getVersion() <= NIFStream::generateVersion(4, 2, 2, 0))
velocity = nif->getVector3();
nif->read(mVelocity);
if (nif->getBethVersion() <= NIFFile::BethVersion::BETHVER_FO3)
readRecordList(nif, props);
if (nif->getVersion() <= NIFStream::generateVersion(4, 2, 2, 0))
hasBounds = nif->getBoolean();
if (hasBounds)
bounds.read(nif);
// Reference to the collision object in Gamebryo files.
readRecordList(nif, mProperties);
if (nif->getVersion() <= NIFStream::generateVersion(4, 2, 2, 0) && nif->get<bool>())
mBounds.read(nif);
if (nif->getVersion() >= NIFStream::generateVersion(10, 0, 1, 0))
collision.read(nif);
parents.clear();
isBone = false;
mCollision.read(nif);
}
void Node::post(Reader& nif)
void NiAVObject::post(Reader& nif)
{
Named::post(nif);
postRecordList(nif, props);
collision.post(nif);
NiObjectNET::post(nif);
postRecordList(nif, mProperties);
mCollision.post(nif);
}
void Node::setBone()
void NiAVObject::setBone()
{
isBone = true;
mIsBone = true;
}
void NiNode::read(NIFStream* nif)
{
Node::read(nif);
readRecordList(nif, children);
NiAVObject::read(nif);
readRecordList(nif, mChildren);
if (nif->getBethVersion() < NIFFile::BethVersion::BETHVER_FO4)
readRecordList(nif, effects);
readRecordList(nif, mEffects);
// 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)
@ -128,23 +127,24 @@ namespace Nif
// 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 (0 == recIndex && !Misc::StringUtils::ciEqual(name, "bip01"))
if (recIndex == 0 && !Misc::StringUtils::ciEqual(mName, "bip01"))
{
trafo = Nif::Transformation::getIdentity();
mTransform = Nif::NiTransform::getIdentity();
}
}
void NiNode::post(Reader& nif)
{
Node::post(nif);
postRecordList(nif, children);
postRecordList(nif, effects);
NiAVObject::post(nif);
for (auto& child : children)
postRecordList(nif, mChildren);
postRecordList(nif, mEffects);
for (auto& child : mChildren)
{
// Why would a unique list of children contain empty refs?
if (!child.empty())
child->parents.push_back(this);
child->mParents.push_back(this);
}
}
@ -168,7 +168,7 @@ namespace Nif
void NiGeometry::read(NIFStream* nif)
{
Node::read(nif);
NiAVObject::read(nif);
data.read(nif);
skin.read(nif);
material.read(nif);
@ -182,7 +182,7 @@ namespace Nif
void NiGeometry::post(Reader& nif)
{
Node::post(nif);
NiAVObject::post(nif);
data.post(nif);
skin.post(nif);
shaderprop.post(nif);
@ -221,7 +221,7 @@ namespace Nif
void NiCamera::read(NIFStream* nif)
{
Node::read(nif);
NiAVObject::read(nif);
cam.read(nif);
@ -287,7 +287,7 @@ namespace Nif
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0))
mMode = nif->getUShort() & 0x7;
else
mMode = (flags >> 5) & 0x3;
mMode = (mFlags >> 5) & 0x3;
}
void NiDefaultAVObjectPalette::read(NIFStream* nif)
@ -335,7 +335,7 @@ namespace Nif
void BSTriShape::read(NIFStream* nif)
{
Node::read(nif);
NiAVObject::read(nif);
nif->read(mBoundingSphere);
if (nif->getBethVersion() == NIFFile::BethVersion::BETHVER_F76)
@ -389,7 +389,7 @@ namespace Nif
void BSTriShape::post(Reader& nif)
{
Node::post(nif);
NiAVObject::post(nif);
mSkin.post(nif);
mShaderProperty.post(nif);
mAlphaProperty.post(nif);

View File

@ -15,7 +15,7 @@ namespace Nif
struct NiBoundingVolume
{
enum Type
enum Type : uint32_t
{
BASE_BV = 0xFFFFFFFF,
SPHERE_BV = 0,
@ -51,7 +51,7 @@ namespace Nif
osg::Vec3f origin;
};
unsigned int type;
uint32_t type{ BASE_BV };
osg::BoundingSpheref sphere;
NiBoxBV box;
NiCapsuleBV capsule;
@ -62,11 +62,13 @@ namespace Nif
void read(NIFStream* nif);
};
/** A Node is an object that's part of the main NIF tree. It has
parent node (unless it's the root), and transformation (location
and rotation) relative to it's parent.
*/
struct Node : public Named
struct NiSequenceStreamHelper : NiObjectNET
{
};
// NiAVObject is an object that is a part of the main NIF tree. It has
// a parent node (unless it's the root) and transformation relative to its parent.
struct NiAVObject : public NiObjectNET
{
enum Flags
{
@ -76,57 +78,48 @@ namespace Nif
Flag_ActiveCollision = 0x0020
};
// Node flags. Interpretation depends somewhat on the type of node.
unsigned int flags;
Transformation trafo;
osg::Vec3f velocity; // Unused? Might be a run-time game state
PropertyList props;
// Bounding box info
bool hasBounds{ false };
NiBoundingVolume bounds;
// Collision object info
NiCollisionObjectPtr collision;
// Node flags. Interpretation depends on the record type.
uint32_t mFlags;
NiTransform mTransform;
osg::Vec3f mVelocity;
PropertyList mProperties;
NiBoundingVolume mBounds;
NiCollisionObjectPtr mCollision;
// Parent nodes for the node. Only types derived from NiNode can be parents.
std::vector<NiNode*> mParents;
bool mIsBone{ false };
void read(NIFStream* nif) override;
void post(Reader& nif) override;
// Parent node, or nullptr for the root node. As far as I'm aware, only
// NiNodes (or types derived from NiNodes) can be parents.
std::vector<NiNode*> parents;
bool isBone{ false };
void setBone();
bool isHidden() const { return flags & Flag_Hidden; }
bool hasMeshCollision() const { return flags & Flag_MeshCollision; }
bool hasBBoxCollision() const { return flags & Flag_BBoxCollision; }
bool collisionActive() const { return flags & Flag_ActiveCollision; }
bool isHidden() const { return mFlags & Flag_Hidden; }
bool hasMeshCollision() const { return mFlags & Flag_MeshCollision; }
bool hasBBoxCollision() const { return mFlags & Flag_BBoxCollision; }
bool collisionActive() const { return mFlags & Flag_ActiveCollision; }
};
struct NiNode : Node
struct NiNode : NiAVObject
{
NodeList children;
NodeList effects;
enum BSAnimFlags
{
AnimFlag_AutoPlay = 0x0020
};
enum BSParticleFlags
{
ParticleFlag_AutoPlay = 0x0020,
ParticleFlag_LocalSpace = 0x0080
};
NiAVObjectList mChildren;
NiAVObjectList mEffects;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
struct NiGeometry : Node
struct NiGeometry : NiAVObject
{
/* Possible flags:
0x40 - mesh has no vertex normals ?
@ -172,7 +165,7 @@ namespace Nif
{
};
struct NiCamera : Node
struct NiCamera : NiAVObject
{
struct Camera
{
@ -230,7 +223,7 @@ namespace Nif
void read(NIFStream* nif) override;
bool swing() const { return flags & Flag_Swing; }
bool swing() const { return mFlags & Flag_Swing; }
};
// Abstract
@ -272,8 +265,8 @@ namespace Nif
struct NiDefaultAVObjectPalette : Record
{
NodePtr mScene;
std::unordered_map<std::string, NodePtr> mObjects;
NiAVObjectPtr mScene;
std::unordered_map<std::string, NiAVObjectPtr> mObjects;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
@ -281,7 +274,7 @@ namespace Nif
struct BSTreeNode : NiNode
{
NodeList mBones1, mBones2;
NiAVObjectList mBones1, mBones2;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
@ -346,7 +339,7 @@ namespace Nif
void read(NIFStream* nif, uint16_t flags);
};
struct BSTriShape : Node
struct BSTriShape : NiAVObject
{
osg::BoundingSpheref mBoundingSphere;
std::array<float, 6> mBoundMinMax;
@ -393,5 +386,6 @@ namespace Nif
void read(NIFStream* nif) override;
};
} // Namespace
}
#endif

View File

@ -374,7 +374,7 @@ namespace Nif
struct NiCollisionObject : public Record
{
// The node that references this object
NodePtr mTarget;
NiAVObjectPtr mTarget;
void read(NIFStream* nif) override { mTarget.read(nif); }
void post(Reader& nif) override { mTarget.post(nif); }
@ -541,7 +541,7 @@ namespace Nif
struct bhkCompressedMeshShape : public bhkShape
{
NodePtr mTarget;
NiAVObjectPtr mTarget;
uint32_t mUserData;
float mRadius;
osg::Vec4f mScale;

View File

@ -29,7 +29,7 @@
namespace Nif
{
struct Property : public Named
struct Property : public NiObjectNET
{
};

View File

@ -1,9 +1,10 @@
#ifndef OPENMW_COMPONENTS_NIF_RECORDPTR_HPP
#define OPENMW_COMPONENTS_NIF_RECORDPTR_HPP
#include <vector>
#include "niffile.hpp"
#include "nifstream.hpp"
#include <vector>
namespace Nif
{
@ -39,7 +40,7 @@ namespace Nif
assert(index == -2);
// Store the index for later
index = nif->getInt();
index = nif->get<int32_t>();
assert(index >= -1);
}
@ -90,12 +91,13 @@ namespace Nif
template <class T>
void readRecordList(NIFStream* nif, RecordListT<T>& list)
{
const int length = nif->getInt();
const std::uint32_t length = nif->get<std::uint32_t>();
if (length < 0)
throw std::runtime_error("Negative NIF record list length: " + std::to_string(length));
// No reasonable list can hit this generous limit
if (length >= (1 << 24))
throw std::runtime_error("Record list too long: " + std::to_string(length));
list.resize(static_cast<std::size_t>(length));
list.resize(length);
for (auto& value : list)
value.read(nif);
@ -108,14 +110,14 @@ namespace Nif
value.post(nif);
}
struct Node;
struct NiAVObject;
struct Extra;
struct Property;
struct NiUVData;
struct NiPosData;
struct NiVisData;
struct Controller;
struct Named;
struct NiObjectNET;
struct NiSkinData;
struct NiFloatData;
struct NiMorphData;
@ -150,13 +152,13 @@ namespace Nif
struct BSMultiBound;
struct BSMultiBoundData;
using NodePtr = RecordPtrT<Node>;
using NiAVObjectPtr = RecordPtrT<NiAVObject>;
using ExtraPtr = RecordPtrT<Extra>;
using NiUVDataPtr = RecordPtrT<NiUVData>;
using NiPosDataPtr = RecordPtrT<NiPosData>;
using NiVisDataPtr = RecordPtrT<NiVisData>;
using ControllerPtr = RecordPtrT<Controller>;
using NamedPtr = RecordPtrT<Named>;
using NiObjectNETPtr = RecordPtrT<NiObjectNET>;
using NiSkinDataPtr = RecordPtrT<NiSkinData>;
using NiMorphDataPtr = RecordPtrT<NiMorphData>;
using NiPixelDataPtr = RecordPtrT<NiPixelData>;
@ -188,7 +190,7 @@ namespace Nif
using BSMultiBoundPtr = RecordPtrT<BSMultiBound>;
using BSMultiBoundDataPtr = RecordPtrT<BSMultiBoundData>;
using NodeList = RecordListT<Node>;
using NiAVObjectList = RecordListT<NiAVObject>;
using PropertyList = RecordListT<Property>;
using ExtraList = RecordListT<Extra>;
using NiSourceTextureList = RecordListT<NiSourceTexture>;

View File

@ -6,7 +6,7 @@
namespace Nif
{
struct NiTexture : public Named
struct NiTexture : public NiObjectNET
{
};

View File

@ -132,13 +132,13 @@ namespace NifBullet
mShape->mFileHash = nif.getHash();
const size_t numRoots = nif.numRoots();
std::vector<const Nif::Node*> roots;
std::vector<const Nif::NiAVObject*> roots;
for (size_t i = 0; i < numRoots; ++i)
{
const Nif::Record* r = nif.getRoot(i);
if (!r)
continue;
const Nif::Node* node = dynamic_cast<const Nif::Node*>(r);
const Nif::NiAVObject* node = dynamic_cast<const Nif::NiAVObject*>(r);
if (node)
roots.emplace_back(node);
}
@ -151,7 +151,7 @@ namespace NifBullet
}
// Try to find a valid bounding box first. If one's found for any root node, use that.
for (const Nif::Node* node : roots)
for (const Nif::NiAVObject* node : roots)
{
if (findBoundingBox(*node, filename))
{
@ -175,15 +175,19 @@ namespace NifBullet
// If there's no bounding box, we'll have to generate a Bullet collision shape
// from the collision data present in every root node.
for (const Nif::Node* node : roots)
for (const Nif::NiAVObject* node : roots)
{
bool hasCollisionNode = hasRootCollisionNode(*node);
bool hasCollisionShape = hasCollisionNode && !collisionShapeIsEmpty(*node);
if (hasCollisionNode && !hasCollisionShape)
mShape->mVisualCollisionType = Resource::VisualCollisionType::Camera;
bool generateCollisionShape = !hasCollisionShape;
const Nif::NiNode* colNode = findRootCollisionNode(*node);
bool hasCollisionShape = false;
if (colNode != nullptr)
{
if (colNode->mBounds.type == Nif::NiBoundingVolume::Type::BASE_BV && !colNode->mChildren.empty())
hasCollisionShape = true;
else
mShape->mVisualCollisionType = Resource::VisualCollisionType::Camera;
}
HandleNodeArgs args;
args.mAutogenerated = args.mIsCollisionNode = generateCollisionShape;
args.mAutogenerated = args.mIsCollisionNode = !hasCollisionShape;
args.mAnimated = isAnimated;
handleNode(filename, *node, nullptr, args, mShape->mVisualCollisionType);
}
@ -199,87 +203,75 @@ namespace NifBullet
// Find a boundingBox in the node hierarchy.
// Return: use bounding box for collision?
bool BulletNifLoader::findBoundingBox(const Nif::Node& node, const std::string& filename)
bool BulletNifLoader::findBoundingBox(const Nif::NiAVObject& node, const std::string& filename)
{
if (node.hasBounds)
unsigned int type = node.mBounds.type;
switch (type)
{
unsigned int type = node.bounds.type;
switch (type)
case Nif::NiBoundingVolume::Type::BASE_BV:
break;
case Nif::NiBoundingVolume::Type::BOX_BV:
mShape->mCollisionBox.mExtents = node.mBounds.box.extents;
mShape->mCollisionBox.mCenter = node.mBounds.box.center;
break;
default:
{
case Nif::NiBoundingVolume::Type::BOX_BV:
mShape->mCollisionBox.mExtents = node.bounds.box.extents;
mShape->mCollisionBox.mCenter = node.bounds.box.center;
break;
default:
{
std::stringstream warning;
warning << "Unsupported NiBoundingVolume type " << type << " in node " << node.recIndex;
warning << " in file " << filename;
warn(warning.str());
}
}
if (node.hasBBoxCollision())
{
return true;
std::stringstream warning;
warning << "Unsupported NiBoundingVolume type " << type << " in node " << node.recIndex;
warning << " in file " << filename;
warn(warning.str());
}
}
if (type != Nif::NiBoundingVolume::Type::BASE_BV && node.hasBBoxCollision())
return true;
if (const Nif::NiNode* ninode = dynamic_cast<const Nif::NiNode*>(&node))
{
const Nif::NodeList& list = ninode->children;
for (const auto& child : list)
for (const auto& child : ninode->mChildren)
if (!child.empty() && findBoundingBox(child.get(), filename))
return true;
}
return false;
}
bool BulletNifLoader::hasRootCollisionNode(const Nif::Node& rootNode) const
const Nif::NiNode* BulletNifLoader::findRootCollisionNode(const Nif::NiAVObject& rootNode) const
{
if (const Nif::NiNode* ninode = dynamic_cast<const Nif::NiNode*>(&rootNode))
{
for (const auto& child : ninode->children)
for (const auto& child : ninode->mChildren)
{
if (child.empty())
continue;
if (child.getPtr()->recType == Nif::RC_RootCollisionNode)
return true;
if (!child.empty() && child.getPtr()->recType == Nif::RC_RootCollisionNode)
return static_cast<const Nif::NiNode*>(child.getPtr());
}
}
return false;
return nullptr;
}
bool BulletNifLoader::collisionShapeIsEmpty(const Nif::Node& rootNode) const
{
if (const Nif::NiNode* ninode = dynamic_cast<const Nif::NiNode*>(&rootNode))
{
for (const auto& child : ninode->children)
{
if (child.empty())
continue;
const Nif::Node* childNode = child.getPtr();
if (childNode->recType != Nif::RC_RootCollisionNode)
continue;
const Nif::NiNode* niChildnode
= static_cast<const Nif::NiNode*>(childNode); // RootCollisionNode is always a NiNode
if (childNode->hasBounds || niChildnode->children.size() > 0)
return false;
}
}
return true;
}
void BulletNifLoader::handleNode(const std::string& fileName, const Nif::Node& node, const Nif::Parent* parent,
HandleNodeArgs args, Resource::VisualCollisionType& visualCollisionType)
void BulletNifLoader::handleNode(const std::string& fileName, const Nif::NiAVObject& node,
const Nif::Parent* parent, HandleNodeArgs args, Resource::VisualCollisionType& visualCollisionType)
{
// TODO: allow on-the fly collision switching via toggling this flag
if (node.recType == Nif::RC_NiCollisionSwitch && !node.collisionActive())
return;
if (!node.controller.empty() && node.controller->recType == Nif::RC_NiKeyframeController
&& node.controller->isActive())
args.mAnimated = true;
for (Nif::ControllerPtr ctrl = node.mController; !ctrl.empty(); ctrl = ctrl->next)
{
if (args.mAnimated)
break;
if (!ctrl->isActive())
continue;
switch (ctrl->recType)
{
case Nif::RC_NiKeyframeController:
case Nif::RC_NiPathController:
case Nif::RC_NiRollController:
args.mAnimated = true;
break;
default:
continue;
}
}
if (node.recType == Nif::RC_RootCollisionNode)
{
@ -304,13 +296,7 @@ namespace NifBullet
args.mAvoid = true;
// Check for extra data
std::vector<Nif::ExtraPtr> extraCollection;
for (Nif::ExtraPtr e = node.extra; !e.empty(); e = e->mNext)
extraCollection.emplace_back(e);
for (const auto& extraNode : node.extralist)
if (!extraNode.empty())
extraCollection.emplace_back(extraNode);
for (const auto& e : extraCollection)
for (const auto& e : node.getExtraList())
{
if (e->recType == Nif::RC_NiStringExtraData)
{
@ -346,10 +332,10 @@ namespace NifBullet
if (args.mIsCollisionNode)
{
// NOTE: a trishape with hasBounds=true, but no BBoxCollision flag should NOT go through handleNiTriShape!
// NOTE: a trishape with bounds, but no BBoxCollision flag should NOT go through handleNiTriShape!
// It must be ignored completely.
// (occurs in tr_ex_imp_wall_arch_04.nif)
if (!node.hasBounds
if (node.mBounds.type == Nif::NiBoundingVolume::Type::BASE_BV
&& (node.recType == Nif::RC_NiTriShape || node.recType == Nif::RC_NiTriStrips
|| node.recType == Nif::RC_BSLODTriShape))
{
@ -360,14 +346,13 @@ namespace NifBullet
// For NiNodes, loop through children
if (const Nif::NiNode* ninode = dynamic_cast<const Nif::NiNode*>(&node))
{
const Nif::NodeList& list = ninode->children;
const Nif::Parent currentParent{ *ninode, parent };
for (const auto& child : list)
for (const auto& child : ninode->mChildren)
{
if (child.empty())
continue;
assert(std::find(child->parents.begin(), child->parents.end(), ninode) != child->parents.end());
assert(std::find(child->mParents.begin(), child->mParents.end(), ninode) != child->mParents.end());
handleNode(fileName, child.get(), &currentParent, args, visualCollisionType);
}
}
@ -378,7 +363,7 @@ namespace NifBullet
{
// mHasMarkers is specifically BSXFlags editor marker flag.
// If this changes, the check must be corrected.
if (args.mHasMarkers && Misc::StringUtils::ciStartsWith(niGeometry.name, "EditorMarker"))
if (args.mHasMarkers && Misc::StringUtils::ciStartsWith(niGeometry.mName, "EditorMarker"))
return;
if (niGeometry.data.empty() || niGeometry.data->mVertices.empty())
@ -395,9 +380,9 @@ namespace NifBullet
auto childShape = std::make_unique<Resource::TriangleMeshShape>(childMesh.get(), true);
std::ignore = childMesh.release();
osg::Matrixf transform = niGeometry.trafo.toMatrix();
osg::Matrixf transform = niGeometry.mTransform.toMatrix();
for (const Nif::Parent* parent = nodeParent; parent != nullptr; parent = parent->mParent)
transform *= parent->mNiNode.trafo.toMatrix();
transform *= parent->mNiNode.mTransform.toMatrix();
childShape->setLocalScaling(Misc::Convert::toBullet(transform.getScale()));
transform.orthoNormalize(transform);

View File

@ -22,10 +22,8 @@ class btCollisionShape;
namespace Nif
{
struct Node;
struct Transformation;
struct NiTriShape;
struct NiTriStrips;
struct NiAVObject;
struct NiNode;
struct NiGeometry;
struct Parent;
}
@ -50,7 +48,7 @@ namespace NifBullet
osg::ref_ptr<Resource::BulletShape> load(Nif::FileView file);
private:
bool findBoundingBox(const Nif::Node& node, const std::string& filename);
bool findBoundingBox(const Nif::NiAVObject& node, const std::string& filename);
struct HandleNodeArgs
{
@ -61,11 +59,10 @@ namespace NifBullet
bool mAvoid{ false };
};
void handleNode(const std::string& fileName, const Nif::Node& node, const Nif::Parent* parent,
void handleNode(const std::string& fileName, const Nif::NiAVObject& node, const Nif::Parent* parent,
HandleNodeArgs args, Resource::VisualCollisionType& visualCollisionType);
bool hasRootCollisionNode(const Nif::Node& rootNode) const;
bool collisionShapeIsEmpty(const Nif::Node& rootNode) const;
const Nif::NiNode* findRootCollisionNode(const Nif::NiAVObject& rootNode) const;
void handleNiTriShape(const Nif::NiGeometry& nifNode, const Nif::Parent* parent, HandleNodeArgs args);

View File

@ -2,10 +2,10 @@
namespace NifOsg
{
MatrixTransform::MatrixTransform(const Nif::Transformation& trafo)
: osg::MatrixTransform(trafo.toMatrix())
, mScale(trafo.scale)
, mRotationScale(trafo.rotation)
MatrixTransform::MatrixTransform(const Nif::NiTransform& transform)
: osg::MatrixTransform(transform.toMatrix())
, mScale(transform.mScale)
, mRotationScale(transform.mRotation)
{
}

View File

@ -12,7 +12,7 @@ namespace NifOsg
{
public:
MatrixTransform() = default;
MatrixTransform(const Nif::Transformation& trafo);
MatrixTransform(const Nif::NiTransform& transform);
MatrixTransform(const MatrixTransform& copy, const osg::CopyOp& copyop);
META_Node(NifOsg, MatrixTransform)

View File

@ -76,12 +76,12 @@ namespace
void apply(osg::Drawable& node) override { traverse(node); }
};
void getAllNiNodes(const Nif::Node* node, std::vector<int>& outIndices)
void getAllNiNodes(const Nif::NiAVObject* node, std::vector<int>& outIndices)
{
if (const Nif::NiNode* ninode = dynamic_cast<const Nif::NiNode*>(node))
{
outIndices.push_back(ninode->recIndex);
for (const auto& child : ninode->children)
for (const auto& child : ninode->mChildren)
if (!child.empty())
getAllNiNodes(child.getPtr(), outIndices);
}
@ -103,11 +103,11 @@ namespace
// Collect all properties affecting the given drawable that should be handled on drawable basis rather than on the
// node hierarchy above it.
void collectDrawableProperties(
const Nif::Node* nifNode, const Nif::Parent* parent, std::vector<const Nif::Property*>& out)
const Nif::NiAVObject* nifNode, const Nif::Parent* parent, std::vector<const Nif::Property*>& out)
{
if (parent != nullptr)
collectDrawableProperties(&parent->mNiNode, parent->mParent, out);
for (const auto& property : nifNode->props)
for (const auto& property : nifNode->mProperties)
{
if (!property.empty())
{
@ -275,21 +275,28 @@ namespace NifOsg
return;
}
Nif::ExtraPtr extra = seq->extra;
if (extra.empty() || extra->recType != Nif::RC_NiTextKeyExtraData)
Nif::ExtraList extraList = seq->getExtraList();
if (extraList.empty())
{
Log(Debug::Warning) << "NIFFile Warning: First extra data was not a NiTextKeyExtraData, but a "
<< (extra.empty() ? std::string_view("nil") : std::string_view(extra->recName))
<< ". File: " << nif.getFilename();
Log(Debug::Warning) << "NIFFile Warning: NiSequenceStreamHelper has no text keys. File: "
<< nif.getFilename();
return;
}
extractTextKeys(static_cast<const Nif::NiTextKeyExtraData*>(extra.getPtr()), target.mTextKeys);
extra = extra->mNext;
Nif::ControllerPtr ctrl = seq->controller;
for (; !extra.empty() && !ctrl.empty(); (extra = extra->mNext), (ctrl = ctrl->next))
if (extraList[0]->recType != Nif::RC_NiTextKeyExtraData)
{
Log(Debug::Warning) << "NIFFile Warning: First extra data was not a NiTextKeyExtraData, but a "
<< std::string_view(extraList[0]->recName) << ". File: " << nif.getFilename();
return;
}
auto textKeyExtraData = static_cast<const Nif::NiTextKeyExtraData*>(extraList[0].getPtr());
extractTextKeys(textKeyExtraData, target.mTextKeys);
Nif::ControllerPtr ctrl = seq->mController;
for (size_t i = 1; i < extraList.size() && !ctrl.empty(); i++, (ctrl = ctrl->next))
{
Nif::ExtraPtr extra = extraList[i];
if (extra->recType != Nif::RC_NiStringExtraData || ctrl->recType != Nif::RC_NiKeyframeController)
{
Log(Debug::Warning) << "NIFFile Warning: Unexpected extra data " << extra->recName
@ -338,13 +345,13 @@ namespace NifOsg
osg::ref_ptr<osg::Node> load(Nif::FileView nif, Resource::ImageManager* imageManager)
{
const size_t numRoots = nif.numRoots();
std::vector<const Nif::Node*> roots;
std::vector<const Nif::NiAVObject*> roots;
for (size_t i = 0; i < numRoots; ++i)
{
const Nif::Record* r = nif.getRoot(i);
if (!r)
continue;
const Nif::Node* nifNode = dynamic_cast<const Nif::Node*>(r);
const Nif::NiAVObject* nifNode = dynamic_cast<const Nif::NiAVObject*>(r);
if (nifNode)
roots.emplace_back(nifNode);
}
@ -355,7 +362,7 @@ namespace NifOsg
osg::ref_ptr<osg::Group> created(new osg::Group);
created->setDataVariance(osg::Object::STATIC);
for (const Nif::Node* root : roots)
for (const Nif::NiAVObject* root : roots)
{
auto node = handleNode(root, nullptr, nullptr,
{ .mNifVersion = nif.getVersion(),
@ -390,13 +397,13 @@ namespace NifOsg
return created;
}
void applyNodeProperties(const Nif::Node* nifNode, osg::Node* applyTo,
void applyNodeProperties(const Nif::NiAVObject* nifNode, osg::Node* applyTo,
SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* imageManager,
std::vector<unsigned int>& boundTextures, int animflags)
{
bool hasStencilProperty = false;
for (const auto& property : nifNode->props)
for (const auto& property : nifNode->mProperties)
{
if (property.empty())
continue;
@ -413,13 +420,13 @@ namespace NifOsg
}
}
for (const auto& property : nifNode->props)
for (const auto& property : nifNode->mProperties)
{
if (!property.empty())
{
// Get the lowest numbered recIndex of the NiTexturingProperty root node.
// This is what is overridden when a spell effect "particle texture" is used.
if (nifNode->parents.empty() && !mFoundFirstRootTexturingProperty
if (nifNode->mParents.empty() && !mFoundFirstRootTexturingProperty
&& property.getPtr()->recType == Nif::RC_NiTexturingProperty)
{
mFirstRootTextureIndex = property.getPtr()->recIndex;
@ -454,7 +461,7 @@ namespace NifOsg
static osg::ref_ptr<osg::LOD> handleLodNode(const Nif::NiLODNode* niLodNode)
{
osg::ref_ptr<osg::LOD> lod(new osg::LOD);
lod->setName(niLodNode->name);
lod->setName(niLodNode->mName);
lod->setCenterMode(osg::LOD::USER_DEFINED_CENTER);
lod->setCenter(niLodNode->lodCenter);
for (unsigned int i = 0; i < niLodNode->lodLevels.size(); ++i)
@ -469,29 +476,29 @@ namespace NifOsg
static osg::ref_ptr<osg::Switch> handleSwitchNode(const Nif::NiSwitchNode* niSwitchNode)
{
osg::ref_ptr<osg::Switch> switchNode(new osg::Switch);
switchNode->setName(niSwitchNode->name);
switchNode->setName(niSwitchNode->mName);
switchNode->setNewChildDefaultValue(false);
switchNode->setSingleChildOn(niSwitchNode->initialIndex);
return switchNode;
}
static osg::ref_ptr<osg::Sequence> prepareSequenceNode(const Nif::Node* nifNode)
static osg::ref_ptr<osg::Sequence> prepareSequenceNode(const Nif::NiAVObject* nifNode)
{
const Nif::NiFltAnimationNode* niFltAnimationNode = static_cast<const Nif::NiFltAnimationNode*>(nifNode);
osg::ref_ptr<osg::Sequence> sequenceNode(new osg::Sequence);
sequenceNode->setName(niFltAnimationNode->name);
if (!niFltAnimationNode->children.empty())
sequenceNode->setName(niFltAnimationNode->mName);
if (!niFltAnimationNode->mChildren.empty())
{
if (niFltAnimationNode->swing())
sequenceNode->setDefaultTime(
niFltAnimationNode->mDuration / (niFltAnimationNode->children.size() * 2));
niFltAnimationNode->mDuration / (niFltAnimationNode->mChildren.size() * 2));
else
sequenceNode->setDefaultTime(niFltAnimationNode->mDuration / niFltAnimationNode->children.size());
sequenceNode->setDefaultTime(niFltAnimationNode->mDuration / niFltAnimationNode->mChildren.size());
}
return sequenceNode;
}
static void activateSequenceNode(osg::Group* osgNode, const Nif::Node* nifNode)
static void activateSequenceNode(osg::Group* osgNode, const Nif::NiAVObject* nifNode)
{
const Nif::NiFltAnimationNode* niFltAnimationNode = static_cast<const Nif::NiFltAnimationNode*>(nifNode);
osg::Sequence* sequenceNode = static_cast<osg::Sequence*>(osgNode);
@ -528,7 +535,7 @@ namespace NifOsg
texture->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP_TO_EDGE);
}
bool handleEffect(const Nif::Node* nifNode, osg::StateSet* stateset, Resource::ImageManager* imageManager)
bool handleEffect(const Nif::NiAVObject* nifNode, osg::StateSet* stateset, Resource::ImageManager* imageManager)
{
if (nifNode->recType != Nif::RC_NiTextureEffect)
{
@ -589,7 +596,7 @@ namespace NifOsg
}
// Get a default dataVariance for this node to be used as a hint by optimization (post)routines
osg::ref_ptr<osg::Group> createNode(const Nif::Node* nifNode)
osg::ref_ptr<osg::Group> createNode(const Nif::NiAVObject* nifNode)
{
osg::ref_ptr<osg::Group> node;
osg::Object::DataVariance dataVariance = osg::Object::UNSPECIFIED;
@ -604,15 +611,15 @@ namespace NifOsg
// This takes advantage of the fact root nodes can't have additional controllers
// loaded from an external .kf file (original engine just throws "can't find node" errors if you
// try).
if (nifNode->parents.empty() && nifNode->controller.empty() && nifNode->trafo.isIdentity())
if (nifNode->mParents.empty() && nifNode->mController.empty() && nifNode->mTransform.isIdentity())
node = new osg::Group;
dataVariance = nifNode->isBone ? osg::Object::DYNAMIC : osg::Object::STATIC;
dataVariance = nifNode->mIsBone ? osg::Object::DYNAMIC : osg::Object::STATIC;
break;
}
if (!node)
node = new NifOsg::MatrixTransform(nifNode->trafo);
node = new NifOsg::MatrixTransform(nifNode->mTransform);
node->setDataVariance(dataVariance);
@ -620,9 +627,9 @@ namespace NifOsg
}
osg::ref_ptr<osg::Node> handleNode(
const Nif::Node* nifNode, const Nif::Parent* parent, osg::Group* parentNode, HandleNodeArgs args)
const Nif::NiAVObject* nifNode, const Nif::Parent* parent, osg::Group* parentNode, HandleNodeArgs args)
{
if (args.mRootNode && Misc::StringUtils::ciEqual(nifNode->name, "Bounding Box"))
if (args.mRootNode && Misc::StringUtils::ciEqual(nifNode->mName, "Bounding Box"))
return nullptr;
osg::ref_ptr<osg::Group> node = createNode(nifNode);
@ -632,7 +639,7 @@ namespace NifOsg
node->addCullCallback(new BillboardCallback);
}
node->setName(nifNode->name);
node->setName(nifNode->mName);
if (parentNode)
parentNode->addChild(node);
@ -646,16 +653,7 @@ namespace NifOsg
// - finding a random child NiNode in NiBspArrayController
node->setUserValue("recIndex", nifNode->recIndex);
std::vector<Nif::ExtraPtr> extraCollection;
for (Nif::ExtraPtr e = nifNode->extra; !e.empty(); e = e->mNext)
extraCollection.emplace_back(e);
for (const auto& extraNode : nifNode->extralist)
if (!extraNode.empty())
extraCollection.emplace_back(extraNode);
for (const auto& e : extraCollection)
for (const auto& e : nifNode->getExtraList())
{
if (e->recType == Nif::RC_NiTextKeyExtraData && args.mTextKeys)
{
@ -694,7 +692,7 @@ namespace NifOsg
}
if (nifNode->recType == Nif::RC_NiBSAnimationNode || nifNode->recType == Nif::RC_NiBSParticleNode)
args.mAnimFlags = nifNode->flags;
args.mAnimFlags = nifNode->mFlags;
if (nifNode->recType == Nif::RC_NiSortAdjustNode)
{
@ -727,7 +725,7 @@ namespace NifOsg
if (nifNode->isHidden())
{
bool hasVisController = false;
for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next)
for (Nif::ControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->next)
{
hasVisController |= (ctrl->recType == Nif::RC_NiVisController);
if (hasVisController)
@ -755,12 +753,12 @@ namespace NifOsg
bool skip;
if (args.mNifVersion <= Nif::NIFFile::NIFVersion::VER_MW)
{
skip = (args.mHasMarkers && Misc::StringUtils::ciStartsWith(nifNode->name, "tri editormarker"))
|| Misc::StringUtils::ciStartsWith(nifNode->name, "shadow")
|| Misc::StringUtils::ciStartsWith(nifNode->name, "tri shadow");
skip = (args.mHasMarkers && Misc::StringUtils::ciStartsWith(nifNode->mName, "tri editormarker"))
|| Misc::StringUtils::ciStartsWith(nifNode->mName, "shadow")
|| Misc::StringUtils::ciStartsWith(nifNode->mName, "tri shadow");
}
else
skip = args.mHasMarkers && Misc::StringUtils::ciStartsWith(nifNode->name, "EditorMarker");
skip = args.mHasMarkers && Misc::StringUtils::ciStartsWith(nifNode->mName, "EditorMarker");
if (!skip)
{
Nif::NiSkinInstancePtr skin = static_cast<const Nif::NiGeometry*>(nifNode)->skin;
@ -770,7 +768,7 @@ namespace NifOsg
else
handleSkinnedGeometry(nifNode, parent, node, composite, args.mBoundTextures, args.mAnimFlags);
if (!nifNode->controller.empty())
if (!nifNode->mController.empty())
handleMeshControllers(nifNode, node, composite, args.mBoundTextures, args.mAnimFlags);
}
}
@ -807,9 +805,9 @@ namespace NifOsg
const Nif::NiSwitchNode* niSwitchNode = static_cast<const Nif::NiSwitchNode*>(nifNode);
osg::ref_ptr<osg::Switch> switchNode = handleSwitchNode(niSwitchNode);
node->addChild(switchNode);
if (niSwitchNode->name == Constants::NightDayLabel)
if (niSwitchNode->mName == Constants::NightDayLabel)
mHasNightDayLabel = true;
else if (niSwitchNode->name == Constants::HerbalismLabel)
else if (niSwitchNode->mName == Constants::HerbalismLabel)
mHasHerbalismLabel = true;
currentNode = switchNode;
@ -831,7 +829,7 @@ namespace NifOsg
const Nif::NiNode* ninode = dynamic_cast<const Nif::NiNode*>(nifNode);
if (ninode)
{
const Nif::NodeList& children = ninode->children;
const Nif::NiAVObjectList& children = ninode->mChildren;
const Nif::Parent currentParent{ *ninode, parent };
for (const auto& child : children)
if (!child.empty())
@ -840,7 +838,7 @@ namespace NifOsg
// Propagate effects to the the direct subgraph instead of the node itself
// This simulates their "affected node list" which Morrowind appears to replace with the subgraph (?)
// Note that the serialized affected node list is actually unused
for (const auto& effect : ninode->effects)
for (const auto& effect : ninode->mEffects)
if (!effect.empty())
{
osg::ref_ptr<osg::StateSet> effectStateSet = new osg::StateSet;
@ -856,11 +854,11 @@ namespace NifOsg
return node;
}
void handleMeshControllers(const Nif::Node* nifNode, osg::Node* node,
void handleMeshControllers(const Nif::NiAVObject* nifNode, osg::Node* node,
SceneUtil::CompositeStateSetUpdater* composite, const std::vector<unsigned int>& boundTextures,
int animflags)
{
for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next)
for (Nif::ControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->next)
{
if (!ctrl->isActive())
continue;
@ -885,9 +883,9 @@ namespace NifOsg
}
}
void handleNodeControllers(const Nif::Node* nifNode, osg::Node* node, int animflags, bool& isAnimated)
void handleNodeControllers(const Nif::NiAVObject* nifNode, osg::Node* node, int animflags, bool& isAnimated)
{
for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next)
for (Nif::ControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->next)
{
if (!ctrl->isActive())
continue;
@ -965,7 +963,7 @@ namespace NifOsg
void handleMaterialControllers(const Nif::Property* materialProperty,
SceneUtil::CompositeStateSetUpdater* composite, int animflags, const osg::Material* baseMaterial)
{
for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next)
for (Nif::ControllerPtr ctrl = materialProperty->mController; !ctrl.empty(); ctrl = ctrl->next)
{
if (!ctrl->isActive())
continue;
@ -1016,7 +1014,7 @@ namespace NifOsg
void handleTextureControllers(const Nif::Property* texProperty, SceneUtil::CompositeStateSetUpdater* composite,
Resource::ImageManager* imageManager, osg::StateSet* stateset, int animflags)
{
for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next)
for (Nif::ControllerPtr ctrl = texProperty->mController; !ctrl.empty(); ctrl = ctrl->next)
{
if (!ctrl->isActive())
continue;
@ -1123,7 +1121,7 @@ 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, ParticleSystem* partsys, const Nif::NiParticleSystemController* partctrl)
const Nif::NiAVObject* nifNode, ParticleSystem* partsys, const Nif::NiParticleSystemController* partctrl)
{
auto particleNode = static_cast<const Nif::NiParticles*>(nifNode);
if (particleNode->data.empty() || particleNode->data->recType != Nif::RC_NiParticlesData)
@ -1249,14 +1247,14 @@ namespace NifOsg
mEmitterQueue.clear();
}
void handleParticleSystem(const Nif::Node* nifNode, const Nif::Parent* parent, osg::Group* parentNode,
void handleParticleSystem(const Nif::NiAVObject* nifNode, const Nif::Parent* parent, osg::Group* parentNode,
SceneUtil::CompositeStateSetUpdater* composite, int animflags)
{
osg::ref_ptr<ParticleSystem> partsys(new ParticleSystem);
partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT);
const Nif::NiParticleSystemController* partctrl = nullptr;
for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next)
for (Nif::ControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->next)
{
if (!ctrl->isActive())
continue;
@ -1377,7 +1375,7 @@ namespace NifOsg
}
}
void handleNiGeometry(const Nif::Node* nifNode, const Nif::Parent* parent, osg::Geometry* geometry,
void handleNiGeometry(const Nif::NiAVObject* nifNode, const Nif::Parent* parent, osg::Geometry* geometry,
osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite,
const std::vector<unsigned int>& boundTextures, int animflags)
{
@ -1465,7 +1463,7 @@ namespace NifOsg
new osg::DrawElementsUShort(osg::PrimitiveSet::LINES, line.size(), line.data()));
}
}
handleNiGeometryData(geometry, niGeometryData, boundTextures, nifNode->name);
handleNiGeometryData(geometry, niGeometryData, boundTextures, nifNode->mName);
// osg::Material properties are handled here for two reasons:
// - if there are no vertex colors, we need to disable colorMode.
@ -1476,7 +1474,7 @@ namespace NifOsg
applyDrawableProperties(parentNode, drawableProps, composite, !niGeometryData->mColors.empty(), animflags);
}
void handleGeometry(const Nif::Node* nifNode, const Nif::Parent* parent, osg::Group* parentNode,
void handleGeometry(const Nif::NiAVObject* nifNode, const Nif::Parent* parent, osg::Group* parentNode,
SceneUtil::CompositeStateSetUpdater* composite, const std::vector<unsigned int>& boundTextures,
int animflags)
{
@ -1487,7 +1485,7 @@ namespace NifOsg
if (geom->empty())
return;
osg::ref_ptr<osg::Drawable> drawable;
for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next)
for (Nif::ControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->next)
{
if (!ctrl->isActive())
continue;
@ -1507,7 +1505,7 @@ namespace NifOsg
}
if (!drawable.get())
drawable = geom;
drawable->setName(nifNode->name);
drawable->setName(nifNode->mName);
parentNode->addChild(drawable);
}
@ -1532,7 +1530,7 @@ namespace NifOsg
return morphGeom;
}
void handleSkinnedGeometry(const Nif::Node* nifNode, const Nif::Parent* parent, osg::Group* parentNode,
void handleSkinnedGeometry(const Nif::NiAVObject* nifNode, const Nif::Parent* parent, osg::Group* parentNode,
SceneUtil::CompositeStateSetUpdater* composite, const std::vector<unsigned int>& boundTextures,
int animflags)
{
@ -1543,17 +1541,17 @@ namespace NifOsg
return;
osg::ref_ptr<SceneUtil::RigGeometry> rig(new SceneUtil::RigGeometry);
rig->setSourceGeometry(geometry);
rig->setName(nifNode->name);
rig->setName(nifNode->mName);
// Assign bone weights
osg::ref_ptr<SceneUtil::RigGeometry::InfluenceMap> map(new SceneUtil::RigGeometry::InfluenceMap);
const Nif::NiSkinInstance* skin = static_cast<const Nif::NiGeometry*>(nifNode)->skin.getPtr();
const Nif::NiSkinData* data = skin->mData.getPtr();
const Nif::NodeList& bones = skin->mBones;
const Nif::NiAVObjectList& bones = skin->mBones;
for (std::size_t i = 0; i < bones.size(); ++i)
{
std::string boneName = Misc::StringUtils::lowerCase(bones[i].getPtr()->name);
std::string boneName = Misc::StringUtils::lowerCase(bones[i].getPtr()->mName);
SceneUtil::RigGeometry::BoneInfluence influence;
influence.mWeights = data->mBones[i].mWeights;
@ -1839,7 +1837,7 @@ namespace NifOsg
for (size_t i = 0; i < texprop->textures.size(); ++i)
{
if (texprop->textures[i].inUse
|| (i == Nif::NiTexturingProperty::BaseTexture && !texprop->controller.empty()))
|| (i == Nif::NiTexturingProperty::BaseTexture && !texprop->mController.empty()))
{
switch (i)
{
@ -1866,7 +1864,7 @@ namespace NifOsg
if (texprop->textures[i].inUse)
{
const Nif::NiTexturingProperty::Texture& tex = texprop->textures[i];
if (tex.texture.empty() && texprop->controller.empty())
if (tex.texture.empty() && texprop->mController.empty())
{
if (i == 0)
Log(Debug::Warning) << "Base texture is in use but empty on shape \"" << nodeName
@ -2424,7 +2422,7 @@ namespace NifOsg
mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.specular, 1.f));
mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness);
if (!matprop->controller.empty())
if (!matprop->mController.empty())
{
hasMatCtrl = true;
handleMaterialControllers(matprop, composite, animflags, mat);