diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 3e70c8cd22..c21f423bfc 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -111,7 +111,6 @@ int main(int argc, char** argv) //osgDB::writeNodeFile(*newNode, "out.osg"); - osg::Group* newNode = new osg::Group; NifOsg::Loader loader; loader.resourceManager = &resourceMgr; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index c73bcbc969..c05bad5ae5 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -302,12 +302,50 @@ namespace } return morphGeom; } + + void extractTextKeys(const Nif::NiTextKeyExtraData *tk, NifOsg::TextKeyMap &textkeys) + { + for(size_t i = 0;i < tk->list.size();i++) + { + const std::string &str = tk->list[i].text; + std::string::size_type pos = 0; + while(pos < str.length()) + { + if(::isspace(str[pos])) + { + pos++; + continue; + } + + std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos)); + if(nextpos != std::string::npos) + { + do { + nextpos--; + } while(nextpos > pos && ::isspace(str[nextpos])); + nextpos++; + } + else if(::isspace(*str.rbegin())) + { + std::string::const_iterator last = str.end(); + do { + --last; + } while(last != str.begin() && ::isspace(*last)); + nextpos = std::distance(str.begin(), ++last); + } + std::string result = str.substr(pos, nextpos-pos); + textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::toLower(result))); + + pos = nextpos; + } + } + } } namespace NifOsg { - void Loader::loadKf(Nif::NIFFilePtr nif, osg::Node *rootNode, int sourceIndex) + void Loader::loadKf(Nif::NIFFilePtr nif, osg::Node *rootNode, int sourceIndex, TextKeyMap& textKeys) { if(nif->numRoots() < 1) { @@ -334,7 +372,7 @@ namespace NifOsg return; } - //extractTextKeys(static_cast(extra.getPtr()), textKeys); + extractTextKeys(static_cast(extra.getPtr()), textKeys); std::map controllerMap; @@ -364,55 +402,45 @@ namespace NifOsg rootNode->accept(visitor); } - osg::Node* Loader::load(Nif::NIFFilePtr nif, osg::Group *parentNode) + osg::Node* Loader::load(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys) { mNif = nif; if (nif->numRoots() < 1) - { nif->fail("Found no root nodes"); - } const Nif::Record* r = nif->getRoot(0); const Nif::Node* nifNode = dynamic_cast(r); if (nifNode == NULL) - { nif->fail("First root was not a node, but a " + r->recName); - } mRootNode = parentNode; - osg::Node* created = handleNode(nifNode, parentNode, false, std::map(), 0, 0); + osg::Node* created = handleNode(nifNode, parentNode, false, std::map(), 0, 0, false, textKeys); return created; } - osg::Node* Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode) + osg::Node* Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys) { mNif = nif; if (nif->numRoots() < 1) - { - //nif->warn("Found no root nodes"); nif->fail("Found no root nodes"); - } const Nif::Record* r = nif->getRoot(0); assert(r != NULL); const Nif::Node* nifNode = dynamic_cast(r); if (nifNode == NULL) - { - //nif->warn("First root was not a node, but a " + r->recName); nif->fail("First root was not a node, but a " + r->recName); - } osg::ref_ptr skel = new osgAnimation::Skeleton; parentNode->addChild(skel); mRootNode = parentNode; - handleNode(nifNode, skel, true, std::map(), 0, 0); + handleNode(nifNode, skel, true, std::map(), 0, 0, false, textKeys); return skel; } @@ -437,7 +465,7 @@ namespace NifOsg } osg::Node* Loader::handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, - std::map boundTextures, int animflags, int particleflags, bool collisionNode) + std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys) { osg::ref_ptr transformNode; if (nifNode->recType == Nif::RC_NiBillboardNode) @@ -458,6 +486,9 @@ namespace NifOsg } // Ignoring name for non-bone nodes for now. We might need it later in isolated cases, e.g. AttachLight. + // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) + parentNode->insertChild(0, transformNode); + // UserData used for a variety of features: // - finding the correct emitter node for a particle system // - establishing connections to the animated collision shapes, which are handled in a separate loader @@ -467,6 +498,27 @@ namespace NifOsg transformNode->getOrCreateUserDataContainer()->addUserObject( new NodeUserData(nifNode->recIndex, nifNode->trafo.scale, nifNode->trafo.rotation)); + for (Nif::ExtraPtr e = nifNode->extra; !e.empty(); e = e->extra) + { + if(e->recType == Nif::RC_NiTextKeyExtraData && textKeys) + { + const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); + extractTextKeys(tk, *textKeys); + } + else if(e->recType == Nif::RC_NiStringExtraData) + { + const Nif::NiStringExtraData *sd = static_cast(e.getPtr()); + // String markers may contain important information + // affecting the entire subtree of this obj + // TODO: implement show markers flag + if(sd->string == "MRK" /*&& !sShowMarkers*/) + { + // Marker objects. These meshes are only visible in the editor. + skipMeshes = true; + } + } + } + if (nifNode->recType == Nif::RC_NiBSAnimationNode) animflags |= nifNode->flags; if (nifNode->recType == Nif::RC_NiBSParticleNode) @@ -476,7 +528,7 @@ namespace NifOsg // We still need to animate the hidden bones so the physics system can access them if (nifNode->recType == Nif::RC_RootCollisionNode) { - collisionNode = true; + skipMeshes = true; // Leave mask for UpdateVisitor enabled transformNode->setNodeMask(0x1); } @@ -486,12 +538,9 @@ namespace NifOsg if (nifNode->flags & Nif::NiNode::Flag_Hidden) transformNode->setNodeMask(0x1); // Leave mask for UpdateVisitor enabled - // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) - parentNode->insertChild(0, transformNode); - applyNodeProperties(nifNode, transformNode, boundTextures, animflags); - if (nifNode->recType == Nif::RC_NiTriShape && !collisionNode) + if (nifNode->recType == Nif::RC_NiTriShape && !skipMeshes) { const Nif::NiTriShape* triShape = static_cast(nifNode); if (!createSkeleton || triShape->skin.empty()) @@ -520,7 +569,7 @@ namespace NifOsg for(size_t i = 0;i < children.length();++i) { if(!children[i].empty()) - handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, particleflags, collisionNode); + handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys); } } diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 18e3e7db8c..9fc262c70c 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -40,15 +40,15 @@ namespace NifOsg // though, when assembling from several files, i.e. equipment parts /// Create a scene graph for the given NIF. Assumes no skinning is used. /// @param node The parent of the new root node for the created scene graph. - osg::Node* load(Nif::NIFFilePtr file, osg::Group* parentNode); + osg::Node* load(Nif::NIFFilePtr file, osg::Group* parentNode, TextKeyMap* textKeys = NULL); /// Create a scene graph for the given NIF. Assumes skinning will be used. - osg::Node* loadAsSkeleton(Nif::NIFFilePtr file, osg::Group* parentNode); + osg::Node* loadAsSkeleton(Nif::NIFFilePtr file, osg::Group* parentNode, TextKeyMap* textKeys = NULL); /// Load keyframe controllers from the given kf file onto the given scene graph. /// @param sourceIndex The source index for this animation source, used for identifying /// which animation source a keyframe controller came from. - void loadKf(Nif::NIFFilePtr kf, osg::Node* rootNode, int sourceIndex); + void loadKf(Nif::NIFFilePtr kf, osg::Node* rootNode, int sourceIndex, TextKeyMap &textKeys); const VFS::Manager* resourceManager; @@ -56,7 +56,7 @@ namespace NifOsg /// @param createSkeleton If true, use an osgAnimation::Bone for NIF nodes, otherwise an osg::MatrixTransform. osg::Node* handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, - std::map boundTextures, int animflags, int particleflags, bool collisionNode=false); + std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys); void handleMeshControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, const std::map& boundTextures, int animflags);