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:
commit
42b77342c5
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -30,7 +30,7 @@ namespace Nif
|
||||
{
|
||||
|
||||
// Abstract
|
||||
struct NiDynamicEffect : public Node
|
||||
struct NiDynamicEffect : public NiAVObject
|
||||
{
|
||||
bool mSwitchState{ true };
|
||||
void read(NIFStream* nif) override;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 <>
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -29,7 +29,7 @@
|
||||
namespace Nif
|
||||
{
|
||||
|
||||
struct Property : public Named
|
||||
struct Property : public NiObjectNET
|
||||
{
|
||||
};
|
||||
|
||||
|
@ -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>;
|
||||
|
@ -6,7 +6,7 @@
|
||||
namespace Nif
|
||||
{
|
||||
|
||||
struct NiTexture : public Named
|
||||
struct NiTexture : public NiObjectNET
|
||||
{
|
||||
};
|
||||
|
||||
|
@ -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(), ¤tParent, 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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user