From d7a4a9fd66f2eaf03da816692a07b6b621f7c86a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 15:25:45 +0200 Subject: [PATCH] Create NIF root nodes as Group instead of Transform when possible --- components/nifosg/nifloader.cpp | 56 +++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 40eedad51..91dea6ef2 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -414,12 +414,7 @@ namespace NifOsg osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { - osg::ref_ptr transformNode = new osg::MatrixTransform(nifNode->trafo.toMatrix()); - - if (nifNode->recType == Nif::RC_NiBillboardNode) - { - transformNode->addCullCallback(new BillboardCallback); - } + osg::ref_ptr node = new osg::MatrixTransform(nifNode->trafo.toMatrix()); // Set a default DataVariance (used as hint by optimization routines). switch (nifNode->recType) @@ -429,21 +424,34 @@ namespace NifOsg case Nif::RC_NiRotatingParticles: // Leaf nodes in the NIF hierarchy, so won't be able to dynamically attach children. // No support for keyframe controllers (just crashes in the original engine). - transformNode->setDataVariance(osg::Object::STATIC); + node->setDataVariance(osg::Object::STATIC); break; default: // could have new children attached at any time, or added external keyframe controllers from .kf files - transformNode->setDataVariance(osg::Object::DYNAMIC); + node->setDataVariance(osg::Object::DYNAMIC); break; } - transformNode->setName(nifNode->name); + if (nifNode->recType == Nif::RC_NiBillboardNode) + { + node->addCullCallback(new BillboardCallback); + } + else if (!rootNode && nifNode->controller.empty() && nifNode->trafo.isIdentity()) + { + // The Root node can be created as a Group if no transformation is required. + // 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). + node = new osg::Group; + node->setDataVariance(osg::Object::STATIC); + } + + node->setName(nifNode->name); if (parentNode) - parentNode->addChild(transformNode); + parentNode->addChild(node); if (!rootNode) - rootNode = transformNode; + rootNode = node; // UserData used for a variety of features: // - finding the correct emitter node for a particle system @@ -451,7 +459,7 @@ namespace NifOsg // - finding a random child NiNode in NiBspArrayController // - storing the previous 3x3 rotation and scale values for when a KeyframeController wants to // change only certain elements of the 4x4 transform - transformNode->getOrCreateUserDataContainer()->addUserObject( + node->getOrCreateUserDataContainer()->addUserObject( new NodeUserData(nifNode->recIndex, nifNode->trafo.scale, nifNode->trafo.rotation)); for (Nif::ExtraPtr e = nifNode->extra; !e.empty(); e = e->extra) @@ -485,7 +493,7 @@ namespace NifOsg { skipMeshes = true; // Leave mask for UpdateVisitor enabled - transformNode->setNodeMask(0x1); + node->setNodeMask(0x1); } // We can skip creating meshes for hidden nodes if they don't have a VisController that @@ -500,39 +508,39 @@ namespace NifOsg skipMeshes = true; // skip child meshes, but still create the child node hierarchy for animating collision shapes // now hide this node, but leave the mask for UpdateVisitor enabled so that KeyframeController works - transformNode->setNodeMask(0x1); + node->setNodeMask(0x1); } osg::ref_ptr composite = new SceneUtil::CompositeStateSetUpdater; - applyNodeProperties(nifNode, transformNode, composite, textureManager, boundTextures, animflags); + applyNodeProperties(nifNode, node, composite, textureManager, boundTextures, animflags); if (nifNode->recType == Nif::RC_NiTriShape && !skipMeshes) { const Nif::NiTriShape* triShape = static_cast(nifNode); if (triShape->skin.empty()) - handleTriShape(triShape, transformNode, composite, boundTextures, animflags); + handleTriShape(triShape, node, composite, boundTextures, animflags); else - handleSkinnedTriShape(triShape, transformNode, composite, boundTextures, animflags); + handleSkinnedTriShape(triShape, node, composite, boundTextures, animflags); if (!nifNode->controller.empty()) handleMeshControllers(nifNode, composite, boundTextures, animflags); } if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles) - handleParticleSystem(nifNode, transformNode, composite, animflags, particleflags, rootNode); + handleParticleSystem(nifNode, node, composite, animflags, particleflags, rootNode); if (composite->getNumControllers() > 0) - transformNode->addUpdateCallback(composite); + node->addUpdateCallback(composite); // Note: NiTriShapes are not allowed to have KeyframeControllers (the vanilla engine just crashes when there is one). // We can take advantage of this constraint for optimizations later. - if (!nifNode->controller.empty()) - handleNodeControllers(nifNode, transformNode, animflags); + if (!nifNode->controller.empty() && node->getDataVariance() == osg::Object::DYNAMIC) + handleNodeControllers(nifNode, static_cast(node.get()), animflags); // Optimization pass - optimize(nifNode, transformNode, skipMeshes); + optimize(nifNode, node, skipMeshes); const Nif::NiNode *ninode = dynamic_cast(nifNode); if(ninode) @@ -542,12 +550,12 @@ namespace NifOsg { if(!children[i].empty()) { - handleNode(children[i].getPtr(), transformNode, textureManager, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); + handleNode(children[i].getPtr(), node, textureManager, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); } } } - return transformNode; + return node; } void handleMeshControllers(const Nif::Node *nifNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map &boundTextures, int animflags)