Port nifloader to the more efficient StateSetController

c++11
scrawl 10 years ago
parent 5dd1ab24fe
commit de2c85e0f8

@ -278,7 +278,7 @@ UVController::UVController(const Nif::NiUVData *data, std::set<int> textureUnits
}
UVController::UVController(const UVController& copy, const osg::CopyOp& copyop)
: osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), Controller(copy)
: osg::Object(copy, copyop), StateSetController(copy, copyop), Controller(copy)
, mUTrans(copy.mUTrans)
, mVTrans(copy.mVTrans)
, mUScale(copy.mUScale)
@ -287,11 +287,17 @@ UVController::UVController(const UVController& copy, const osg::CopyOp& copyop)
{
}
void UVController::operator()(osg::Node* node, osg::NodeVisitor* nv)
void UVController::setDefaults(osg::StateSet *stateset)
{
osg::TexMat* texMat = new osg::TexMat;
for (std::set<int>::const_iterator it = mTextureUnits.begin(); it != mTextureUnits.end(); ++it)
stateset->setTextureAttributeAndModes(*it, texMat, osg::StateAttribute::ON);
}
void UVController::apply(osg::StateSet* stateset, osg::NodeVisitor* nv)
{
if (hasInput())
{
osg::StateSet* stateset = getWritableStateSet(node);
float value = getInputValue(nv);
float uTrans = interpKey(mUTrans->mKeys, value, 0.0f);
float vTrans = interpKey(mVTrans->mKeys, value, 0.0f);
@ -301,15 +307,13 @@ void UVController::operator()(osg::Node* node, osg::NodeVisitor* nv)
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)
// setting once is enough because all other texture units share the same TexMat (see setDefaults).
if (mTextureUnits.size())
{
stateset->setTextureAttributeAndModes(*it, texMat, osg::StateAttribute::ON);
osg::TexMat* texMat = static_cast<osg::TexMat*>(stateset->getTextureAttribute(*mTextureUnits.begin(), osg::StateAttribute::TEXMAT));
texMat->setMatrix(mat);
}
}
traverse(node, nv);
}
VisController::VisController(const Nif::NiVisData *data)
@ -363,26 +367,21 @@ AlphaController::AlphaController()
}
AlphaController::AlphaController(const AlphaController &copy, const osg::CopyOp &copyop)
: osg::NodeCallback(copy, copyop), ValueInterpolator(), Controller(copy)
: StateSetController(copy, copyop), ValueInterpolator(), Controller(copy)
, mData(copy.mData)
{
}
void AlphaController::operator () (osg::Node* node, osg::NodeVisitor* nv)
void AlphaController::apply(osg::StateSet *stateset, osg::NodeVisitor *nv)
{
if (hasInput())
{
osg::StateSet* stateset = getWritableStateSet(node);
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);
}
osg::Material* mat = static_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL));
osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK);
diffuse.a() = value;
mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse);
}
traverse(node, nv);
}
MaterialColorController::MaterialColorController(const Nif::NiPosData *data)
@ -395,26 +394,21 @@ MaterialColorController::MaterialColorController()
}
MaterialColorController::MaterialColorController(const MaterialColorController &copy, const osg::CopyOp &copyop)
: osg::NodeCallback(copy, copyop), Controller(copy)
: StateSetController(copy, copyop), Controller(copy)
, mData(copy.mData)
{
}
void MaterialColorController::operator() (osg::Node* node, osg::NodeVisitor* nv)
void MaterialColorController::apply(osg::StateSet *stateset, osg::NodeVisitor *nv)
{
if (hasInput())
{
osg::StateSet* stateset = getWritableStateSet(node);
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);
}
osg::Material* mat = static_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL));
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);
}
FlipController::FlipController(const Nif::NiFlipController *ctrl, std::vector<osg::ref_ptr<osg::Texture2D> > textures)
@ -429,7 +423,7 @@ FlipController::FlipController()
}
FlipController::FlipController(const FlipController &copy, const osg::CopyOp &copyop)
: osg::NodeCallback(copy, copyop)
: StateSetController(copy, copyop)
, Controller(copy)
, mTexSlot(copy.mTexSlot)
, mDelta(copy.mDelta)
@ -437,15 +431,13 @@ FlipController::FlipController(const FlipController &copy, const osg::CopyOp &co
{
}
void FlipController::operator() (osg::Node* node, osg::NodeVisitor* nv)
void FlipController::apply(osg::StateSet* stateset, osg::NodeVisitor* nv)
{
if (hasInput() && mDelta != 0)
{
osg::StateSet* stateset = getWritableStateSet(node);
int curTexture = int(getInputValue(nv) / mDelta) % mTextures.size();
stateset->setTextureAttribute(mTexSlot, mTextures[curTexture]);
}
traverse(node, nv);
}
ParticleSystemController::ParticleSystemController(const Nif::NiParticleSystemController *ctrl)
@ -507,12 +499,4 @@ void SourcedKeyframeController::operator ()(osg::Node* node, osg::NodeVisitor* n
traverse(node, nv);
}
osg::StateSet *StateSetController::getWritableStateSet(osg::Node *node)
{
osg::StateSet* orig = node->getOrCreateStateSet();
osg::StateSet* cloned = new osg::StateSet(*orig, osg::CopyOp::SHALLOW_COPY);
node->setStateSet(cloned);
return cloned;
}
}

