Refactor controllers, now part of the scene graph as UpdateCallbacks

Practical benefits:
- The controller update is now run automatically
- Creating an instance of a scene graph should now work properly using the defined copy constructors
pull/638/head
scrawl 10 years ago
parent af27a10b0c
commit 4957ceeb1d

@ -112,15 +112,11 @@ int main(int argc, char** argv)
//osgDB::writeNodeFile(*newNode, "out.osg");
std::vector<NifOsg::Controller > controllers;
osg::Group* newNode = new osg::Group;
NifOsg::Loader loader;
loader.resourceManager = &resourceMgr;
loader.loadAsSkeleton(nif, newNode);
for (unsigned int i=0; i<loader.mControllers.size(); ++i)
controllers.push_back(loader.mControllers[i]);
osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform;
root->addChild(trans);
@ -137,6 +133,8 @@ int main(int argc, char** argv)
viewer.setCameraManipulator(new osgGA::TrackballManipulator());
viewer.addEventHandler(new WireframeKeyHandler(root));
//viewer.getCamera()->setCullMask()
// We're going to change this from the event callback, set the variance to DYNAMIC so that
// we don't interfere with the draw thread.
root->getOrCreateStateSet()->setDataVariance(osg::Node::DYNAMIC);
@ -148,9 +146,6 @@ int main(int argc, char** argv)
//trans->setAttitude(osg::Quat(viewer.getFrameStamp()->getSimulationTime()*5, osg::Vec3f(0,0,1)));
viewer.frame();
for (unsigned int i=0; i<controllers.size(); ++i)
controllers[i].update();
}
return 0;

@ -30,7 +30,7 @@ void CSVRender::UnpagedWorldspaceWidget::update()
/// \todo deal with mSunlight and mFog/mForDensity
//flagAsModified();
flagAsModified();
}
CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& cellId, CSMDoc::Document& document, QWidget* parent)

