Port Animation::addEffect

c++11
scrawl 10 years ago
parent 083c41c950
commit edc5cad79e

@ -14,6 +14,8 @@
#include <components/files/configurationmanager.hpp>
#include <components/sceneutil/controller.hpp>
#include <osgGA/TrackballManipulator>
#include <osg/PositionAttitudeTransform>
@ -129,6 +131,9 @@ int main(int argc, char** argv)
Resource::TextureManager texMgr(&resourceMgr);
newNode->addChild(loader.load(nif, &texMgr));
SceneUtil::AssignControllerSourcesVisitor visitor(boost::shared_ptr<SceneUtil::FrameTimeSource>(new SceneUtil::FrameTimeSource));
newNode->accept(visitor);
osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform;
root->addChild(trans);

@ -20,7 +20,7 @@ set(GAME_HEADER
source_group(game FILES ${GAME} ${GAME_HEADER})
add_openmw_dir (mwrender
actors objects renderingmanager animation sky npcanimation
actors objects renderingmanager animation sky npcanimation vismask
# debugging camera creatureanimation activatoranimation
# renderinginterface localmap occlusionquery water shadows
# characterpreview globalmap ripplesimulation refraction

@ -10,13 +10,18 @@
#include <components/resource/scenemanager.hpp>
#include <components/resource/texturemanager.hpp>
#include <components/misc/resourcehelpers.hpp>
#include <components/sceneutil/statesetupdater.hpp>
#include <components/sceneutil/visitor.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwworld/class.hpp"
#include "vismask.hpp"
namespace
{
@ -62,6 +67,30 @@ namespace
std::vector<osg::ref_ptr<osg::Texture2D> > mTextures;
};
class FindMaxControllerLengthVisitor : public SceneUtil::ControllerVisitor
{
public:
FindMaxControllerLengthVisitor()
: SceneUtil::ControllerVisitor()
, mMaxLength(0)
{
}
virtual void visit(osg::Node& , SceneUtil::Controller& ctrl)
{
if (ctrl.mFunction)
mMaxLength = std::max(mMaxLength, ctrl.mFunction->getMaximum());
}
float getMaxLength() const
{
return mMaxLength;
}
private:
float mMaxLength;
};
}
namespace MWRender
@ -83,6 +112,8 @@ namespace MWRender
osg::Vec3f Animation::runAnimation(float duration)
{
updateEffects(duration);
return osg::Vec3f();
}
@ -147,6 +178,133 @@ namespace MWRender
return result;
}
void Animation::addEffect (const std::string& model, int effectId, bool loop, const std::string& bonename, std::string texture)
{
// Early out if we already have this effect
for (std::vector<EffectParams>::iterator it = mEffects.begin(); it != mEffects.end(); ++it)
if (it->mLoop && loop && it->mEffectId == effectId && it->mBoneName == bonename)
return;
EffectParams params;
params.mModelName = model;
osg::ref_ptr<osg::Group> parentNode;
if (bonename.empty())
parentNode = mObjectRoot->asGroup();
else
{
SceneUtil::FindByNameVisitor visitor(bonename);
mObjectRoot->accept(visitor);
if (!visitor.mFoundNode)
throw std::runtime_error("Can't find bone " + bonename);
parentNode = visitor.mFoundNode;
}
osg::ref_ptr<osg::Node> node = mResourceSystem->getSceneManager()->createInstance(model, parentNode);
params.mObjects = PartHolderPtr(new PartHolder(node));
FindMaxControllerLengthVisitor findMaxLengthVisitor;
node->accept(findMaxLengthVisitor);
params.mMaxControllerLength = findMaxLengthVisitor.getMaxLength();
node->setNodeMask(Mask_Effect);
params.mLoop = loop;
params.mEffectId = effectId;
params.mBoneName = bonename;
params.mAnimTime = boost::shared_ptr<EffectAnimationTime>(new EffectAnimationTime);
SceneUtil::AssignControllerSourcesVisitor assignVisitor(boost::shared_ptr<SceneUtil::ControllerSource>(params.mAnimTime));
node->accept(assignVisitor);
if (!texture.empty())
{
std::string correctedTexture = Misc::ResourceHelpers::correctTexturePath(texture, mResourceSystem->getVFS());
// Not sure if wrap settings should be pulled from the overridden texture?
osg::ref_ptr<osg::Texture2D> tex = mResourceSystem->getTextureManager()->getTexture2D(correctedTexture, osg::Texture2D::CLAMP,
osg::Texture2D::CLAMP);
osg::ref_ptr<osg::StateSet> stateset;
if (node->getStateSet())
stateset = static_cast<osg::StateSet*>(node->getStateSet()->clone(osg::CopyOp::SHALLOW_COPY));
else
stateset = new osg::StateSet;
stateset->setTextureAttribute(0, tex, osg::StateAttribute::OVERRIDE);
node->setStateSet(stateset);
}
// TODO: in vanilla morrowind the effect is scaled based on the host object's bounding box.
mEffects.push_back(params);
}
void Animation::removeEffect(int effectId)
{
for (std::vector<EffectParams>::iterator it = mEffects.begin(); it != mEffects.end(); ++it)
{
if (it->mEffectId == effectId)
{
mEffects.erase(it);
return;
}
}
}
void Animation::getLoopingEffects(std::vector<int> &out)
{
for (std::vector<EffectParams>::iterator it = mEffects.begin(); it != mEffects.end(); ++it)
{
if (it->mLoop)
out.push_back(it->mEffectId);
}
}
void Animation::updateEffects(float duration)
{
for (std::vector<EffectParams>::iterator it = mEffects.begin(); it != mEffects.end(); )
{
it->mAnimTime->addTime(duration);
if (it->mAnimTime->getTime() >= it->mMaxControllerLength)
{
if (it->mLoop)
{
// Start from the beginning again; carry over the remainder
// Not sure if this is actually needed, the controller function might already handle loops
float remainder = it->mAnimTime->getTime() - it->mMaxControllerLength;
it->mAnimTime->resetTime(remainder);
}
else
{
it = mEffects.erase(it);
continue;
}
}
++it;
}
}
float Animation::EffectAnimationTime::getValue(osg::NodeVisitor*)
{
return mTime;
}
void Animation::EffectAnimationTime::addTime(float duration)
{
mTime += duration;
}
void Animation::EffectAnimationTime::resetTime(float time)
{
mTime = time;
}
float Animation::EffectAnimationTime::getTime() const
{
return mTime;
}
// --------------------------------------------------------------------------------
ObjectAnimation::ObjectAnimation(const MWWorld::Ptr &ptr, const std::string &model, Resource::ResourceSystem* resourceSystem)
@ -159,11 +317,6 @@ namespace MWRender
if (!ptr.getClass().getEnchantment(ptr).empty())
addGlow(mObjectRoot, getEnchantmentColor(ptr));
}
else
{
// No model given. Create an object root anyway, so that lights can be added to it if needed.
//mObjectRoot = NifOgre::ObjectScenePtr (new NifOgre::ObjectScene(mInsert->getCreator()));
}
}
}

@ -61,17 +61,18 @@ protected:
virtual void setValue(Ogre::Real value);
};
class EffectAnimationTime : public Ogre::ControllerValue<Ogre::Real>
class EffectAnimationTime : public SceneUtil::ControllerSource
{
private:
float mTime;
public:
EffectAnimationTime() : mTime(0) { }
void addTime(float time) { mTime += time; }
void resetTime(float value) { mTime = value; }
virtual float getValue(osg::NodeVisitor* nv);
virtual Ogre::Real getValue() const;
virtual void setValue(Ogre::Real value);
void addTime(float duration);
void resetTime(float time);
float getTime() const;
EffectAnimationTime() : mTime(0) { }
};
class NullAnimationTime : public SceneUtil::ControllerSource
@ -124,6 +125,44 @@ protected:
Resource::ResourceSystem* mResourceSystem;
/// @brief Detaches the node from its parent when the object goes out of scope.
class PartHolder
{
public:
PartHolder(osg::ref_ptr<osg::Node> node)
: mNode(node)
{
}
~PartHolder()
{
if (mNode->getNumParents())
mNode->getParent(0)->removeChild(mNode);
}
osg::ref_ptr<osg::Node> getNode()
{
return mNode;
}
private:
osg::ref_ptr<osg::Node> mNode;
};
typedef boost::shared_ptr<PartHolder> PartHolderPtr;
struct EffectParams
{
std::string mModelName; // Just here so we don't add the same effect twice
PartHolderPtr mObjects;
boost::shared_ptr<EffectAnimationTime> mAnimTime;
float mMaxControllerLength;
int mEffectId;
bool mLoop;
std::string mBoneName;
};
std::vector<EffectParams> mEffects;
/* Sets the appropriate animations on the bone groups based on priority.
*/
//void resetActiveGroups();
@ -192,12 +231,12 @@ public:
* @param loop Loop the effect. If false, it is removed automatically after it finishes playing. If true,
* you need to remove it manually using removeEffect when the effect should end.
* @param bonename Bone to attach to, or empty string to use the scene node instead
* @param texture override the texture specified in the model's materials
* @param texture override the texture specified in the model's materials - if empty, do not override
* @note Will not add an effect twice.
*/
//void addEffect (const std::string& model, int effectId, bool loop = false, const std::string& bonename = "", std::string texture = "");
//void removeEffect (int effectId);
//void getLoopingEffects (std::vector<int>& out);
void addEffect (const std::string& model, int effectId, bool loop = false, const std::string& bonename = "", std::string texture = "");
void removeEffect (int effectId);
void getLoopingEffects (std::vector<int>& out);
//void updatePtr(const MWWorld::Ptr &ptr);
@ -273,6 +312,9 @@ public:
//float getVelocity(const std::string &groupname) const;
virtual osg::Vec3f runAnimation(float duration);
/// This is typically called as part of runAnimation, but may be called manually if needed.
void updateEffects(float duration);
};
class ObjectAnimation : public Animation {

@ -587,12 +587,15 @@ public:
}
};
PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, int group, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor)
Animation::PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, int group, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor)
{
osg::ref_ptr<osg::Node> instance = mResourceSystem->getSceneManager()->createInstance(model);
osg::ref_ptr<osg::Node> attached = SceneUtil::attach(instance, mObjectRoot, bonefilter, bonename);
if (enchantedGlow)
addGlow(attached, *glowColor);
// TODO: set group userdata for inventory picking
return PartHolderPtr(new PartHolder(attached));
}

@ -50,26 +50,6 @@ public:
};
*/
/// @brief Detaches the node from its parent when the object goes out of scope.
class PartHolder
{
public:
PartHolder(osg::ref_ptr<osg::Node> node)
: mNode(node)
{
}
~PartHolder()
{
if (mNode->getNumParents())
mNode->getParent(0)->removeChild(mNode);
}
private:
osg::ref_ptr<osg::Node> mNode;
};
typedef boost::shared_ptr<PartHolder> PartHolderPtr;
class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener
{
public:

@ -246,7 +246,7 @@ void Objects::removeCell(const MWWorld::CellStore* store)
}
}
void Objects::update(float dt, Ogre::Camera* camera)
void Objects::update(float dt)
{
PtrAnimationMap::const_iterator it = mObjects.begin();
for(;it != mObjects.end();++it)

@ -49,7 +49,7 @@ public:
Animation* getAnimation(const MWWorld::Ptr &ptr);
void update (float dt, Ogre::Camera* camera);
void update (float dt);
///< per-frame update
//Ogre::AxisAlignedBox getDimensions(MWWorld::CellStore*);

@ -160,4 +160,9 @@ namespace MWRender
return mSky.get();
}
void RenderingManager::update(float dt, bool paused)
{
mObjects->update(dt);
}
}

@ -63,6 +63,8 @@ namespace MWRender
osg::Vec3f getEyePos();
void update(float dt, bool paused);
private:
osgViewer::Viewer& mViewer;
osg::ref_ptr<osg::Group> mRootNode;

@ -0,0 +1,17 @@
#ifndef OPENMW_MWRENDER_VISMASK_H
#define OPENMW_MWRENDER_VISMASK_H
namespace MWRender
{
/// Node masks used for controlling visibility of game objects.
enum VisMask
{
Mask_UpdateVisitor = 0x1, // reserved for separating UpdateVisitors from CullVisitors
Mask_Effect = 0x2
};
}
#endif

@ -180,7 +180,7 @@ namespace MWWorld
}
}
//mRendering.update (duration, paused);
mRendering.update (duration, paused);
}
void Scene::unloadCell (CellStoreCollection::iterator iter)