@ -8,6 +8,8 @@
#include <components/nifcache/nifcache.hpp>
#include <components/sceneutil/statesetcontroller.hpp>
#include <boost/shared_ptr.hpp>
#include <set> //UVController
@ -189,19 +191,7 @@ namespace NifOsg
bool mEnabled;
};
class StateSetController
{
protected:
// Clones a StateSet to make it "writable". This is to prevent race conditions when the OSG draw thread of the last frame
// queues up a StateSet that we want to modify. Note, we could also set the StateSet to DYNAMIC data variance but that would
// undo all the benefits of the threading model - having the cull and draw traversals run in parallel can yield up to 200% framerates.
// If the StateSet allocations per frame are proving too much of an overhead we could "reuse" StateSets from previous frames,
// kind of like a double buffering scheme.
osg::StateSet* getWritableStateSet(osg::Node* node);
};
// Note we're using NodeCallback instead of StateSet::Callback because the StateSet callback doesn't support nesting
class UVController : public osg::NodeCallback, public Controller, public StateSetController, public ValueInterpolator
class UVController : public SceneUtil::StateSetController, public Controller, public ValueInterpolator
{
public:
UVController();
@ -210,7 +200,8 @@ namespace NifOsg
META_Object(NifOsg,UVController)
virtual void operator() (osg::Node*, osg::NodeVisitor*);
virtual void setDefaults(osg::StateSet* stateset);
virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv);
private:
Nif::FloatKeyMapPtr mUTrans;
@ -237,7 +228,7 @@ namespace NifOsg
virtual void operator() (osg::Node* node, osg::NodeVisitor* nv);
};
class AlphaController : public osg::NodeCallback, public Controller, public StateSetController, public ValueInterpolator
class AlphaController : public SceneUtil::StateSetController, public Controller, public ValueInterpolator
{
private:
Nif::FloatKeyMapPtr mData;
@ -247,12 +238,12 @@ namespace NifOsg
AlphaController();
AlphaController(const AlphaController& copy, const osg::CopyOp& copyop);
virtual void operator() (osg::Node* node, osg::NodeVisitor* nv);
virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv);
META_Object(NifOsg, AlphaController)
};
class MaterialColorController : public osg::NodeCallback, public Controller, public StateSetController, public ValueInterpolator
class MaterialColorController : public SceneUtil::StateSetController, public Controller, public ValueInterpolator
{
private:
Nif::Vector3KeyMapPtr mData;
@ -264,10 +255,10 @@ namespace NifOsg
META_Object(NifOsg, MaterialColorController)
virtual void operator() (osg::Node* node, osg::NodeVisitor* nv);
virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv);
};
class FlipController : public osg::NodeCallback, public Controller, public StateSetController
class FlipController : public SceneUtil::StateSetController, public Controller
{
private:
int mTexSlot;
@ -281,7 +272,7 @@ namespace NifOsg
META_Object(NifOsg, FlipController)
virtual void operator() (osg::Node* node, osg::NodeVisitor* nv);
virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv);
};
class ParticleSystemController : public osg::NodeCallback, public Controller