@ -48,7 +48,53 @@ float ControllerFunction::calculate(float value)
return value;
}
osg::Quat KeyframeControllerValue::interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time)
FrameTimeSource::FrameTimeSource()
: mLastTime(0.0)
{
}
float FrameTimeSource::getValue(osg::NodeVisitor *nv)
{
// TODO: dt could be computed globally instead of once per instance
double time = nv->getFrameStamp()->getReferenceTime();
float dt = static_cast<float>(time - mLastTime);
mLastTime = time;
return dt;
}
KeyframeController::KeyframeController()
{
}
KeyframeController::KeyframeController(const KeyframeController &copy, const osg::CopyOp &copyop)
: osg::NodeCallback(copy, copyop)
, Controller(copy)
, mRotations(copy.mRotations)
, mXRotations(copy.mXRotations)
, mYRotations(copy.mYRotations)
, mZRotations(copy.mZRotations)
, mTranslations(copy.mTranslations)
, mScales(copy.mScales)
, mNif(copy.mNif)
, mInitialQuat(copy.mInitialQuat)
, mInitialScale(copy.mInitialScale)
{
}
KeyframeController::KeyframeController(const Nif::NIFFilePtr &nif, const Nif::NiKeyframeData *data,
osg::Quat initialQuat, float initialScale)
: mRotations(&data->mRotations)
, mXRotations(&data->mXRotations)
, mYRotations(&data->mYRotations)
, mZRotations(&data->mZRotations)
, mTranslations(&data->mTranslations)
, mScales(&data->mScales)
, mNif(nif)
, mInitialQuat(initialQuat)
, mInitialScale(initialScale)
{ }
osg::Quat KeyframeController::interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time)
{
if(time <= keys.begin()->first)
return keys.begin()->second.mValue;
@ -81,7 +127,7 @@ osg::Quat KeyframeControllerValue::interpKey(const Nif::QuaternionKeyMap::MapTyp
return keys.rbegin()->second.mValue;
}
osg::Quat KeyframeControllerValue::getXYZRotation(float time) const
osg::Quat KeyframeController::getXYZRotation(float time) const
{
float xrot = interpKey(mXRotations->mKeys, time);
float yrot = interpKey(mYRotations->mKeys, time);
@ -92,96 +138,108 @@ osg::Quat KeyframeControllerValue::getXYZRotation(float time) const
return (zr*yr*xr);
}
KeyframeControllerValue::KeyframeControllerValue(osg::Node *target, const Nif::NIFFilePtr &nif, const Nif::NiKeyframeData *data,
osg::Quat initialQuat, float initialScale)
: NodeTargetValue(target)
, mRotations(&data->mRotations)
, mXRotations(&data->mXRotations)
, mYRotations(&data->mYRotations)
, mZRotations(&data->mZRotations)
, mTranslations(&data->mTranslations)
, mScales(&data->mScales)
, mNif(nif)
, mInitialQuat(initialQuat)
, mInitialScale(initialScale)
{ }
osg::Vec3f KeyframeControllerValue::getTranslation(float time) const
osg::Vec3f KeyframeController::getTranslation(float time) const
{
if(mTranslations->mKeys.size() > 0)
return interpKey(mTranslations->mKeys, time);
osg::MatrixTransform* trans = static_cast<osg::MatrixTransform*>(mNode);
return trans->getMatrix().getTrans();
return osg::Vec3f();
}
void KeyframeControllerValue::setValue(float time)
void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv)
{
osg::MatrixTransform* trans = static_cast<osg::MatrixTransform*>(mNode);
osg::Matrix mat = trans->getMatrix();
if(mRotations->mKeys.size() > 0)
mat.setRotate(interpKey(mRotations->mKeys, time));
else if (!mXRotations->mKeys.empty() || !mYRotations->mKeys.empty() || !mZRotations->mKeys.empty())
mat.setRotate(getXYZRotation(time));
else
mat.setRotate(mInitialQuat);
// let's hope no one's using multiple KeyframeControllers on the same node (not that would make any sense...)
float scale = mInitialScale;
if(mScales->mKeys.size() > 0)
scale = interpKey(mScales->mKeys, time);
if (hasInput())
{
osg::MatrixTransform* trans = static_cast<osg::MatrixTransform*>(node);
osg::Matrix mat = trans->getMatrix();
float time = getInputValue(nv);
if(mRotations->mKeys.size() > 0)
mat.setRotate(interpKey(mRotations->mKeys, time));
else if (!mXRotations->mKeys.empty() || !mYRotations->mKeys.empty() || !mZRotations->mKeys.empty())
mat.setRotate(getXYZRotation(time));
else
mat.setRotate(mInitialQuat);
// let's hope no one's using multiple KeyframeControllers on the same node (not that would make any sense...)
float scale = mInitialScale;
if(mScales->mKeys.size() > 0)
scale = interpKey(mScales->mKeys, time);
for (int i=0;i<3;++i)
for (int j=0;j<3;++j)
mat(i,j) *= scale;
if(mTranslations->mKeys.size() > 0)
mat.setTrans(interpKey(mTranslations->mKeys, time));
trans->setMatrix(mat);
}
for (int i=0;i<3;++i)
for (int j=0;j<3;++j)
mat(i,j) *= scale;
traverse(node, nv);
}
if(mTranslations->mKeys.size() > 0)
mat.setTrans(interpKey(mTranslations->mKeys, time));
trans->setMatrix(mat);
Controller::Controller()
{
}
Controller::Controller(boost::shared_ptr<ControllerSource> src, boost::shared_ptr<ControllerValue> dest, boost::shared_ptr<ControllerFunction> function)
: mSource(src)
, mDestValue(dest)
, mFunction(function)
bool Controller::hasInput() const
{
return mSource.get() != NULL;
}
float Controller::getInputValue(osg::NodeVisitor* nv)
{
return mFunction->calculate(mSource->getValue(nv));
}
void Controller::update()
GeomMorpherController::GeomMorpherController()
{
if (mSource.get())
{
mDestValue->setValue(mFunction->calculate(mSource->getValue()));
}
}
GeomMorpherControllerValue::GeomMorpherControllerValue(osgAnimation::MorphGeometry *geom, const Nif::NiMorphData* morphData)
: mGeom(geom)
, mMorphs(morphData->mMorphs)
GeomMorpherController::GeomMorpherController(const GeomMorpherController &copy, const osg::CopyOp &copyop)
: osg::Drawable::UpdateCallback(copy, copyop)
, Controller(copy)
, mMorphs(copy.mMorphs)
{
}
GeomMorpherController::GeomMorpherController(const Nif::NiMorphData *data)
: mMorphs(data->mMorphs)
{
}
void GeomMorpherControllerValue::setValue(float time)
void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable)
{
if (mMorphs.size() <= 1)
return;
int i = 0;
for (std::vector<Nif::NiMorphData::MorphData>::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i)
osgAnimation::MorphGeometry* morphGeom = dynamic_cast<osgAnimation::MorphGeometry*>(drawable);
if (morphGeom)
{
float val = 0;
if (!it->mData.mKeys.empty())
val = interpKey(it->mData.mKeys, time);
val = std::max(0.f, std::min(1.f, val));
mGeom->setWeight(i, val);
if (hasInput())
{
if (mMorphs.size() <= 1)
return;
float input = getInputValue(nv);
int i = 0;
for (std::vector<Nif::NiMorphData::MorphData>::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i)
{
float val = 0;
if (!it->mData.mKeys.empty())
val = interpKey(it->mData.mKeys, input);
val = std::max(0.f, std::min(1.f, val));
morphGeom->setWeight(i, val);
}
}
morphGeom->transformSoftwareMethod();
}
}
UVControllerValue::UVControllerValue(osg::StateSet *target, const Nif::NiUVData *data, std::set<int> textureUnits)
: mStateSet(target)
, mUTrans(data->mKeyList[0])
UVController::UVController()
{
}
UVController::UVController(const Nif::NiUVData *data, std::set<int> textureUnits)
: mUTrans(data->mKeyList[0])
, mVTrans(data->mKeyList[1])
, mUScale(data->mKeyList[2])
, mVScale(data->mKeyList[3])
@ -189,26 +247,58 @@ UVControllerValue::UVControllerValue(osg::StateSet *target, const Nif::NiUVData
{
}
void UVControllerValue::setValue(float value)
UVController::UVController(const UVController& copy, const osg::CopyOp& copyop)
: osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), Controller(copy)
, mUTrans(copy.mUTrans)
, mVTrans(copy.mVTrans)
, mUScale(copy.mUScale)
, mVScale(copy.mVScale)
, mTextureUnits(copy.mTextureUnits)
{
float uTrans = interpKey(mUTrans.mKeys, value, 0.0f);
float vTrans = interpKey(mVTrans.mKeys, value, 0.0f);
float uScale = interpKey(mUScale.mKeys, value, 1.0f);
float vScale = interpKey(mVScale.mKeys, value, 1.0f);
osg::Matrixf mat = osg::Matrixf::scale(uScale, vScale, 1);
mat.setTrans(uTrans, vTrans, 0);
osg::TexMat* texMat = new osg::TexMat;
texMat->setMatrix(mat);
}
for (std::set<int>::const_iterator it = mTextureUnits.begin(); it != mTextureUnits.end(); ++it)
void UVController::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (hasInput())
{
mStateSet->setTextureAttributeAndModes(*it, texMat, osg::StateAttribute::ON);
osg::StateSet* stateset = node->getStateSet();
float value = getInputValue(nv);
float uTrans = interpKey(mUTrans.mKeys, value, 0.0f);
float vTrans = interpKey(mVTrans.mKeys, value, 0.0f);
float uScale = interpKey(mUScale.mKeys, value, 1.0f);
float vScale = interpKey(mVScale.mKeys, value, 1.0f);
osg::Matrixf mat = osg::Matrixf::scale(uScale, vScale, 1);
mat.setTrans(uTrans, vTrans, 0);
osg::TexMat* texMat = new osg::TexMat;
texMat->setMatrix(mat);
for (std::set<int>::const_iterator it = mTextureUnits.begin(); it != mTextureUnits.end(); ++it)
{
stateset->setTextureAttributeAndModes(*it, texMat, osg::StateAttribute::ON);
}
}
traverse(node, nv);
}
VisController::VisController(const Nif::NiVisData *data)
: mData(data->mVis)
{
}
VisController::VisController()
{
}
VisController::VisController(const VisController &copy, const osg::CopyOp &copyop)
: osg::NodeCallback(copy, copyop)
, Controller(copy)
, mData(copy.mData)
{
}
bool VisControllerValue::calculate(float time) const
bool VisController::calculate(float time) const
{
if(mData.size() == 0)
return true;
@ -221,77 +311,140 @@ bool VisControllerValue::calculate(float time) const
return mData.back().isSet;
}
void VisControllerValue::setValue(float time)
void VisController::operator() (osg::Node* node, osg::NodeVisitor* nv)
{
if (hasInput())
{
bool vis = calculate(getInputValue(nv));
node->setNodeMask(vis ? ~0 : 0);
}
traverse(node, nv);
}
AlphaController::AlphaController(const Nif::NiFloatData *data)
: mData(data->mKeyList)
{
bool vis = calculate(time);
mNode->setNodeMask(vis ? ~0 : 0);
}
AlphaControllerValue::AlphaControllerValue(osg::StateSet *target, const Nif::NiFloatData *data)
: mTarget(target)
, mData(data->mKeyList)
AlphaController::AlphaController()
{
}
void AlphaControllerValue::setValue(float time)
AlphaController::AlphaController(const AlphaController &copy, const osg::CopyOp &copyop)
: osg::NodeCallback(copy, copyop), ValueInterpolator(), Controller(copy)
{
float value = interpKey(mData.mKeys, time);
osg::Material* mat = dynamic_cast<osg::Material*>(mTarget->getAttribute(osg::StateAttribute::MATERIAL));
if (!mat)
return;
}
osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK);
diffuse.a() = value;
mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse);
void AlphaController::operator () (osg::Node* node, osg::NodeVisitor* nv)
{
if (hasInput())
{
osg::StateSet* stateset = node->getStateSet();
float value = interpKey(mData.mKeys, getInputValue(nv));
osg::Material* mat = dynamic_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL));
if (mat)
{
osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK);
diffuse.a() = value;
mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse);
}
}
traverse(node, nv);
}
MaterialColorControllerValue::MaterialColorControllerValue(osg::StateSet *target, const Nif::NiPosData *data)
: mTarget(target), mData(data->mKeyList)
MaterialColorController::MaterialColorController(const Nif::NiPosData *data)
: mData(data->mKeyList)
{
}
MaterialColorController::MaterialColorController()
{
}
void MaterialColorControllerValue::setValue(float time)
MaterialColorController::MaterialColorController(const MaterialColorController &copy, const osg::CopyOp &copyop)
: osg::NodeCallback(copy, copyop), Controller(copy)
, mData(copy.mData)
{
osg::Vec3f value = interpKey(mData.mKeys, time);
osg::Material* mat = dynamic_cast<osg::Material*>(mTarget->getAttribute(osg::StateAttribute::MATERIAL));
if (!mat)
return;
}
osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK);
diffuse.set(value.x(), value.y(), value.z(), diffuse.a());
mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse);
void MaterialColorController::operator() (osg::Node* node, osg::NodeVisitor* nv)
{
if (hasInput())
{
osg::StateSet* stateset = node->getStateSet();
osg::Vec3f value = interpKey(mData.mKeys, getInputValue(nv));
osg::Material* mat = dynamic_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL));
if (mat)
{
osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK);
diffuse.set(value.x(), value.y(), value.z(), diffuse.a());
mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse);
}
}
traverse(node, nv);
}
FlipControllerValue::FlipControllerValue(osg::StateSet* target, const Nif::NiFlipController *ctrl,
std::vector<osg::ref_ptr<osg::Image> > textures)
FlipController::FlipController(const Nif::NiFlipController *ctrl, std::vector<osg::ref_ptr<osg::Image> > textures)
: mTexSlot(ctrl->mTexSlot)
, mDelta(ctrl->mDelta)
, mTextures(textures)
, mTarget(target)
{
}
void FlipControllerValue::setValue(float time)
FlipController::FlipController()
{
}
FlipController::FlipController(const FlipController &copy, const osg::CopyOp &copyop)
: osg::NodeCallback(copy, copyop)
, Controller(copy)
, mTexSlot(copy.mTexSlot)
, mDelta(copy.mDelta)
, mTextures(copy.mTextures)
{
if (mDelta == 0)
return;
int curTexture = int(time / mDelta) % mTextures.size();
osg::Texture2D* tex = dynamic_cast<osg::Texture2D*>(mTarget->getAttribute(osg::StateAttribute::TEXTURE));
if (!tex)
return;
tex->setImage(mTextures[curTexture].get());
}
ParticleSystemControllerValue::ParticleSystemControllerValue(osgParticle::Emitter *emitter, const Nif::NiParticleSystemController *ctrl)
: mEmitter(emitter), mEmitStart(ctrl->startTime), mEmitStop(ctrl->stopTime)
void FlipController::operator() (osg::Node* node, osg::NodeVisitor* nv)
{
if (hasInput() && mDelta != 0)
{
osg::StateSet* stateset = node->getStateSet();
int curTexture = int(getInputValue(nv) / mDelta) % mTextures.size();
osg::Texture2D* tex = dynamic_cast<osg::Texture2D*>(stateset->getAttribute(osg::StateAttribute::TEXTURE));
if (tex)
tex->setImage(mTextures[curTexture].get());
}
traverse(node, nv);
}
ParticleSystemController::ParticleSystemController(const Nif::NiParticleSystemController *ctrl)
: mEmitStart(ctrl->startTime), mEmitStop(ctrl->stopTime)
{
}
ParticleSystemController::ParticleSystemController()
{
}
void ParticleSystemControllerValue::setValue(float time)
ParticleSystemController::ParticleSystemController(const ParticleSystemController &copy, const osg::CopyOp &copyop)
: osg::NodeCallback(copy, copyop)
, Controller(copy)
, mEmitStart(copy.mEmitStart)
, mEmitStop(copy.mEmitStop)
{
mEmitter->setEnabled(time >= mEmitStart && time < mEmitStop);
}
void ParticleSystemController::operator() (osg::Node* node, osg::NodeVisitor* nv)
{
if (hasInput())
{
osgParticle::ParticleProcessor* emitter = dynamic_cast<osgParticle::ParticleProcessor*>(node);
float time = getInputValue(nv);
if (emitter)
emitter->setEnabled(time >= mEmitStart && time < mEmitStop);
}
traverse(node, nv);
}
}

