diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 463eb9e45..5916359c8 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -477,22 +477,19 @@ void ParticleSystemController::operator() (osg::Node* node, osg::NodeVisitor* nv traverse(node, nv); } -SourcedKeyframeController::SourcedKeyframeController(const Nif::NiKeyframeData *data, int sourceIndex) +SourcedKeyframeController::SourcedKeyframeController(const Nif::NiKeyframeData *data) : KeyframeController(data) - , mSourceIndex(sourceIndex) , mEnabled(false) { } SourcedKeyframeController::SourcedKeyframeController() - : mSourceIndex(0) - , mEnabled(false) + : mEnabled(false) { } SourcedKeyframeController::SourcedKeyframeController(const SourcedKeyframeController ©, const osg::CopyOp ©op) : KeyframeController(copy, copyop) - , mSourceIndex(copy.mSourceIndex) , mEnabled(copy.mEnabled) { } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 0e5885333..80e6090e4 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -169,14 +169,13 @@ namespace NifOsg osg::Quat getXYZRotation(float time) const; }; - // Specialization of KeyframeController that remembers a "source index" for the animation source - // it came from, and can be enabled/disabled. Used for multiple animation sources support, i.e. .kf files. + // Specialization that can be enabled/disabled. Used for multiple animation sources support, i.e. .kf files. // A SourcedKeyframeController is disabled by default and should be manually enabled when playing an animation from // the relevant animation source. class SourcedKeyframeController : public KeyframeController { public: - SourcedKeyframeController(const Nif::NiKeyframeData* data, int sourceIndex); + SourcedKeyframeController(const Nif::NiKeyframeData* data); SourcedKeyframeController(); SourcedKeyframeController(const SourcedKeyframeController& copy, const osg::CopyOp& copyop); @@ -184,12 +183,9 @@ namespace NifOsg virtual void operator() (osg::Node*, osg::NodeVisitor*); - int getSourceIndex() const; - void setEnabled(bool enabled); private: - int mSourceIndex; bool mEnabled; }; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 555105e35..94885a11b 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -298,6 +298,7 @@ namespace // NodeVisitor that adds keyframe controllers to an existing scene graph, used when loading .kf files + /* class LoadKfVisitor : public osg::NodeVisitor { public: @@ -332,6 +333,7 @@ namespace std::map mMap; int mSourceIndex; }; + */ // Node callback used to dirty a RigGeometry's bounding box every frame, so that RigBoundingBoxCallback updates. // This has to be attached to the geode, because the RigGeometry's Drawable::UpdateCallback is already used internally and not extensible. @@ -522,19 +524,15 @@ namespace NifOsg sShowMarkers = show; } + bool Loader::getShowMarkers() + { + return sShowMarkers; + } + class LoaderImpl { public: - Resource::TextureManager* mTextureManager; - bool mShowMarkers; - - LoaderImpl(Resource::TextureManager* textureManager, bool showMarkers) - : mTextureManager(textureManager) - , mShowMarkers(showMarkers) - { - } - - void loadKf(Nif::NIFFilePtr nif, osg::Node *rootNode, int sourceIndex, TextKeyMap& textKeys) + static void loadKf(Nif::NIFFilePtr nif, KeyframeHolder& target) { if(nif->numRoots() < 1) { @@ -561,9 +559,7 @@ namespace NifOsg return; } - extractTextKeys(static_cast(extra.getPtr()), textKeys); - - std::map controllerMap; + extractTextKeys(static_cast(extra.getPtr()), target.mTextKeys); extra = extra->extra; Nif::ControllerPtr ctrl = seq->controller; @@ -584,17 +580,17 @@ namespace NifOsg if(key->data.empty()) continue; - controllerMap[strdata->string] = key; - } + osg::ref_ptr callback(new NifOsg::SourcedKeyframeController(key->data.getPtr())); + callback->mFunction = boost::shared_ptr(new NifOsg::ControllerFunction(key)); - LoadKfVisitor visitor(controllerMap, sourceIndex); - rootNode->accept(visitor); + target.mKeyframeControllers[strdata->string] = callback; + } } - osg::ref_ptr load(Nif::NIFFilePtr nif, TextKeyMap* textKeys) + static osg::ref_ptr load(Nif::NIFFilePtr nif, Resource::TextureManager* textureManager) { if (nif->getUseSkinning()) - return loadAsSkeleton(nif, textKeys); + return loadAsSkeleton(nif, textureManager); if (nif->numRoots() < 1) nif->fail("Found no root nodes"); @@ -605,11 +601,16 @@ namespace NifOsg if (nifNode == NULL) nif->fail("First root was not a node, but a " + r->recName); - osg::ref_ptr created = handleNode(nifNode, NULL, false, std::map(), 0, 0, false, textKeys); + osg::ref_ptr textkeys (new TextKeyMapHolder); + + osg::ref_ptr created = handleNode(nifNode, NULL, textureManager, false, std::map(), 0, 0, false, &textkeys->mTextKeys); + + created->getOrCreateUserDataContainer()->addUserObject(textkeys); + return created; } - osg::ref_ptr loadAsSkeleton(Nif::NIFFilePtr nif, TextKeyMap* textKeys) + static osg::ref_ptr loadAsSkeleton(Nif::NIFFilePtr nif, Resource::TextureManager* textureManager) { if (nif->numRoots() < 1) nif->fail("Found no root nodes"); @@ -621,24 +622,28 @@ namespace NifOsg if (nifNode == NULL) nif->fail("First root was not a node, but a " + r->recName); + osg::ref_ptr textkeys (new TextKeyMapHolder); + osg::ref_ptr skel = new osgAnimation::Skeleton; skel->setDefaultUpdateCallback(); // validates the skeleton hierarchy - handleNode(nifNode, skel, true, std::map(), 0, 0, false, textKeys); + handleNode(nifNode, skel, textureManager, true, std::map(), 0, 0, false, &textkeys->mTextKeys); + + skel->getOrCreateUserDataContainer()->addUserObject(textkeys); return skel; } - void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, std::map& boundTextures, int animflags) + static void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) { const Nif::PropertyList& props = nifNode->props; for (size_t i = 0; i mFunction = boost::shared_ptr(new ControllerFunction(ctrl)); } - osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, + static osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, bool createSkeleton, std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { osg::ref_ptr transformNode; @@ -698,7 +703,7 @@ namespace NifOsg const Nif::NiStringExtraData *sd = static_cast(e.getPtr()); // String markers may contain important information // affecting the entire subtree of this obj - if(sd->string == "MRK" && !mShowMarkers) + if(sd->string == "MRK" && !Loader::getShowMarkers()) { // Marker objects. These meshes are only visible in the editor. skipMeshes = true; @@ -735,7 +740,7 @@ namespace NifOsg transformNode->setNodeMask(0x1); } - applyNodeProperties(nifNode, transformNode, boundTextures, animflags); + applyNodeProperties(nifNode, transformNode, textureManager, boundTextures, animflags); if (nifNode->recType == Nif::RC_NiTriShape && !skipMeshes) { @@ -767,7 +772,8 @@ namespace NifOsg { if(!children[i].empty()) { - handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); + handleNode(children[i].getPtr(), transformNode, textureManager, + createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); } } } @@ -775,7 +781,7 @@ namespace NifOsg return transformNode; } - void handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map &boundTextures, int animflags) + static void handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map &boundTextures, int animflags) { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -797,7 +803,7 @@ namespace NifOsg } } - void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags) + static void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags) { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -825,7 +831,7 @@ namespace NifOsg } } - void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, osg::StateSet *stateset, int animflags) + static void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -852,7 +858,7 @@ namespace NifOsg } } - void handleTextureControllers(const Nif::Property *texProperty, osg::Node* node, osg::StateSet *stateset, int animflags) + static void handleTextureControllers(const Nif::Property *texProperty, osg::Node* node, Resource::TextureManager* textureManager, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -878,8 +884,8 @@ namespace NifOsg wrapT = inherit->getWrap(osg::Texture2D::WRAP_T); } - std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, mTextureManager->getVFS()); - osg::ref_ptr texture = mTextureManager->getTexture2D(filename, wrapS, wrapT); + std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, textureManager->getVFS()); + osg::ref_ptr texture = textureManager->getTexture2D(filename, wrapS, wrapT); textures.push_back(texture); } osg::ref_ptr callback(new FlipController(flipctrl, textures)); @@ -892,7 +898,7 @@ namespace NifOsg } } - void handleParticlePrograms(Nif::ExtraPtr affectors, Nif::ExtraPtr colliders, osg::Group *attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf) + static void handleParticlePrograms(Nif::ExtraPtr affectors, Nif::ExtraPtr colliders, osg::Group *attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf) { osgParticle::ModularProgram* program = new osgParticle::ModularProgram; attachTo->addChild(program); @@ -934,7 +940,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, osgParticle::ParticleSystem* partsys, const Nif::NiParticleSystemController* partctrl) + static void handleParticleInitialState(const Nif::Node* nifNode, osgParticle::ParticleSystem* partsys, const Nif::NiParticleSystemController* partctrl) { const Nif::NiAutoNormalParticlesData *particledata = NULL; if(nifNode->recType == Nif::RC_NiAutoNormalParticles) @@ -970,7 +976,7 @@ namespace NifOsg } } - osg::ref_ptr handleParticleEmitter(const Nif::NiParticleSystemController* partctrl) + static osg::ref_ptr handleParticleEmitter(const Nif::NiParticleSystemController* partctrl) { std::vector targets; if (partctrl->recType == Nif::RC_NiBSPArrayController) @@ -1004,7 +1010,7 @@ namespace NifOsg return emitter; } - void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags, osg::Node* rootNode) + static void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags, osg::Node* rootNode) { osg::ref_ptr partsys (new ParticleSystem); partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); @@ -1100,7 +1106,7 @@ namespace NifOsg } } - void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Geode* parentGeode, const std::map& boundTextures, int animflags) + static void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Geode* parentGeode, const std::map& boundTextures, int animflags) { const Nif::NiTriShapeData* data = triShape->data.getPtr(); @@ -1183,7 +1189,7 @@ namespace NifOsg applyMaterialProperties(parentGeode, materialProps, !data->colors.empty(), animflags); } - void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags) + static void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags) { osg::ref_ptr geometry; if(!triShape->controller.empty()) @@ -1215,7 +1221,7 @@ namespace NifOsg parentNode->addChild(geode); } - osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) + static osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) { osg::ref_ptr morphGeom = new osgAnimation::MorphGeometry; morphGeom->setMethod(osgAnimation::MorphGeometry::RELATIVE); @@ -1233,7 +1239,7 @@ namespace NifOsg return morphGeom; } - void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) + static void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) { osg::ref_ptr geode (new osg::Geode); geode->setName(triShape->name); // name will be used for part filtering @@ -1289,8 +1295,8 @@ namespace NifOsg } - void handleProperty(const Nif::Property *property, - osg::Node *node, std::map& boundTextures, int animflags) + static void handleProperty(const Nif::Property *property, + osg::Node *node, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) { osg::StateSet* stateset = node->getOrCreateStateSet(); @@ -1417,13 +1423,13 @@ namespace NifOsg continue; } - std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, mTextureManager->getVFS()); + std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, textureManager->getVFS()); unsigned int clamp = static_cast(tex.clamp); int wrapT = (clamp) & 0x1; int wrapS = (clamp >> 1) & 0x1; - osg::Texture2D* texture2d = mTextureManager->getTexture2D(filename, + osg::Texture2D* texture2d = textureManager->getTexture2D(filename, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP); @@ -1465,7 +1471,7 @@ namespace NifOsg stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF); boundTextures.erase(i); } - handleTextureControllers(texprop, node, stateset, animflags); + handleTextureControllers(texprop, node, textureManager, stateset, animflags); } break; } @@ -1482,7 +1488,7 @@ namespace NifOsg } } - void applyMaterialProperties(osg::Node* node, const std::vector& properties, + static void applyMaterialProperties(osg::Node* node, const std::vector& properties, bool hasVertexColors, int animflags) { osg::StateSet* stateset = node->getOrCreateStateSet(); @@ -1550,22 +1556,19 @@ namespace NifOsg }; - osg::ref_ptr Loader::load(Nif::NIFFilePtr file, TextKeyMap *textKeys) + osg::ref_ptr Loader::load(Nif::NIFFilePtr file, Resource::TextureManager* textureManager) { - LoaderImpl loader(mTextureManager, sShowMarkers); - return loader.load(file, textKeys); + return LoaderImpl::load(file, textureManager); } - osg::ref_ptr Loader::loadAsSkeleton(Nif::NIFFilePtr file, TextKeyMap *textKeys) + osg::ref_ptr Loader::loadAsSkeleton(Nif::NIFFilePtr file, Resource::TextureManager* textureManager) { - LoaderImpl loader(mTextureManager, sShowMarkers); - return loader.loadAsSkeleton(file, textKeys); + return LoaderImpl::loadAsSkeleton(file, textureManager); } - void Loader::loadKf(Nif::NIFFilePtr kf, osg::Node *rootNode, int sourceIndex, TextKeyMap &textKeys) + void Loader::loadKf(Nif::NIFFilePtr kf, KeyframeHolder& target) { - LoaderImpl loader(mTextureManager, sShowMarkers); - loader.loadKf(kf, rootNode, sourceIndex, textKeys); + LoaderImpl::loadKf(kf, target); } } diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 716cd1957..1c403a4fe 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -6,6 +6,9 @@ #include // NIFFilePtr #include +#include + +#include "controller.hpp" namespace osg { @@ -21,30 +24,52 @@ namespace NifOsg { typedef std::multimap TextKeyMap; + struct TextKeyMapHolder : public osg::Object + { + public: + TextKeyMapHolder() {} + TextKeyMapHolder(const TextKeyMapHolder& copy, const osg::CopyOp& copyop) + : osg::Object(copy, copyop) + , mTextKeys(copy.mTextKeys) + {} + + TextKeyMap mTextKeys; + + META_Object(NifOsg, TextKeyMapHolder) + + }; + + class KeyframeHolder : public osg::Referenced + { + public: + TextKeyMap mTextKeys; + + std::map > mKeyframeControllers; + }; + /// The main class responsible for loading NIF files into an OSG-Scenegraph. /// @par This scene graph is self-contained and can be cloned using osg::clone if desired. Particle emitters /// and programs hold a pointer to their ParticleSystem, which would need to be manually updated when cloning. class Loader { public: + // TODO: add text keys as user data on the node /// Create a scene graph for the given NIF. Auto-detects when skinning is used and calls loadAsSkeleton instead. /// @param node The parent of the new root node for the created scene graph. - osg::ref_ptr load(Nif::NIFFilePtr file, TextKeyMap* textKeys = NULL); + static osg::ref_ptr load(Nif::NIFFilePtr file, Resource::TextureManager* textureManager); /// Create a scene graph for the given NIF. Always creates a skeleton so that rigs can be attached on the created scene. - osg::ref_ptr loadAsSkeleton(Nif::NIFFilePtr file, TextKeyMap* textKeys = NULL); + static osg::ref_ptr loadAsSkeleton(Nif::NIFFilePtr file, Resource::TextureManager* textureManager); - /// 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, TextKeyMap &textKeys); + /// Load keyframe controllers from the given kf file. + static void loadKf(Nif::NIFFilePtr kf, KeyframeHolder& target); /// Set whether or not nodes marked as "MRK" should be shown. /// These should be hidden ingame, but visible in the editior. /// Default: false. static void setShowMarkers(bool show); - Resource::TextureManager* mTextureManager; + static bool getShowMarkers(); private: diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 3f38762ca..e626a9f08 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -82,10 +82,7 @@ namespace Resource // TODO: add support for non-NIF formats NifOsg::Loader loader; - loader.mTextureManager = mTextureManager; - osg::ref_ptr loaded = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized))); - - // TODO: provide way for the user to get textKeys (attach to the node?) + osg::ref_ptr loaded = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); mIndex[normalized] = loaded; return loaded; @@ -108,6 +105,27 @@ namespace Resource return cloned; } + osg::ref_ptr SceneManager::getKeyframes(const std::string &name) + { + std::string normalized = name; + mVFS->normalizeFilename(normalized); + + KeyframeIndex::iterator it = mKeyframeIndex.find(normalized); + if (it == mKeyframeIndex.end()) + { + Files::IStreamPtr file = mVFS->get(normalized); + + NifOsg::Loader loader; + osg::ref_ptr loaded (new NifOsg::KeyframeHolder); + loader.loadKf(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), *loaded.get()); + + mKeyframeIndex[normalized] = loaded; + return loaded; + } + else + return it->second; + } + void SceneManager::attachTo(osg::Node *instance, osg::Group *parentNode) const { parentNode->addChild(instance); diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 7b3bcb2d5..4d6ad4855 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -7,6 +7,8 @@ #include #include +#include + namespace Resource { class TextureManager; @@ -17,6 +19,11 @@ namespace VFS class Manager; } +namespace NifOsg +{ + class KeyframeHolder; +} + namespace Resource { @@ -41,6 +48,11 @@ namespace Resource /// @note Assumes the given instance was not attached to any parents before. void attachTo(osg::Node* instance, osg::Group* parentNode) const; + /// Get a read-only copy of the given keyframe file. + osg::ref_ptr getKeyframes(const std::string& name); + + /// Manually release created OpenGL objects for the given graphics context. This may be required + /// in cases where multiple contexts are used over the lifetime of the application. void releaseGLObjects(osg::State* state); private: @@ -50,6 +62,9 @@ namespace Resource // observer_ptr? typedef std::map > Index; Index mIndex; + + typedef std::map > KeyframeIndex; + KeyframeIndex mKeyframeIndex; }; }