@ -719,13 +719,13 @@ namespace NifOsg
return skel;
}
static void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, Resource::TextureManager* textureManager, std::map<int, int>& boundTextures, int animflags)
static void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetController* composite, 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, textureManager, boundTextures, animflags);
handleProperty(props[i].getPtr(), applyTo, composite, textureManager, boundTextures, animflags);
}
}
@ -825,7 +825,9 @@ namespace NifOsg
transformNode->setNodeMask(0x1);
}
applyNodeProperties(nifNode, transformNode, textureManager, boundTextures, animflags);
osg::ref_ptr<SceneUtil::CompositeStateSetController> composite = new SceneUtil::CompositeStateSetController;
applyNodeProperties(nifNode, transformNode, composite, textureManager, boundTextures, animflags);
if (nifNode->recType == Nif::RC_NiTriShape && !skipMeshes)
{
@ -836,9 +838,12 @@ namespace NifOsg
handleSkinnedTriShape(triShape, transformNode, boundTextures, animflags);
if (!nifNode->controller.empty())
handleMeshControllers(nifNode, transformNode, boundTextures, animflags);
handleMeshControllers(nifNode, composite, boundTextures, animflags);
}
if (composite->getNumControllers() > 0)
transformNode->addUpdateCallback(composite);
if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles)
handleParticleSystem(nifNode, transformNode, animflags, particleflags, rootNode);
@ -866,7 +871,7 @@ namespace NifOsg
return transformNode;
}
static void handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map<int, int> &boundTextures, int animflags)
static void handleMeshControllers(const Nif::Node *nifNode, SceneUtil::CompositeStateSetController* composite, const std::map<int, int> &boundTextures, int animflags)
{
for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next)
{
@ -881,8 +886,7 @@ namespace NifOsg
osg::ref_ptr<UVController> ctrl = new UVController(uvctrl->data.getPtr(), texUnits);
setupController(uvctrl, ctrl, animflags);
transformNode->addUpdateCallback(ctrl);
composite->addController(ctrl);
}
}
}
@ -915,8 +919,9 @@ namespace NifOsg
}
}
static void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, osg::StateSet *stateset, int animflags)
static void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, int animflags)
{
osg::ref_ptr<SceneUtil::CompositeStateSetController> composite = new SceneUtil::CompositeStateSetController;
for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next)
{
if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active))
@ -926,21 +931,23 @@ namespace NifOsg
const Nif::NiAlphaController* alphactrl = static_cast<const Nif::NiAlphaController*>(ctrl.getPtr());
osg::ref_ptr<AlphaController> ctrl(new AlphaController(alphactrl->data.getPtr()));
setupController(alphactrl, ctrl, animflags);
node->addUpdateCallback(ctrl);
composite->addController(ctrl);
}
else if (ctrl->recType == Nif::RC_NiMaterialColorController)
{
const Nif::NiMaterialColorController* matctrl = static_cast<const Nif::NiMaterialColorController*>(ctrl.getPtr());
osg::ref_ptr<MaterialColorController> ctrl(new MaterialColorController(matctrl->data.getPtr()));
setupController(matctrl, ctrl, animflags);
node->addUpdateCallback(ctrl);
composite->addController(ctrl);
}
else
std::cerr << "Unexpected material controller " << ctrl->recType << std::endl;
}
if (composite->getNumControllers() > 0)
node->addUpdateCallback(composite);
}
static void handleTextureControllers(const Nif::Property *texProperty, osg::Node* node, Resource::TextureManager* textureManager, osg::StateSet *stateset, int animflags)
static void handleTextureControllers(const Nif::Property *texProperty, SceneUtil::CompositeStateSetController* composite, Resource::TextureManager* textureManager, osg::StateSet *stateset, int animflags)
{
for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next)
{
@ -972,7 +979,7 @@ namespace NifOsg
}
osg::ref_ptr<FlipController> callback(new FlipController(flipctrl, textures));
setupController(ctrl.getPtr(), callback, animflags);
node->addUpdateCallback(callback);
composite->addController(callback);
}
else
std::cerr << "Unexpected texture controller " << ctrl->recName << std::endl;
@ -1419,7 +1426,7 @@ namespace NifOsg
static void handleProperty(const Nif::Property *property,
osg::Node *node, Resource::TextureManager* textureManager, std::map<int, int>& boundTextures, int animflags)
osg::Node *node, SceneUtil::CompositeStateSetController* composite, Resource::TextureManager* textureManager, std::map<int, int>& boundTextures, int animflags)
{
osg::StateSet* stateset = node->getOrCreateStateSet();
@ -1594,7 +1601,7 @@ namespace NifOsg
stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF);
boundTextures.erase(i);
}
handleTextureControllers(texprop, node, textureManager, stateset, animflags);
handleTextureControllers(texprop, composite, textureManager, stateset, animflags);
}
break;
}
@ -1646,7 +1653,7 @@ namespace NifOsg
mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness);
if (!matprop->controller.empty())
handleMaterialControllers(matprop, node, stateset, animflags);
handleMaterialControllers(matprop, node, animflags);
break;
}

