Skip to content

Commit

Permalink
Model Renderer: Controlling looping of animation sequences
Browse files Browse the repository at this point in the history
Added the "looping" boolean parameter for animation sequences.
Non-looping animations are stopped when they reach their duration.
  • Loading branch information
skyjake committed Aug 3, 2015
1 parent e0bbe5b commit de065c4
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 24 deletions.
4 changes: 4 additions & 0 deletions doomsday/apps/client/include/render/mobjanimator.h
Expand Up @@ -38,8 +38,12 @@ class MobjAnimator : public de::ModelDrawable::Animator

de::ddouble currentTime(int index) const;

struct Parameters;

private:
ModelRenderer::StateAnims const *_stateAnims;

struct Private;
};

#endif // DENG_CLIENT_RENDER_MOBJANIMATOR_H
94 changes: 75 additions & 19 deletions doomsday/apps/client/src/render/mobjanimator.cpp
Expand Up @@ -21,10 +21,41 @@
#include "clientapp.h"
#include "dd_loop.h"

#include <de/ScriptedInfo>

using namespace de;

static String const DEF_PROBABILITY("prob");
static String const DEF_ROOT_NODE ("node");
static String const DEF_LOOPING ("looping");

struct MobjAnimator::Parameters
{
enum LoopMode {
NotLooping = 0,
Looping = 1
};

LoopMode looping;

Parameters(LoopMode loop = NotLooping) : looping(loop) {}
};

Q_DECLARE_METATYPE(MobjAnimator::Parameters)

struct MobjAnimator::Private
{
static bool isRunning(Animation const &anim)
{
Parameters const &params = anim.data.value<Parameters>();
if(params.looping == Parameters::Looping)
{
// Looping animations are always running.
return true;
}
return !anim.isAtEnd();
}
};

MobjAnimator::MobjAnimator(DotPath const &id, ModelDrawable const &model)
: ModelDrawable::Animator(model)
Expand All @@ -43,24 +74,38 @@ void MobjAnimator::triggerByState(String const &stateName)

foreach(ModelRenderer::AnimSequence const &seq, found.value())
{
// Test for the probability of this animation.
float chance = seq.def->getf(DEF_PROBABILITY, 1.f);
if(frand() > chance) continue;

// Start the animation on the specified node (defaults to root),
// unless it is already running.
String const node = seq.def->gets(DEF_ROOT_NODE, "");
int animId = ModelRenderer::identifierFromText(seq.name, [this] (String const &name) {
return model().animationIdForName(name);
});

// Do not restart running sequences.
// TODO: Only restart if the current state is not the expected one.
if(isRunning(animId, node)) continue;

start(animId, node);

//LOG_WIP(" Starting anim: " _E(b)) << seq.name;
try
{
// Test for the probability of this animation.
float chance = seq.def->getf(DEF_PROBABILITY, 1.f);
if(frand() > chance) continue;

// Start the animation on the specified node (defaults to root),
// unless it is already running.
String const node = seq.def->gets(DEF_ROOT_NODE, "");
int animId = ModelRenderer::identifierFromText(seq.name, [this] (String const &name) {
return model().animationIdForName(name);
});

// Do not restart running sequences.
// TODO: Only restart if the current state is not the expected one.
if(isRunning(animId, node)) continue;

// Start a new sequence.
Animation &anim = start(animId, node);

Parameters params(ScriptedInfo::isTrue(*seq.def, DEF_LOOPING)?
Parameters::Looping : Parameters::NotLooping);
anim.data.setValue(params);
}
catch(ModelDrawable::Animator::InvalidError const &er)
{
LOGDEV_GL_WARNING("Failed to start animation \"%s\": %s")
<< seq.name << er.asText();
continue;
}

LOG_WIP("Starting anim: " _E(b)) << seq.name;
break;
}
}
Expand All @@ -72,13 +117,24 @@ void MobjAnimator::advanceTime(TimeDelta const &elapsed)
for(int i = 0; i < count(); ++i)
{
Animation &anim = at(i);
Parameters const &params = anim.data.value<Parameters>();
ddouble factor = 1.0;
// TODO: Determine actual time factor.

// Advance the sequence.
anim.time += factor * elapsed;

//qDebug() << "advancing" << anim.animId << "time" << anim.time;
if(params.looping == Parameters::NotLooping)
{
// Clamp at the end.
anim.time = min(anim.time, anim.duration);
}

// Stop finished animations.
if(!Private::isRunning(anim))
{
stop(i--);
}
}
}

Expand Down
7 changes: 2 additions & 5 deletions doomsday/apps/client/src/render/modelrenderer.cpp
Expand Up @@ -203,15 +203,12 @@ DENG2_PIMPL(ModelRenderer)
{
up = Vector3f(asset.geta(DEF_UP_VECTOR));
}
bool mirror = (asset.has(DEF_MIRROR)? ScriptedInfo::isTrue(asset.get(DEF_MIRROR)) : false);
bool mirror = ScriptedInfo::isTrue(asset, DEF_MIRROR);
aux->cull = mirror? gl::Back : gl::Front;
// Assimp's coordinate system uses different handedness than Doomsday,
// so mirroring is needed.
aux->transformation = Matrix4f::unnormalizedFrame(front, up, !mirror);
if(asset.has(DEF_AUTOSCALE))
{
aux->autoscaleToThingHeight = !ScriptedInfo::isFalse(asset.get(DEF_AUTOSCALE));
}
aux->autoscaleToThingHeight = !ScriptedInfo::isFalse(asset, DEF_AUTOSCALE, false);

// Custom texture maps.
if(asset.has(DEF_MATERIAL))
Expand Down

0 comments on commit de065c4

Please sign in to comment.