Skip to content

Instantly share code, notes, and snippets.

@finlaybob
Created August 13, 2012 20:06
Show Gist options
  • Select an option

  • Save finlaybob/3343751 to your computer and use it in GitHub Desktop.

Select an option

Save finlaybob/3343751 to your computer and use it in GitHub Desktop.
#pragma once
#ifndef SHIFTERS_H
#define SHIFTERS_H
/**
* This work is licensed under a Creative Commons,
* Attribution-NonCommercial-ShareAlike 3.0 Unported License.
* http://creativecommons.org/licenses/by-nc-sa/3.0/
*
* You may copy, tweak, and build upon this work non-commercially
* as long as 1. The author is credited and 2. You license the modified
* creations under identical terms.
*
*
* This library allows you to obtain a variety of different movements or
* "tween". I hate that word with the fire of a thousand suns. So I've
* called them Shifters instead.
*
* There are:
* Linear, Quadratic, Cubic, Sinusoidal and Circular. These ease in and
* out.
*
* ElasticOut only eases out for now.
*
* To get one:
* Shifters::Linear<glm::vec3> position;
**/
#ifndef PI
#define PI 3.14159265359
#endif
#include "glm/glm.hpp"
namespace Shifter
{
template <class T>
class Linear{
public:
T current;
T target;
float duration;
T out;
float t;
bool finished;
Linear(T cur,T tgt, float dur): current(cur), target(tgt), duration(dur)
{
t = 0;
finished = false;
}
T getVal(){
if (t<duration && !finished)
{
out = ((target-current)*(t/duration))+(current);
}
else
{
out = target;
finished = true;
}
t++;
return out;
}
void reset(T cur,T tgt, float dur){
current = cur;
target = tgt;
duration = dur;
finished = false;
t=0;
}
};
template <class T>
class Quadratic{
public:
T current;
T target;
float duration;
T out;
float t;
bool finished;
Quadratic(T cur,T tgt, float dur): current(cur), target(tgt), duration(dur)
{
t = 0;
finished = false;
}
T getVal()
{
T c = (target-current);
T b = current;
if(t<duration && !finished){
float _t = t/(duration/2);
if (_t < 1)
{
out = (c*0.5f)*_t*_t + b;
}else{
_t--;
out = (-c*0.5f) * (_t*(_t-2) - 1) + b;
}
t++;
}else{
out = target;
finished = true;
}
return out;
}
void reset(T cur,T tgt, float dur){
current = cur;
target = tgt;
duration = dur;
finished = false;
t=0;
}
};
template <class T>
class Cubic{
public:
T current;
T target;
float duration;
T out;
float t;
bool finished;
Cubic(T cur,T tgt, float dur): current(cur), target(tgt), duration(dur)
{
t = 0;
finished = false;
}
T getVal()
{
T c = (target-current);
T b = current;
if(t<duration && !finished){
float _t = t/(duration/2);
if (_t < 1)
{
out = (c*0.5f)*_t*_t*_t + b;
}else{
_t-=2;
out = (c*0.5f) * (_t*_t*_t + 2) + b;
}
t++;
}else{
out = target;
finished = true;
}
return out;
}
void reset(T cur,T tgt, float dur){
current = cur;
target = tgt;
duration = dur;
finished = false;
t=0;
}
};
template<class T>
class Sinusoidal{
public:
T current;
T target;
float duration;
T out;
float t;
bool finished;
Sinusoidal(T cur,T tgt, float dur): current(cur), target(tgt), duration(dur)
{
t = 0;
finished = false;
}
T getVal(){
T c = (target - current);
T b = current;
if(t<duration && !finished){
out = -c/2.0f * float(cos(PI*(t/duration)) - 1) + b;
t++;
}else{
finished = true;
out = target;
}
return out;
}
void reset(T cur,T tgt, float dur){
current = cur;
target = tgt;
duration = dur;
finished = false;
t=0;
}
};
template <class T>
class Circular{
public:
T current;
T target;
float duration;
T out;
float t;
bool finished;
Circular(T cur,T tgt, float dur): current(cur), target(tgt), duration(dur)
{
t = 0;
finished = false;
}
T getVal()
{
T c = (target-current);
T b = current;
if(t<duration && !finished){
float _t = t/(duration/2);
if (_t < 1)
{
out = -c/2.0f * (sqrt(1 - _t*_t) - 1) + b;
}else{
_t-=2;
out = c/2.0f * (sqrt(1 - _t*_t) + 1) + b;
}
t++;
}else{
out = target;
finished = true;
}
return out;
}
void reset(T cur,T tgt, float dur){
current = cur;
target = tgt;
duration = dur;
finished = false;
t=0;
}
};
template <class T>
/*
* For the love of god, do not try and use a glm::vec3 in here...
*/
class ElasticOut{
public:
T current;
T target;
float duration,amplitude,period;
T out;
float t;
bool finished;
ElasticOut(T cur,T tgt, float dur, float amp = 0.0f):
current(cur), target(tgt), duration(dur), amplitude(amp)
{
assert(typeid(T) != typeid(glm::vec3));
t = 0;
finished = false;
}
T getVal(){
float _t = t;
T c = (target-current);
T b = current;
float s = 0;
float a = amplitude;
float p = duration*0.3f;
if(fabs(a) < c){
a = c;
}
if(t<duration && !finished)
{
if (_t==0){
out = b;
}else{
if ((_t/=duration)==1) {
out = b+c;
}else{
s = T(p/(2.0f*PI) * asin(c/a));
out = T(a*pow(2,-10*_t) * sin( (_t*duration-s)*(2*PI)/p ) + c + b);
}
}
t++;
}else{
finished = true;
out = target;
}
return out;
}
void reset(T cur,T tgt, float dur, float amp = 0.0f)
{
current = cur;
target = tgt;
duration = dur;
amplitude = amp;
finished = false;
t = 0;
}
};
class ElasticOutVec3{
public:
Shifter::ElasticOut<float> *ex;
Shifter::ElasticOut<float> *ey;
Shifter::ElasticOut<float> *ez;
glm::vec3 current;
glm::vec3 target;
float duration;
float amplitude;
bool finished;
ElasticOutVec3(glm::vec3 Vcur,glm::vec3 Vtgt, float dur, float amp = 0.0f):
current(Vcur), target(Vtgt), duration(dur), amplitude(amp)
{
finished = false;
ex = new Shifter::ElasticOut<float>(current.x,target.x,duration,amplitude);
ey = new Shifter::ElasticOut<float>(current.y,target.y,duration,amplitude);
ez = new Shifter::ElasticOut<float>(current.z,target.z,duration,amplitude);
}
glm::vec3 getVal(){
finished = (ex->finished && ey->finished && ez->finished);
return glm::vec3(ex->getVal(),ey->getVal(),ez->getVal());
}
void reset(glm::vec3 Vcur,glm::vec3 Vtgt, float dur, float amp = 0.0f)
{
current = Vcur;
target = Vtgt;
duration = dur;
amplitude = amp;
finished = false;
ex->reset(current.x,target.x,duration,amplitude);
ey->reset(current.y,target.y,duration,amplitude);
ez->reset(current.z,target.z,duration,amplitude);
}
~ElasticOutVec3(){
delete ex;
delete ey;
delete ez;
}
};
};
#endif // SHIFTERS
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment