From fcb40aa40c6a13ca0e0962b35973ac4574779574 Mon Sep 17 00:00:00 2001 From: Charles McGarvey Date: Mon, 2 Nov 2009 12:02:33 -0700 Subject: [PATCH] starting to move to a generic state structure --- src/Character.cc | 85 +++++++++++++---- src/Character.hh | 6 +- src/Moof/OpenGL.hh | 4 +- src/Moof/RK4.hh | 221 ++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 282 insertions(+), 34 deletions(-) diff --git a/src/Character.cc b/src/Character.cc index accad65..ffecfd5 100644 --- a/src/Character.cc +++ b/src/Character.cc @@ -32,15 +32,58 @@ #include "Log.hh" +struct SpringForce +{ + explicit SpringForce(Mf::Vector2 x) : + location(x) {} + + const Mf::Vector2& operator () (const Mf::LinearState<2>& state) + { + Mf::Vector2 x = state.position - location; + Mf::Scalar mag = x.length(); + Mf::Scalar d = 50.0; + + // spring: + //current.force += -15.0 * x - 1.5 * current.velocity; + force = -20.0 * (mag - d) * (x / mag) - 2.0 * state.velocity; + + return force; + } + +private: + + Mf::Vector2 force; + Mf::Vector2 location; +}; + +struct WindResistenceForce +{ + const Mf::Vector2& operator () (const Mf::LinearState<2>& state) + { + force = -2.0 * state.velocity; + return force; + } + +private: + + Mf::Vector2 force; +}; + + Character::Character(const std::string& name) : tilemap_(name), animation_(name) { + current.init(); + current.mass = 1.0; current.inverseMass = 1.0 / current.mass; // gravity - current.force = Mf::Vector2(0.0, -120.0); + current.force = Mf::Vector2(0.0, 000.0); + current.forces.push_back(SpringForce(Mf::Vector2(500.0, 200.0))); + current.forces.push_back(WindResistenceForce()); + current.forces.push_back(Mf::LinearState<2>::GravityForce(-2000.0)); // starting position current.position = Mf::Vector2(64.0, 64.0); @@ -55,21 +98,25 @@ void Character::update(Mf::Scalar t, Mf::Scalar dt) { previous = current; - Mf::Vector2 x = current.position - Mf::Vector2(500.0, 200.0); - Mf::Scalar mag = x.length(); - Mf::Scalar d = 50.0; - - // gravity: - current.force = Mf::Vector2(0.0, -2000.0); - // spring: - //current.force += -15.0 * x - 1.5 * current.velocity; - current.force += -20.0 * (mag - d) * (x / mag) - 2.0 * current.velocity; - // internal: - current.force += userForce; - current.recalculate(); + //Mf::Vector2 x = current.position - Mf::Vector2(500.0, 200.0); + //Mf::Scalar mag = x.length(); + //Mf::Scalar d = 50.0; + + //// gravity: + //current.force = Mf::Vector2(0.0, -2000.0); + //// spring: + ////current.force += -15.0 * x - 1.5 * current.velocity; + //current.force += -20.0 * (mag - d) * (x / mag) - 2.0 * current.velocity; + //// internal: + //current.force += userForce; + //current.recalculate(); //std::cout << "force: " << current.momentum << std::endl; - Mf::euler(current, t, dt); + //Mf::euler(current, t, dt); + + //current.force = Mf::Vector2(0.0, -2000.0); + current.force = userForce; + current.integrate(t, dt); animation_.update(t, dt); } @@ -77,7 +124,7 @@ void Character::update(Mf::Scalar t, Mf::Scalar dt) void Character::draw(Mf::Scalar alpha) const { - State state = cml::lerp(previous, current, alpha); + Mf::Vector2 position = cml::lerp(previous.position, current.position, alpha); //glColor3f(1.0f, 1.0f, 1.0f); tilemap_.bind(); @@ -95,13 +142,13 @@ void Character::draw(Mf::Scalar alpha) const glBegin(GL_TRIANGLE_FAN); glTexCoord2f(coords[0], coords[1]); - glVertex3(state.position[0]-s, state.position[1]-s, z); + glVertex3(position[0]-s, position[1]-s, z); glTexCoord2f(coords[2], coords[3]); - glVertex3(state.position[0]+s, state.position[1]-s, z); + glVertex3(position[0]+s, position[1]-s, z); glTexCoord2f(coords[4], coords[5]); - glVertex3(state.position[0]+s, state.position[1]+s, z); + glVertex3(position[0]+s, position[1]+s, z); glTexCoord2f(coords[6], coords[7]); - glVertex3(state.position[0]-s, state.position[1]+s, z); + glVertex3(position[0]-s, position[1]+s, z); glEnd(); //glColor3f(0.0f, 0.0f, 0.0f); diff --git a/src/Character.hh b/src/Character.hh index 087bf49..090e7cb 100644 --- a/src/Character.hh +++ b/src/Character.hh @@ -50,6 +50,7 @@ typedef boost::shared_ptr CharacterP; struct Character : public Mf::Entity { + /* struct Derivative { Mf::Vector2 velocity; @@ -134,9 +135,10 @@ struct Character : public Mf::Entity return newState; } }; +*/ - State previous; - State current; + Mf::State2 previous; + Mf::State2 current; private: diff --git a/src/Moof/OpenGL.hh b/src/Moof/OpenGL.hh index c16d701..e74f601 100644 --- a/src/Moof/OpenGL.hh +++ b/src/Moof/OpenGL.hh @@ -40,7 +40,7 @@ typedef GLdouble GLscalar; #define GL_SCALAR GL_DOUBLE -#define SCALAR(D) D +#define SCALAR(D) (D) inline void glGetScalarv(GLenum a, GLscalar* b) { glGetDoublev(a, b); } @@ -96,7 +96,7 @@ inline void glTexCoord4v(const GLscalar* a) typedef GLfloat GLscalar; #define GL_SCALAR GL_FLOAT -#define SCALAR(F) F##f +#define SCALAR(F) (F##f) inline void glGetScalarv(GLenum a, GLscalar* b) { glGetFloatv(a, b); } diff --git a/src/Moof/RK4.hh b/src/Moof/RK4.hh index 806127e..453cf1e 100644 --- a/src/Moof/RK4.hh +++ b/src/Moof/RK4.hh @@ -29,17 +29,23 @@ #ifndef _MOOF_RK4_HH_ #define _MOOF_RK4_HH_ +#include + +#include +#include + #include namespace Mf { + // Generic implementations of a few simple integrators. To use, you need one // type representing the state and another containing the derivatives of the // primary state variables. The state class must implement these methods: // // void getDerivative(Derivative_Type& derivative, Scalar absoluteTime); -// void applyDerivative(const Derivative_Type& derivative, Scalar deltaTime); +// void step(const Derivative_Type& derivative, Scalar deltaTime); // // Additionally, the derivative class must overload a few operators: // @@ -55,11 +61,10 @@ inline D evaluate(const S& state, Scalar t) } template -inline D evaluate(const S& state, Scalar t, Scalar dt, const D& derivative) +inline D evaluate(S state, Scalar t, Scalar dt, const D& derivative) { - S temp = state; - temp.applyDerivative(derivative, dt); - return evaluate(temp, t + dt); + state.step(derivative, dt); + return evaluate(state, t + dt); } @@ -68,30 +73,224 @@ inline void euler(S& state, Scalar t, Scalar dt) { D a = evaluate(state, t); - state.applyDerivative(a, dt); + state.step(a, dt); } template inline void rk2(S& state, Scalar t, Scalar dt) { D a = evaluate(state, t); - D b = evaluate(state, t, dt * 0.5, a); + D b = evaluate(state, t, dt * SCALAR(0.5), a); - state.applyDerivative(b, dt); + state.step(b, dt); } template inline void rk4(S& state, Scalar t, Scalar dt) { D a = evaluate(state, t); - D b = evaluate(state, t, dt * 0.5, a); - D c = evaluate(state, t, dt * 0.5, b); + D b = evaluate(state, t, dt * SCALAR(0.5), a); + D c = evaluate(state, t, dt * SCALAR(0.5), b); D d = evaluate(state, t, dt, c); - state.applyDerivative((a + (b + c) * 2.0 + d) * (1.0/6.0), dt); + state.step((a + (b + c) * SCALAR(2.0) + d) * SCALAR(1.0/6.0), dt); } +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +template +struct LinearState +{ + typedef cml::vector< Scalar, cml::fixed > Vector; + typedef boost::function ForceFunction; + + // primary + + Vector position; + Vector momentum; + + // secondary + + Vector velocity; + + // user + // + Vector force; + std::vector forces; + + // constant + + Scalar mass; + Scalar inverseMass; + + + void recalculateLinear() + { + velocity = momentum * inverseMass; + } + + + struct GravityForce + { + explicit GravityForce(Scalar a = -9.8) + { + force.zero(); + acceleration = a; + } + + const Vector& operator () (const LinearState& state) + { + force[1] = state.mass * acceleration; + return force; + } + + private: + + Vector force; + Scalar acceleration; + }; + + + void init() + { + position.zero(); + momentum.zero(); + + velocity.zero(); + + force.zero(); + forces.clear(); + + mass = SCALAR(1.0); + inverseMass = 1.0 / mass; + } + + + struct Derivative + { + Vector velocity; + Vector force; + + Derivative operator*(Scalar dt) const + { + Derivative derivative; + derivative.velocity = dt * velocity; + derivative.force = dt * force; + return derivative; + } + + Derivative operator+(const Derivative& other) const + { + Derivative derivative; + derivative.velocity = velocity + other.velocity; + derivative.force = force + other.force; + return derivative; + } + }; + + + Vector getForce() const + { + Vector f(force); + + for (size_t i = 0; i < forces.size(); ++i) + { + f += forces[i](*this); + } + + return f; + } + + void getDerivative(Derivative& derivative, Scalar t) const + { + derivative.velocity = velocity; + derivative.force = getForce(); + } + + void step(const Derivative& derivative, Scalar dt) + { + position += dt * derivative.velocity; + momentum += dt * derivative.force; + recalculateLinear(); + } +}; + + +struct RotationalState2 +{ + // primary + + Scalar orientation; + Scalar angularMomentum; + + // secondary + + Scalar angularVelocity; + + // constant + + Scalar inertia; + Scalar inverseInertia; + + + void recalculateRotational() + { + angularVelocity = angularMomentum * inertia; + } + + + struct Derivative + { + Scalar angularVelocity; + Scalar torque; + }; + + void step(const Derivative& derivative, Scalar dt) + { + orientation += dt * derivative.angularVelocity; + angularMomentum += dt * derivative.torque; + recalculateRotational(); + } +}; + +struct RotationalState3 +{ + // primary + + Quaternion orientation; + Vector3 angularMomentum; + + // secondary + + Quaternion spin; + Vector3 angularVelocity; + + // constant + + Scalar inertia; + Scalar inverseInertia; +}; + + +struct State2 : public LinearState<2>, public RotationalState2 +{ + void recalculate() + { + recalculateLinear(); + recalculateRotational(); + } + + void integrate(Scalar t, Scalar dt) + { + rk4,LinearState<2>::Derivative>(*this, t, dt); + } +}; + +struct State3 : public LinearState<3>, public RotationalState3 {}; + + } // namespace Mf #endif // _MOOF_RK4_HH_ -- 2.45.2