@ -17,6 +17,9 @@
#include <osg/ref_ptr>
#include <osg/Timer>
#include <osg/StateSet>
#include <osg/NodeCallback>
#include <osg/Drawable>
namespace osg
@ -93,76 +96,49 @@ namespace NifOsg
class ControllerSource
{
public:
virtual float getValue() const = 0;
virtual float getValue(osg::NodeVisitor* nv) = 0;
};
// FIXME: Should return a dt instead of time
class FrameTimeSource : public ControllerSource
{
public:
virtual float getValue() const
{
return mTimer.time_s();
}
FrameTimeSource();
virtual float getValue(osg::NodeVisitor* nv);
private:
osg::Timer mTimer;
};
class ControllerValue
{
public:
virtual void setValue(float value) = 0;
double mLastTime;
};
class Controller
{
public:
Controller (boost::shared_ptr<ControllerSource> src, boost::shared_ptr<ControllerValue> dest,
boost::shared_ptr<ControllerFunction> function);
Controller();
bool hasInput() const;
virtual void update();
float getInputValue(osg::NodeVisitor* nv);
boost::shared_ptr<ControllerSource> mSource;
boost::shared_ptr<ControllerValue> mDestValue;
// The source value gets passed through this function before it's passed on to the DestValue.
boost::shared_ptr<ControllerFunction> mFunction;
};
// FIXME: Should be with other general extensions.
class NodeTargetValue : public ControllerValue
class GeomMorpherController : public osg::Drawable::UpdateCallback, public Controller, public ValueInterpolator
{
protected:
// TODO: get rid of target pointers, which are incompatible with a copy constructor we will need later
// instead, controllers can be a Node added as child of their target
osg::Node *mNode;
public:
NodeTargetValue(osg::Node *target) : mNode(target)
{ }
virtual osg::Vec3f getTranslation(float value) const = 0;
osg::Node *getNode() const
{ return mNode; }
};
GeomMorpherController(const Nif::NiMorphData* data);
GeomMorpherController();
GeomMorpherController(const GeomMorpherController& copy, const osg::CopyOp& copyop);
class GeomMorpherControllerValue : public ControllerValue, public ValueInterpolator
{
public:
// FIXME: don't copy the morph data?
GeomMorpherControllerValue(osgAnimation::MorphGeometry* geom, const Nif::NiMorphData *data);
META_Object(NifOsg, GeomMorpherController)
virtual void setValue(float time);
virtual void update(osg::NodeVisitor* nv, osg::Drawable* drawable);
private:
osgAnimation::MorphGeometry* mGeom;
std::vector<Nif::NiMorphData::MorphData> mMorphs;
};
class KeyframeControllerValue : public NodeTargetValue, public ValueInterpolator
class KeyframeController : public osg::NodeCallback, public Controller, public ValueInterpolator
{
private:
const Nif::QuaternionKeyMap* mRotations;
@ -185,31 +161,39 @@ namespace NifOsg
public:
/// @note The NiKeyFrameData must be valid as long as this KeyframeController exists.
KeyframeControllerValue(osg::Node *target, const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data,
KeyframeController(const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data,
osg::Quat initialQuat, float initialScale);
KeyframeController();
KeyframeController(const KeyframeController& copy, const osg::CopyOp& copyop);
META_Object(NifOsg, KeyframeController)
virtual osg::Vec3f getTranslation(float time) const;
virtual void setValue(float time);
virtual void operator() (osg::Node*, osg::NodeVisitor*);
};
class UVControllerValue : public ControllerValue, ValueInterpolator
// Note we're using NodeCallback instead of StateSet::Callback because the StateSet callback doesn't support nesting
struct UVController : public osg::NodeCallback, public Controller, public ValueInterpolator
{
public:
UVController();
UVController(const UVController&,const osg::CopyOp& = osg::CopyOp::SHALLOW_COPY);
UVController(const Nif::NiUVData *data, std::set<int> textureUnits);
META_Object(NifOsg,UVController)
virtual void operator() (osg::Node*, osg::NodeVisitor*);
private:
osg::StateSet* mStateSet;
Nif::FloatKeyMap mUTrans;
Nif::FloatKeyMap mVTrans;
Nif::FloatKeyMap mUScale;
Nif::FloatKeyMap mVScale;
std::set<int> mTextureUnits;
public:
UVControllerValue(osg::StateSet* target, const Nif::NiUVData *data, std::set<int> textureUnits);
virtual void setValue(float value);
};
class VisControllerValue : public NodeTargetValue
class VisController : public osg::NodeCallback, public Controller
{
private:
std::vector<Nif::NiVisData::VisData> mData;
@ -217,65 +201,75 @@ namespace NifOsg
bool calculate(float time) const;
public:
VisControllerValue(osg::Node *target, const Nif::NiVisData *data)
: NodeTargetValue(target)
, mData(data->mVis)
{ }
VisController(const Nif::NiVisData *data);
VisController();
VisController(const VisController& copy, const osg::CopyOp& copyop);
virtual osg::Vec3f getTranslation(float time) const
{ return osg::Vec3f(); }
META_Object(NifOsg, VisController)
virtual void setValue(float time);
virtual void operator() (osg::Node* node, osg::NodeVisitor* nv);
};
class AlphaControllerValue : public ControllerValue, public ValueInterpolator
class AlphaController : public osg::NodeCallback, public Controller, public ValueInterpolator
{
private:
osg::StateSet* mTarget;
Nif::FloatKeyMap mData;
public:
AlphaControllerValue(osg::StateSet* target, const Nif::NiFloatData *data);
AlphaController(const Nif::NiFloatData *data);
AlphaController();
AlphaController(const AlphaController& copy, const osg::CopyOp& copyop);
virtual void operator() (osg::Node* node, osg::NodeVisitor* nv);
virtual void setValue(float time);
META_Object(NifOsg, AlphaController)
};
class MaterialColorControllerValue : public ControllerValue, public ValueInterpolator
class MaterialColorController : public osg::NodeCallback, public Controller, public ValueInterpolator
{
private:
osg::StateSet* mTarget;
Nif::Vector3KeyMap mData;
public:
MaterialColorControllerValue(osg::StateSet* target, const Nif::NiPosData *data);
MaterialColorController(const Nif::NiPosData *data);
MaterialColorController();
MaterialColorController(const MaterialColorController& copy, const osg::CopyOp& copyop);
virtual void setValue(float time);
META_Object(NifOsg, MaterialColorController)
virtual void operator() (osg::Node* node, osg::NodeVisitor* nv);
};
// untested
class FlipControllerValue : public ControllerValue
class FlipController : public osg::NodeCallback, public Controller
{
private:
osg::StateSet* mTarget;
int mTexSlot;
float mDelta;
std::vector<osg::ref_ptr<osg::Image> > mTextures;
public:
FlipControllerValue(osg::StateSet* target, const Nif::NiFlipController* ctrl, std::vector<osg::ref_ptr<osg::Image> > textures);
FlipController(const Nif::NiFlipController* ctrl, std::vector<osg::ref_ptr<osg::Image> > textures);
FlipController();
FlipController(const FlipController& copy, const osg::CopyOp& copyop);
META_Object(NifOsg, FlipController)
virtual void setValue(float time);
virtual void operator() (osg::Node* node, osg::NodeVisitor* nv);
};
class ParticleSystemControllerValue : public ControllerValue
class ParticleSystemController : public osg::NodeCallback, public Controller
{
public:
ParticleSystemControllerValue(osgParticle::Emitter* emitter, const Nif::NiParticleSystemController* ctrl);
ParticleSystemController(const Nif::NiParticleSystemController* ctrl);
ParticleSystemController();
ParticleSystemController(const ParticleSystemController& copy, const osg::CopyOp& copyop);
META_Object(NifOsg, ParticleSystemController)
virtual void setValue(float time);
virtual void operator() (osg::Node* node, osg::NodeVisitor* nv);
private:
osgParticle::Emitter* mEmitter;
float mEmitStart;
float mEmitStop;
};

@ -285,17 +285,13 @@ namespace NifOsg
}
}
void Loader::createController(const Nif::Controller *ctrl, boost::shared_ptr<ControllerValue> value, int animflags)
void Loader::setupController(const Nif::Controller* ctrl, Controller* toSetup, int animflags)
{
// FIXME animflags currently not passed to this function
//bool autoPlay = animflags & Nif::NiNode::AnimFlag_AutoPlay;
boost::shared_ptr<ControllerSource> src(new FrameTimeSource); // if autoPlay
//if (autoPlay)
toSetup->mSource = boost::shared_ptr<ControllerSource>(new FrameTimeSource);
boost::shared_ptr<ControllerFunction> function (new ControllerFunction(ctrl
, 0/*autoPlay*/));
//scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength);
mControllers.push_back(Controller(src, value, function));
toSetup->mFunction = boost::shared_ptr<ControllerFunction>(new ControllerFunction(ctrl, 1 /*autoPlay*/));
}
void Loader::handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton,
@ -308,7 +304,6 @@ namespace NifOsg
transformNode = bone;
bone->setMatrix(toMatrix(nifNode->trafo));
bone->setName(nifNode->name);
bone->setUpdateCallback(new UpdateBone);
bone->setInvBindMatrixInSkeletonSpace(osg::Matrixf::inverse(getWorldTransform(nifNode)));
}
else
@ -332,6 +327,7 @@ namespace NifOsg
// We could probably skip hidden nodes entirely if they don't have a VisController that
// might make them visible later
// FIXME: this disables update callbacks, so VisController no longer works
if (nifNode->flags & Nif::NiNode::Flag_Hidden)
transformNode->setNodeMask(0);
@ -358,6 +354,10 @@ namespace NifOsg
if (!nifNode->controller.empty())
handleNodeControllers(nifNode, transformNode, animflags);
// Added last so the changes from KeyframeControllers are taken into account
if (osgAnimation::Bone* bone = dynamic_cast<osgAnimation::Bone*>(transformNode.get()))
bone->addUpdateCallback(new UpdateBone);
const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(nifNode);
if(ninode)
{
@ -382,9 +382,12 @@ namespace NifOsg
std::set<int> texUnits;
for (std::map<int, int>::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it)
texUnits.insert(it->first);
boost::shared_ptr<ControllerValue> dest(new UVControllerValue(transformNode->getOrCreateStateSet()
, uvctrl->data.getPtr(), texUnits));
createController(uvctrl, dest, animflags);
osg::ref_ptr<UVController> ctrl = new UVController(uvctrl->data.getPtr(), texUnits);
setupController(uvctrl, ctrl, animflags);
transformNode->getOrCreateStateSet()->setDataVariance(osg::StateSet::DYNAMIC);
transformNode->addUpdateCallback(ctrl);
}
}
}
@ -406,23 +409,27 @@ namespace NifOsg
std::cerr << "Warning: multiple KeyframeControllers on the same node" << std::endl;
continue;
}
boost::shared_ptr<ControllerValue> dest(new KeyframeControllerValue(transformNode, mNif, key->data.getPtr(),
transformNode->getMatrix().getRotate(), nifNode->trafo.scale));
osg::ref_ptr<KeyframeController> callback(new KeyframeController(mNif, key->data.getPtr(),
transformNode->getMatrix().getRotate(), nifNode->trafo.scale));
setupController(key, callback, animflags);
transformNode->addUpdateCallback(callback);
createController(key, dest, animflags);
seenKeyframeCtrl = true;
}
}
else if (ctrl->recType == Nif::RC_NiVisController)
{
const Nif::NiVisController* visctrl = static_cast<const Nif::NiVisController*>(ctrl.getPtr());
boost::shared_ptr<ControllerValue> dest(new VisControllerValue(transformNode, visctrl->data.getPtr()));
createController(visctrl, dest, animflags);
osg::ref_ptr<VisController> callback(new VisController(visctrl->data.getPtr()));
setupController(visctrl, callback, animflags);
transformNode->addUpdateCallback(callback);
}
}
}
void Loader::handleMaterialControllers(const Nif::Property *materialProperty, osg::StateSet *stateset, int animflags)
void Loader::handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, osg::StateSet *stateset, int animflags)
{
for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next)
{
@ -431,21 +438,25 @@ namespace NifOsg
if (ctrl->recType == Nif::RC_NiAlphaController)
{
const Nif::NiAlphaController* alphactrl = static_cast<const Nif::NiAlphaController*>(ctrl.getPtr());
boost::shared_ptr<ControllerValue> dest(new AlphaControllerValue(stateset, alphactrl->data.getPtr()));
createController(alphactrl, dest, animflags);
osg::ref_ptr<AlphaController> ctrl(new AlphaController(alphactrl->data.getPtr()));
setupController(alphactrl, ctrl, animflags);
stateset->setDataVariance(osg::StateSet::DYNAMIC);
node->addUpdateCallback(ctrl);
}
else if (ctrl->recType == Nif::RC_NiMaterialColorController)
{
const Nif::NiMaterialColorController* matctrl = static_cast<const Nif::NiMaterialColorController*>(ctrl.getPtr());
boost::shared_ptr<ControllerValue> dest(new MaterialColorControllerValue(stateset, matctrl->data.getPtr()));
createController(matctrl, dest, animflags);
osg::ref_ptr<MaterialColorController> ctrl(new MaterialColorController(matctrl->data.getPtr()));
setupController(matctrl, ctrl, animflags);
stateset->setDataVariance(osg::StateSet::DYNAMIC);
node->addUpdateCallback(ctrl);
}
else
std::cerr << "Unexpected material controller " << ctrl->recType << std::endl;
}
}
void Loader::handleTextureControllers(const Nif::Property *texProperty, osg::StateSet *stateset, int animflags)
void Loader::handleTextureControllers(const Nif::Property *texProperty, osg::Node* node, osg::StateSet *stateset, int animflags)
{
for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next)
{
@ -470,8 +481,10 @@ namespace NifOsg
osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->get(filename.c_str()), opts);
textures.push_back(osg::ref_ptr<osg::Image>(result.getImage()));
}
boost::shared_ptr<ControllerValue> dest(new FlipControllerValue(stateset, flipctrl, textures));
createController(flipctrl, dest, animflags);
osg::ref_ptr<FlipController> callback(new FlipController(flipctrl, textures));
setupController(ctrl.getPtr(), callback, animflags);
stateset->setDataVariance(osg::StateSet::DYNAMIC);
node->addUpdateCallback(callback);
}
else
std::cerr << "Unexpected texture controller " << ctrl->recName << std::endl;
@ -577,7 +590,9 @@ namespace NifOsg
// If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster.
parentNode->addChild(emitter);
createController(partctrl, boost::shared_ptr<ControllerValue>(new ParticleSystemControllerValue(emitter, partctrl)), animflags);
osg::ref_ptr<ParticleSystemController> callback(new ParticleSystemController(partctrl));
setupController(partctrl, callback, animflags);
emitter->setUpdateCallback(callback);
// ----------- affector (must be after emitters in the scene graph)
osgParticle::ModularProgram* program = new osgParticle::ModularProgram;
@ -615,14 +630,16 @@ namespace NifOsg
// -----------
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
geode->addDrawable(partsys);
std::vector<const Nif::Property*> materialProps;
collectMaterialProperties(nifNode, materialProps);
applyMaterialProperties(partsys->getOrCreateStateSet(), materialProps, true, animflags);
applyMaterialProperties(geode, materialProps, true, animflags);
partsys->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
partsys->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
geode->addDrawable(partsys);
if (rf == osgParticle::ParticleProcessor::RELATIVE_RF)
parentNode->addChild(geode);
@ -640,7 +657,7 @@ namespace NifOsg
parentNode->addChild(updater);
}
void Loader::triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, const std::map<int, int>& boundTextures, int animflags)
void Loader::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();
@ -720,7 +737,7 @@ namespace NifOsg
// above the actual renderable would be tedious.
std::vector<const Nif::Property*> materialProps;
collectMaterialProperties(triShape, materialProps);
applyMaterialProperties(geometry->getOrCreateStateSet(), materialProps, !data->colors.empty(), animflags);
applyMaterialProperties(parentGeode, materialProps, !data->colors.empty(), animflags);
}
void Loader::handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map<int, int>& boundTextures, int animflags)
@ -733,10 +750,11 @@ namespace NifOsg
if(ctrl->recType == Nif::RC_NiGeomMorpherController && ctrl->flags & Nif::NiNode::ControllerFlag_Active)
{
geometry = handleMorphGeometry(static_cast<const Nif::NiGeomMorpherController*>(ctrl.getPtr()));
boost::shared_ptr<ControllerValue> value(
new GeomMorpherControllerValue(static_cast<osgAnimation::MorphGeometry*>(geometry.get()),
static_cast<const Nif::NiGeomMorpherController*>(ctrl.getPtr())->data.getPtr()));
createController(ctrl.getPtr(), value, 0);
osg::ref_ptr<GeomMorpherController> morphctrl = new GeomMorpherController(
static_cast<const Nif::NiGeomMorpherController*>(ctrl.getPtr())->data.getPtr());
setupController(ctrl.getPtr(), morphctrl, animflags);
geometry->setUpdateCallback(morphctrl);
break;
}
} while(!(ctrl=ctrl->next).empty());
@ -744,9 +762,10 @@ namespace NifOsg
if (!geometry.get())
geometry = new osg::Geometry;
triShapeToGeometry(triShape, geometry, boundTextures, animflags);
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags);
geode->addDrawable(geometry);
parentNode->addChild(geode);
@ -754,8 +773,9 @@ namespace NifOsg
void Loader::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);
osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry);
triShapeToGeometry(triShape, geometry, boundTextures, animflags);
triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags);
osg::ref_ptr<osgAnimation::RigGeometry> rig(new osgAnimation::RigGeometry);
rig->setSourceGeometry(geometry);
@ -795,7 +815,6 @@ namespace NifOsg
osg::ref_ptr<osg::MatrixTransform> trans(new osg::MatrixTransform);
trans->setUpdateCallback(new InvertBoneMatrix());
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
geode->addDrawable(rig);
trans->addChild(geode);
@ -987,7 +1006,7 @@ namespace NifOsg
stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF);
boundTextures.erase(i);
}
handleTextureControllers(texprop, stateset, animflags);
handleTextureControllers(texprop, node, stateset, animflags);
}
break;
}
@ -1003,9 +1022,11 @@ namespace NifOsg
}
}
void Loader::applyMaterialProperties(osg::StateSet* stateset, const std::vector<const Nif::Property*>& properties,
void Loader::applyMaterialProperties(osg::Node* node, const std::vector<const Nif::Property*>& properties,
bool hasVertexColors, int animflags)
{
osg::StateSet* stateset = node->getOrCreateStateSet();
int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty
osg::Material* mat = new osg::Material;
mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF);
@ -1032,7 +1053,7 @@ namespace NifOsg
mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness);
if (!matprop->controller.empty())
handleMaterialControllers(matprop, stateset, animflags);
handleMaterialControllers(matprop, node, stateset, animflags);
break;
}

