TextKeys attached to root node as user data, add .kf loading to scenemanager

c++11
scrawl 10 years ago
parent 25f1c1ae76
commit e5e1013c51

@ -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 &copy, const osg::CopyOp &copyop)
: KeyframeController(copy, copyop)
, mSourceIndex(copy.mSourceIndex)
, mEnabled(copy.mEnabled)
{
}

@ -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;
};

@ -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<std::string, const Nif::NiKeyframeController*> 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<const Nif::NiTextKeyExtraData*>(extra.getPtr()), textKeys);
std::map<std::string, const Nif::NiKeyframeController*> controllerMap;
extractTextKeys(static_cast<const Nif::NiTextKeyExtraData*>(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<NifOsg::SourcedKeyframeController> callback(new NifOsg::SourcedKeyframeController(key->data.getPtr()));
callback->mFunction = boost::shared_ptr<NifOsg::ControllerFunction>(new NifOsg::ControllerFunction(key));
LoadKfVisitor visitor(controllerMap, sourceIndex);
rootNode->accept(visitor);
target.mKeyframeControllers[strdata->string] = callback;
}
}
osg::ref_ptr<osg::Node> load(Nif::NIFFilePtr nif, TextKeyMap* textKeys)
static osg::ref_ptr<osg::Node> 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<osg::Node> created = handleNode(nifNode, NULL, false, std::map<int, int>(), 0, 0, false, textKeys);
osg::ref_ptr<TextKeyMapHolder> textkeys (new TextKeyMapHolder);
osg::ref_ptr<osg::Node> created = handleNode(nifNode, NULL, textureManager, false, std::map<int, int>(), 0, 0, false, &textkeys->mTextKeys);
created->getOrCreateUserDataContainer()->addUserObject(textkeys);
return created;
}
osg::ref_ptr<osg::Node> loadAsSkeleton(Nif::NIFFilePtr nif, TextKeyMap* textKeys)
static osg::ref_ptr<osg::Node> 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<TextKeyMapHolder> textkeys (new TextKeyMapHolder);
osg::ref_ptr<osgAnimation::Skeleton> skel = new osgAnimation::Skeleton;
skel->setDefaultUpdateCallback(); // validates the skeleton hierarchy
handleNode(nifNode, skel, true, std::map<int, int>(), 0, 0, false, textKeys);
handleNode(nifNode, skel, textureManager, true, std::map<int, int>(), 0, 0, false, &textkeys->mTextKeys);
skel->getOrCreateUserDataContainer()->addUserObject(textkeys);
return skel;
}
void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, std::map<int, int>& boundTextures, int animflags)
static void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, Resource::TextureManager* textureManager, std::map<int, int>& boundTextures, int animflags)
{
const Nif::PropertyList& props = nifNode->props;
for (size_t i = 0; i <props.length();++i)
{
if (!props[i].empty())
handleProperty(props[i].getPtr(), applyTo, boundTextures, animflags);
handleProperty(props[i].getPtr(), applyTo, textureManager, boundTextures, animflags);
}
}
void setupController(const Nif::Controller* ctrl, Controller* toSetup, int animflags)
static void setupController(const Nif::Controller* ctrl, Controller* toSetup, int animflags)
{
// TODO: uncomment this, currently commented for easier testing
//bool autoPlay = animflags & Nif::NiNode::AnimFlag_AutoPlay;
@ -648,7 +653,7 @@ namespace NifOsg
toSetup->mFunction = boost::shared_ptr<ControllerFunction>(new ControllerFunction(ctrl));
}
osg::ref_ptr<osg::Node> handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton,
static osg::ref_ptr<osg::Node> handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, bool createSkeleton,
std::map<int, int> boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL)
{
osg::ref_ptr<osg::MatrixTransform> transformNode;
@ -698,7 +703,7 @@ namespace NifOsg
const Nif::NiStringExtraData *sd = static_cast<const Nif::NiStringExtraData*>(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<int, int> &boundTextures, int animflags)
static void handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map<int, int> &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<osg::Texture2D> texture = mTextureManager->getTexture2D(filename, wrapS, wrapT);
std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, textureManager->getVFS());
osg::ref_ptr<osg::Texture2D> texture = textureManager->getTexture2D(filename, wrapS, wrapT);
textures.push_back(texture);
}
osg::ref_ptr<FlipController> 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<Emitter> handleParticleEmitter(const Nif::NiParticleSystemController* partctrl)
static osg::ref_ptr<Emitter> handleParticleEmitter(const Nif::NiParticleSystemController* partctrl)
{
std::vector<int> 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<ParticleSystem> 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<int, int>& boundTextures, int animflags)
static void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Geode* parentGeode, const std::map<int, int>& 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<int, int>& boundTextures, int animflags)
static void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map<int, int>& boundTextures, int animflags)
{
osg::ref_ptr<osg::Geometry> geometry;
if(!triShape->controller.empty())
@ -1215,7 +1221,7 @@ namespace NifOsg
parentNode->addChild(geode);
}
osg::ref_ptr<osg::Geometry> handleMorphGeometry(const Nif::NiGeomMorpherController* morpher)
static osg::ref_ptr<osg::Geometry> handleMorphGeometry(const Nif::NiGeomMorpherController* morpher)
{
osg::ref_ptr<osgAnimation::MorphGeometry> 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<int, int>& boundTextures, int animflags)
static void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map<int, int>& boundTextures, int animflags)
{
osg::ref_ptr<osg::Geode> 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<int, int>& boundTextures, int animflags)
static void handleProperty(const Nif::Property *property,
osg::Node *node, Resource::TextureManager* textureManager, std::map<int, int>& 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<unsigned int>(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<const Nif::Property*>& properties,
static void applyMaterialProperties(osg::Node* node, const std::vector<const Nif::Property*>& properties,
bool hasVertexColors, int animflags)
{
osg::StateSet* stateset = node->getOrCreateStateSet();
@ -1550,22 +1556,19 @@ namespace NifOsg
};
osg::ref_ptr<osg::Node> Loader::load(Nif::NIFFilePtr file, TextKeyMap *textKeys)
osg::ref_ptr<osg::Node> 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<osg::Node> Loader::loadAsSkeleton(Nif::NIFFilePtr file, TextKeyMap *textKeys)
osg::ref_ptr<osg::Node> 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);
}
}