@ -28,4 +28,47 @@ namespace SceneUtil
traverse(node, nv);
}
StateSetController::StateSetController()
{
}
StateSetController::StateSetController(const StateSetController &copy, const osg::CopyOp &copyop)
: osg::NodeCallback(copy, copyop)
{
}
// ----------------------------------------------------------------------------------
void CompositeStateSetController::apply(osg::StateSet *stateset, osg::NodeVisitor *nv)
{
for (unsigned int i=0; i<mCtrls.size(); ++i)
mCtrls[i]->apply(stateset, nv);
}
void CompositeStateSetController::setDefaults(osg::StateSet *stateset)
{
for (unsigned int i=0; i<mCtrls.size(); ++i)
mCtrls[i]->setDefaults(stateset);
}
CompositeStateSetController::CompositeStateSetController()
{
}
CompositeStateSetController::CompositeStateSetController(const CompositeStateSetController &copy, const osg::CopyOp &copyop)
: StateSetController(copy, copyop)
, mCtrls(copy.mCtrls)
{
}
unsigned int CompositeStateSetController::getNumControllers()
{
return mCtrls.size();
}
void CompositeStateSetController::addController(StateSetController *ctrl)
{
mCtrls.push_back(ctrl);
}
}

@ -15,16 +15,21 @@ namespace SceneUtil
/// the first StateSet is the one we can write to, the second is the one currently in use by the draw traversal of the last frame.
/// After a frame is completed the places are swapped.
/// @par Must be set as UpdateCallback on a Node.
/// @note Do not add multiple StateSetControllers on the same Node as they will conflict - instead use the CompositeStateSetController.
class StateSetController : public osg::NodeCallback
{
public:
StateSetController();
StateSetController(const StateSetController& copy, const osg::CopyOp& copyop);
META_Object(SceneUtil, StateSetController)
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
protected:
/// Apply state - to override in derived classes
/// @note Due to the double buffering approach you *have* to apply all state
/// even if it has not changed since the last frame.
virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) = 0;
virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) {}
/// Set default state - optionally override in derived classes
/// @par May be used e.g. to allocate StateAttributes.
@ -34,6 +39,28 @@ namespace SceneUtil
osg::ref_ptr<osg::StateSet> mStateSets[2];
};
/// @brief A variant of the StateSetController that can be made up of multiple controllers all controlling the same target.
class CompositeStateSetController : public StateSetController
{
public:
CompositeStateSetController();
CompositeStateSetController(const CompositeStateSetController& copy, const osg::CopyOp& copyop);
META_Object(SceneUtil, CompositeStateSetController)
unsigned int getNumControllers();
void addController(StateSetController* ctrl);
virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv);
protected:
virtual void setDefaults(osg::StateSet *stateset);
std::vector<osg::ref_ptr<StateSetController> > mCtrls;
};
}
#endif

Loading…
Cancel
Save