@ -9,8 +9,6 @@
#include <osg/Group>
#include "controller.hpp"
namespace osg
{
class Geometry;
@ -25,10 +23,12 @@ namespace Nif
class Node;
class NiTriShape;
class Property;
class Controller;
}
namespace NifOsg
{
class Controller;
/// The main class responsible for loading NIF files into an OSG-Scenegraph.
class Loader
@ -41,9 +41,6 @@ namespace NifOsg
const VFS::Manager* resourceManager;
// FIXME move
std::vector<Controller> mControllers;
private:
/// @param createSkeleton If true, use an osgAnimation::Bone for NIF nodes, otherwise an osg::MatrixTransform.
@ -54,9 +51,9 @@ namespace NifOsg
void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags);
void handleMaterialControllers(const Nif::Property* materialProperty, osg::StateSet* stateset, int animflags);
void handleMaterialControllers(const Nif::Property* materialProperty, osg::Node* node, osg::StateSet* stateset, int animflags);
void handleTextureControllers(const Nif::Property* texProperty, osg::StateSet* stateset, int animflags);
void handleTextureControllers(const Nif::Property* texProperty, osg::Node* node, osg::StateSet* stateset, int animflags);
void handleProperty (const Nif::Property* property, const Nif::Node* nifNode,
osg::Node* node, std::map<int, int>& boundTextures, int animflags);
@ -67,7 +64,7 @@ namespace NifOsg
void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map<int, int>& boundTextures, int animflags);
// Fills the vertex data for the given TriShape into the given Geometry.
void triShapeToGeometry(const Nif::NiTriShape* triShape, osg::Geometry* geom, const std::map<int, int>& boundTextures, int animflags);
void triShapeToGeometry(const Nif::NiTriShape* triShape, osg::Geometry* geom, osg::Geode* parentGeode, const std::map<int, int>& boundTextures, int animflags);
// Creates a skinned osg::Geometry object for the given TriShape, populates it, and attaches it to the given node.
void handleSkinnedTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map<int, int>& boundTextures, int animflags);
@ -75,10 +72,11 @@ namespace NifOsg
// Applies the Properties of the given nifNode onto the StateSet of the given OSG node.
void applyNodeProperties(const Nif::Node* nifNode, osg::Node* applyTo, std::map<int, int>& boundTextures, int animflags);
void applyMaterialProperties(osg::StateSet* stateset, const std::vector<const Nif::Property*>& properties,
void applyMaterialProperties(osg::Node* node, const std::vector<const Nif::Property*>& properties,
bool hasVertexColors, int animflags);
void createController(const Nif::Controller* ctrl, boost::shared_ptr<ControllerValue> value, int animflags);
// Set up the default input and controller function for the given controller.
void setupController(const Nif::Controller* ctrl, Controller* toSetup, int animflags);
Nif::NIFFilePtr mNif;

@ -39,6 +39,7 @@ ParticleShooter::ParticleShooter()
}
ParticleShooter::ParticleShooter(const osgParticle::Shooter &copy, const osg::CopyOp &copyop)
: osgParticle::Shooter(copy, copyop)
{
*this = copy;
}

Loading…
Cancel
Save