@ -6,6 +6,9 @@
#include <components/nifcache/nifcache.hpp> // NIFFilePtr
#include <osg/ref_ptr>
#include <osg/Referenced>
#include "controller.hpp"
namespace osg
{
@ -21,30 +24,52 @@ namespace NifOsg
{
typedef std::multimap<float,std::string> 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<std::string, osg::ref_ptr<SourcedKeyframeController> > 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<osg::Node> load(Nif::NIFFilePtr file, TextKeyMap* textKeys = NULL);
static osg::ref_ptr<osg::Node> 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<osg::Node> loadAsSkeleton(Nif::NIFFilePtr file, TextKeyMap* textKeys = NULL);
static osg::ref_ptr<osg::Node> 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:

@ -82,10 +82,7 @@ namespace Resource
// TODO: add support for non-NIF formats
NifOsg::Loader loader;
loader.mTextureManager = mTextureManager;
osg::ref_ptr<const osg::Node> 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<const osg::Node> 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<const NifOsg::KeyframeHolder> 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<NifOsg::KeyframeHolder> 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);

@ -7,6 +7,8 @@
#include <osg/ref_ptr>
#include <osg/Node>
#include <components/nifosg/nifloader.hpp>
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<const NifOsg::KeyframeHolder> 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<std::string, osg::ref_ptr<const osg::Node> > Index;
Index mIndex;
typedef std::map<std::string, osg::ref_ptr<const NifOsg::KeyframeHolder> > KeyframeIndex;
KeyframeIndex mKeyframeIndex;
};
}

Loading…
Cancel
Save