@ -1606,13 +1606,13 @@ namespace MWWorld
goToJail();
updateWeather(duration, paused);
/*
if (!paused)
doPhysics (duration);
//if (!paused)
// doPhysics (duration);
mWorldScene->update (duration, paused);
/*
performUpdateSceneQueries ();
updateWindowManager ();

@ -64,6 +64,11 @@ float ControllerFunction::calculate(float value)
}
}
float ControllerFunction::getMaximum() const
{
return mStopTime;
}
KeyframeController::KeyframeController()
{
}

@ -95,6 +95,8 @@ namespace NifOsg
ControllerFunction(const Nif::Controller *ctrl);
float calculate(float value);
virtual float getMaximum() const;
};
class GeomMorpherController : public osg::Drawable::UpdateCallback, public SceneUtil::Controller, public ValueInterpolator

@ -32,31 +32,26 @@ namespace SceneUtil
return nv->getFrameStamp()->getSimulationTime();
}
AssignControllerSourcesVisitor::AssignControllerSourcesVisitor()
ControllerVisitor::ControllerVisitor()
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
{
}
AssignControllerSourcesVisitor::AssignControllerSourcesVisitor(boost::shared_ptr<ControllerSource> toAssign)
: mToAssign(toAssign)
, osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
{
}
void AssignControllerSourcesVisitor::apply(osg::Node &node)
void ControllerVisitor::apply(osg::Node &node)
{
osg::NodeCallback* callback = node.getUpdateCallback();
while (callback)
{
if (Controller* ctrl = dynamic_cast<Controller*>(callback))
assign(node, *ctrl);
visit(node, *ctrl);
if (CompositeStateSetUpdater* composite = dynamic_cast<CompositeStateSetUpdater*>(callback))
{
for (unsigned int i=0; i<composite->getNumControllers(); ++i)
{
StateSetUpdater* statesetcontroller = composite->getController(i);
if (Controller* ctrl = dynamic_cast<Controller*>(statesetcontroller))
assign(node, *ctrl);
visit(node, *ctrl);
}
}
@ -66,18 +61,29 @@ namespace SceneUtil
traverse(node);
}
void AssignControllerSourcesVisitor::apply(osg::Geode &geode)
void ControllerVisitor::apply(osg::Geode &geode)
{
for (unsigned int i=0; i<geode.getNumDrawables(); ++i)
{
osg::Drawable* drw = geode.getDrawable(i);
osg::Drawable::UpdateCallback* callback = drw->getUpdateCallback();
if (Controller* ctrl = dynamic_cast<Controller*>(callback))
assign(geode, *ctrl);
visit(geode, *ctrl);
}
}
void AssignControllerSourcesVisitor::assign(osg::Node&, Controller &ctrl)
AssignControllerSourcesVisitor::AssignControllerSourcesVisitor()
: ControllerVisitor()
{
}
AssignControllerSourcesVisitor::AssignControllerSourcesVisitor(boost::shared_ptr<ControllerSource> toAssign)
: ControllerVisitor()
, mToAssign(toAssign)
{
}
void AssignControllerSourcesVisitor::visit(osg::Node&, Controller &ctrl)
{
if (!ctrl.mSource.get())
ctrl.mSource = mToAssign;

@ -25,6 +25,10 @@ namespace SceneUtil
{
public:
virtual float calculate(float input) = 0;
/// Get the "stop time" of the controller function, typically the maximum of the calculate() function.
/// May not be meaningful for all types of controller functions.
virtual float getMaximum() const = 0;
};
class Controller
@ -42,18 +46,27 @@ namespace SceneUtil
boost::shared_ptr<ControllerFunction> mFunction;
};
class AssignControllerSourcesVisitor : public osg::NodeVisitor
/// Pure virtual base class - visit() all controllers that are attached as UpdateCallbacks in a scene graph.
class ControllerVisitor : public osg::NodeVisitor
{
public:
AssignControllerSourcesVisitor();
AssignControllerSourcesVisitor(boost::shared_ptr<ControllerSource> toAssign);
ControllerVisitor();
virtual void apply(osg::Node& node);
virtual void apply(osg::Geode& geode);
virtual void visit(osg::Node& node, Controller& ctrl) = 0;
};
class AssignControllerSourcesVisitor : public ControllerVisitor
{
public:
AssignControllerSourcesVisitor();
AssignControllerSourcesVisitor(boost::shared_ptr<ControllerSource> toAssign);
/// Assign the wanted ControllerSource. May be overriden in derived classes.
/// By default assigns the ControllerSource passed to the constructor of this class if no ControllerSource is assigned to that controller yet.
virtual void assign(osg::Node& node, Controller& ctrl);
virtual void visit(osg::Node& node, Controller& ctrl);
private:
boost::shared_ptr<ControllerSource> mToAssign;

Loading…
Cancel
Save