Explorar el Código

Continuing work on the physics API.
Updated the physics sample (renamed, new code, etc.).
Replaced tabs with spaces in multiple files.

Chris Culy hace 14 años
padre
commit
c9f359b075

+ 11 - 11
.gitignore

@@ -25,7 +25,7 @@
 /gameplay-encoder/Debug
 /gameplay-encoder/Debug
 /gameplay-encoder/Release
 /gameplay-encoder/Release
 /gameplay-samples/sample00-mesh/Debug
 /gameplay-samples/sample00-mesh/Debug
-/gameplay-samples/sample00-mesh//Release
+/gameplay-samples/sample00-mesh/Release
 /gameplay-samples/sample00-mesh/Simulator
 /gameplay-samples/sample00-mesh/Simulator
 /gameplay-samples/sample00-mesh/Simulator-Coverage
 /gameplay-samples/sample00-mesh/Simulator-Coverage
 /gameplay-samples/sample00-mesh/Simulator-Profile
 /gameplay-samples/sample00-mesh/Simulator-Profile
@@ -34,7 +34,7 @@
 /gameplay-samples/sample00-mesh/Device-Profile
 /gameplay-samples/sample00-mesh/Device-Profile
 /gameplay-samples/sample00-mesh/Device-Release
 /gameplay-samples/sample00-mesh/Device-Release
 /gameplay-samples/sample01-longboard/Debug
 /gameplay-samples/sample01-longboard/Debug
-/gameplay-samples/sample01-longboard//Release
+/gameplay-samples/sample01-longboard/Release
 /gameplay-samples/sample01-longboard/Simulator
 /gameplay-samples/sample01-longboard/Simulator
 /gameplay-samples/sample01-longboard/Simulator-Coverage
 /gameplay-samples/sample01-longboard/Simulator-Coverage
 /gameplay-samples/sample01-longboard/Simulator-Profile
 /gameplay-samples/sample01-longboard/Simulator-Profile
@@ -60,12 +60,12 @@
 /gameplay-samples/sample03-character/Device-Coverage
 /gameplay-samples/sample03-character/Device-Coverage
 /gameplay-samples/sample03-character/Device-Profile
 /gameplay-samples/sample03-character/Device-Profile
 /gameplay-samples/sample03-character/Device-Release
 /gameplay-samples/sample03-character/Device-Release
-/gameplay-samples/sample04-catapult/Debug
-/gameplay-samples/sample04-catapult/Release
-/gameplay-samples/sample04-catapult/Simulator
-/gameplay-samples/sample04-catapult/Simulator-Coverage
-/gameplay-samples/sample04-catapult/Simulator-Profile
-/gameplay-samples/sample04-catapult/Device-Debug
-/gameplay-samples/sample04-catapult/Device-Coverage
-/gameplay-samples/sample04-catapult/Device-Profile
-/gameplay-samples/sample04-catapult/Device-Release
+/gameplay-samples/sample04-sandbox/Debug
+/gameplay-samples/sample04-sandbox/Release
+/gameplay-samples/sample04-sandbox/Simulator
+/gameplay-samples/sample04-sandbox/Simulator-Coverage
+/gameplay-samples/sample04-sandbox/Simulator-Profile
+/gameplay-samples/sample04-sandbox/Device-Debug
+/gameplay-samples/sample04-sandbox/Device-Coverage
+/gameplay-samples/sample04-sandbox/Device-Profile
+/gameplay-samples/sample04-sandbox/Device-Release

+ 3 - 1
gameplay.sln

@@ -53,7 +53,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample03-character", "gamep
 EndProject
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gameplay-encoder", "gameplay-encoder\gameplay-encoder.vcxproj", "{9D69B743-4872-4DD1-8E30-0087C64298D7}"
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gameplay-encoder", "gameplay-encoder\gameplay-encoder.vcxproj", "{9D69B743-4872-4DD1-8E30-0087C64298D7}"
 EndProject
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample04-catapult", "gameplay-samples\sample04-catapult\sample04-catapult.vcxproj", "{FA260001-5B2E-41B7-86DD-C7F26DF3A485}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D3CA8AE2-3ED6-458B-963A-EDA671E6F51C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample04-sandbox", "gameplay-samples\sample04-sandbox\sample04-sandbox.vcxproj", "{FA260001-5B2E-41B7-86DD-C7F26DF3A485}"
 	ProjectSection(ProjectDependencies) = postProject
 	ProjectSection(ProjectDependencies) = postProject
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A} = {1032BA4B-57EB-4348-9E03-29DD63E80E4A}
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A} = {1032BA4B-57EB-4348-9E03-29DD63E80E4A}
 	EndProjectSection
 	EndProjectSection

+ 3 - 1
gameplay/gameplay.vcxproj

@@ -94,7 +94,9 @@
     <ClInclude Include="src\Frustum.h" />
     <ClInclude Include="src\Frustum.h" />
     <ClInclude Include="src\Game.h" />
     <ClInclude Include="src\Game.h" />
     <ClInclude Include="src\gameplay-main-qnx.h" />
     <ClInclude Include="src\gameplay-main-qnx.h" />
-    <ClInclude Include="src\gameplay-main-win32.h" />
+    <ClInclude Include="src\gameplay-main-win32.h">
+      <FileType>CppHeader</FileType>
+    </ClInclude>
     <ClInclude Include="src\gameplay-main.h" />
     <ClInclude Include="src\gameplay-main.h" />
     <ClInclude Include="src\gameplay.h" />
     <ClInclude Include="src\gameplay.h" />
     <ClInclude Include="src\Input.h" />
     <ClInclude Include="src\Input.h" />

+ 3 - 3
gameplay/src/AudioController.cpp

@@ -23,9 +23,9 @@ AudioController::~AudioController()
 
 
 void AudioController::initialize()
 void AudioController::initialize()
 {    
 {    
-	alutInit(0, 0);
+    alutInit(0, 0);
 
 
-	ALenum errorID = alutGetError();
+    ALenum errorID = alutGetError();
     if ( errorID != ALUT_ERROR_NO_ERROR)
     if ( errorID != ALUT_ERROR_NO_ERROR)
     {
     {
         LOG_ERROR_VARG("AudioController::initialize() error. Unable to initialize alut: %s\n", alutGetErrorString(errorID));
         LOG_ERROR_VARG("AudioController::initialize() error. Unable to initialize alut: %s\n", alutGetErrorString(errorID));
@@ -35,7 +35,7 @@ void AudioController::initialize()
 
 
 void AudioController::finalize()
 void AudioController::finalize()
 {
 {
-	alutExit();
+    alutExit();
 }
 }
 
 
 void AudioController::pause()
 void AudioController::pause()

+ 2 - 2
gameplay/src/Game.cpp

@@ -94,7 +94,7 @@ bool Game::startup()
 
 
     _animationController.initialize();
     _animationController.initialize();
     _audioController.initialize();
     _audioController.initialize();
-	_physicsController.initialize();
+    _physicsController.initialize();
 
 
     // Call user initialization.
     // Call user initialization.
     initialize();
     initialize();
@@ -240,7 +240,7 @@ const AudioController& Game::getAudioController() const
 
 
 PhysicsController* Game::getPhysicsController()
 PhysicsController* Game::getPhysicsController()
 {
 {
-	return &_physicsController;
+    return &_physicsController;
 }
 }
 
 
 void Game::menu()
 void Game::menu()

+ 4 - 4
gameplay/src/Material.cpp

@@ -24,7 +24,7 @@ Material::Material(const Material& m)
 
 
 Material::~Material()
 Material::~Material()
 {
 {
-	// Destroy all the techniques.
+    // Destroy all the techniques.
     for (unsigned int i = 0, count = _techniques.size(); i < count; ++i)
     for (unsigned int i = 0, count = _techniques.size(); i < count; ++i)
     {
     {
         Technique* technique = _techniques[i];
         Technique* technique = _techniques[i];
@@ -59,7 +59,7 @@ Material* Material::create(const char* materialPath)
     // Create new material from the file passed in.
     // Create new material from the file passed in.
     Material* material = new Material();
     Material* material = new Material();
 
 
-	// Go through all the material properties and create techniques under this material.
+    // Go through all the material properties and create techniques under this material.
     Properties* techniqueProperties = NULL;
     Properties* techniqueProperties = NULL;
     while ((techniqueProperties = materialProperties->getNextNamespace()))
     while ((techniqueProperties = materialProperties->getNextNamespace()))
     {
     {
@@ -195,7 +195,7 @@ bool Material::loadTechnique(Material* material, Properties* techniqueProperties
     // Create a new technique
     // Create a new technique
     Technique* technique = new Technique(techniqueProperties->getId(), material);
     Technique* technique = new Technique(techniqueProperties->getId(), material);
 
 
-	// Go through all the properties and create passes under this technique.
+    // Go through all the properties and create passes under this technique.
     techniqueProperties->rewind();
     techniqueProperties->rewind();
     Properties* passProperties = NULL;
     Properties* passProperties = NULL;
     while ((passProperties = techniqueProperties->getNextNamespace()))
     while ((passProperties = techniqueProperties->getNextNamespace()))
@@ -203,7 +203,7 @@ bool Material::loadTechnique(Material* material, Properties* techniqueProperties
         if (strcmp(passProperties->getNamespace(), "pass") == 0)
         if (strcmp(passProperties->getNamespace(), "pass") == 0)
         {
         {
             // Create and load passes.
             // Create and load passes.
-		    if (!loadPass(technique, passProperties))
+            if (!loadPass(technique, passProperties))
             {
             {
                 SAFE_RELEASE(technique);
                 SAFE_RELEASE(technique);
                 return false;
                 return false;

+ 0 - 7
gameplay/src/Model.cpp

@@ -200,14 +200,7 @@ void Model::setNode(Node* node)
 {
 {
     if (_node != node)
     if (_node != node)
     {
     {
-        SAFE_RELEASE(_node);
-
         _node = node;
         _node = node;
-
-        if (_node)
-        {
-            node->addRef();
-        }
     }
     }
 
 
     // Re-bind node related material parameters
     // Re-bind node related material parameters

+ 3 - 5
gameplay/src/Node.cpp

@@ -51,6 +51,7 @@ Node::~Node()
     SAFE_RELEASE(_model);
     SAFE_RELEASE(_model);
     SAFE_RELEASE(_audioSource);
     SAFE_RELEASE(_audioSource);
     SAFE_RELEASE(_particleEmitter);
     SAFE_RELEASE(_particleEmitter);
+    SAFE_RELEASE(_physicsRigidBody);
 }
 }
 
 
 Node* Node::create(const char* id)
 Node* Node::create(const char* id)
@@ -796,12 +797,9 @@ PhysicsRigidBody* Node::getPhysicsRigidBody()
 void Node::setPhysicsRigidBody(PhysicsRigidBody::Type type, float mass, float friction,
 void Node::setPhysicsRigidBody(PhysicsRigidBody::Type type, float mass, float friction,
         float restitution, float linearDamping, float angularDamping)
         float restitution, float linearDamping, float angularDamping)
 {
 {
-    if (_physicsRigidBody)
-    {
-        SAFE_RELEASE(_physicsRigidBody);
-    }
+    SAFE_RELEASE(_physicsRigidBody);
     
     
-    if (type != PhysicsRigidBody::PHYSICS_SHAPE_NONE)
+    if (type != PhysicsRigidBody::SHAPE_NONE)
         _physicsRigidBody = new PhysicsRigidBody(this, type, mass, friction, restitution, linearDamping, angularDamping);
         _physicsRigidBody = new PhysicsRigidBody(this, type, mass, friction, restitution, linearDamping, angularDamping);
 }
 }
 
 

+ 130 - 6
gameplay/src/PhysicsConstraint.cpp

@@ -4,28 +4,40 @@
 
 
 #include "PhysicsConstraint.h"
 #include "PhysicsConstraint.h"
 
 
+#include "Game.h"
 #include "Node.h"
 #include "Node.h"
+#include "PhysicsMotionState.h"
+#include "PhysicsRigidBody.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
 
 
-PhysicsConstraint::PhysicsConstraint() : _constraint(NULL)
+PhysicsConstraint::PhysicsConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b)
+    : _a(a), _b(b), _constraint(NULL)
 {
 {
 }
 }
 
 
 PhysicsConstraint::~PhysicsConstraint()
 PhysicsConstraint::~PhysicsConstraint()
 {
 {
-    if (_constraint)
-    {
-        SAFE_DELETE(_constraint);
-    }
+    // Remove the physics rigid bodies' references to this constraint.
+    if (_a)
+        _a->removeConstraint(this);
+    if (_b)
+        _b->removeConstraint(this);
+
+    // Remove the constraint from the physics world and delete the Bullet object.
+    Game::getInstance()->getPhysicsController()->removeConstraint(this);
+    SAFE_DELETE(_constraint);
 }
 }
 
 
-Vector3 PhysicsConstraint::midpoint(Node* a, Node* b)
+Vector3 PhysicsConstraint::centerOfMassMidpoint(Node* a, Node* b)
 {
 {
     Vector3 tA, tB;
     Vector3 tA, tB;
     a->getWorldMatrix().getTranslation(&tA);
     a->getWorldMatrix().getTranslation(&tA);
     b->getWorldMatrix().getTranslation(&tB);
     b->getWorldMatrix().getTranslation(&tB);
+
+    tA = getWorldCenterOfMass(a->getModel());
+    tB = getWorldCenterOfMass(b->getModel());
     
     
     Vector3 d(tA, tB);
     Vector3 d(tA, tB);
     d.scale(0.5f);
     d.scale(0.5f);
@@ -35,4 +47,116 @@ Vector3 PhysicsConstraint::midpoint(Node* a, Node* b)
     return c;
     return c;
 }
 }
 
 
+Quaternion PhysicsConstraint::getRotationOffset(Node* node, const Vector3& point)
+{
+    // Create a translation matrix that translates to the given origin.
+    Matrix m;
+    Matrix::createTranslation(point, &m);
+
+    // Calculate the rotation offset to the rigid body by transforming 
+    // the translation matrix above into the rigid body's local space 
+    // (multiply by the inverse world matrix) and extracting the rotation.
+    Matrix mi;
+    node->getWorldMatrix().invert(&mi);
+    mi.multiply(m);
+    
+    Quaternion r;
+    mi.getRotation(&r);
+
+    return r;
+}
+
+Vector3 PhysicsConstraint::getTranslationOffset(Node* node, const Vector3& point)
+{
+    // Create a translation matrix that translates to the given origin.
+    Matrix m;
+    Matrix::createTranslation(point, &m);
+
+    // Calculate the translation offset to the rigid body by transforming 
+    // the translation matrix above into the rigid body's local space 
+    // (multiply by the inverse world matrix) and extracting the translation.
+    Matrix mi;
+    node->getWorldMatrix().invert(&mi);
+    mi.multiply(m);
+    
+    Vector3 t;
+    mi.getTranslation(&t);
+
+    Vector3 s;
+    node->getWorldMatrix().getScale(&s);
+
+    t.x *= s.x;
+    t.y *= s.y;
+    t.z *= s.z;
+    
+    t = offsetByCenterOfMass(node, t);
+
+    return t;
+}
+
+btTransform PhysicsConstraint::getTransformOffset(Node* node, const Vector3& origin)
+{
+    // Create a translation matrix that translates to the given origin.
+    Matrix m;
+    Matrix::createTranslation(origin, &m);
+
+    // Calculate the translation and rotation offset to the rigid body
+    // by transforming the translation matrix above into the rigid body's
+    // local space (multiply by the inverse world matrix and extract components).
+    Matrix mi;
+    node->getWorldMatrix().invert(&mi);
+    mi.multiply(m);
+
+    Quaternion r;
+    mi.getRotation(&r);
+    
+    Vector3 t;
+    mi.getTranslation(&t);
+
+    Vector3 s;
+    node->getWorldMatrix().getScale(&s);
+
+    t.x *= s.x;
+    t.y *= s.y;
+    t.z *= s.z;
+    
+    t = offsetByCenterOfMass(node, t);
+
+    return btTransform(btQuaternion(r.x, r.y, r.z, r.w), btVector3(t.x, t.y, t.z));
+}
+
+// TODO!!!
+Vector3 PhysicsConstraint::getWorldCenterOfMass(Model* model)
+{
+    Vector3 center;
+
+    const BoundingBox& box = model->getMesh()->getBoundingBox();
+    if (!(box.min.isZero() && box.max.isZero()))
+    {
+        Vector3 bMin, bMax;
+        model->getNode()->getWorldMatrix().transformPoint(box.min, &bMin);
+        model->getNode()->getWorldMatrix().transformPoint(box.max, &bMax);
+        center.set(bMin, bMax);
+        center.scale(0.5f);
+        center.add(bMin);
+    }
+    else
+    {
+        const BoundingSphere& sphere = model->getMesh()->getBoundingSphere();
+        if (!(sphere.center.isZero() && sphere.radius == 0))
+        {
+            model->getNode()->getWorldMatrix().transformPoint(sphere.center, &center);
+        }
+    }
+
+    // TODO: This case needs to be fixed (maybe return an error somehow?).
+    return center;
+}
+
+Vector3 PhysicsConstraint::offsetByCenterOfMass(Node* node, const Vector3& v)
+{
+    btVector3 centerOfMassOffset = ((PhysicsMotionState*)node->getPhysicsRigidBody()->_body->getMotionState())->_centerOfMassOffset.getOrigin();
+    return Vector3(v.x + centerOfMassOffset.x(), v.y + centerOfMassOffset.y(), v.z + centerOfMassOffset.z());
+}
+
 }
 }

+ 44 - 5
gameplay/src/PhysicsConstraint.h

@@ -6,19 +6,21 @@
 #define PHYSICSCONSTRAINT_H_
 #define PHYSICSCONSTRAINT_H_
 
 
 #include "Base.h"
 #include "Base.h"
-#include "Ref.h"
+#include "Model.h"
 #include "Vector3.h"
 #include "Vector3.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
     class Node;
     class Node;
+    class PhysicsRigidBody;
 
 
 /**
 /**
  * Base class for physics constraints.
  * Base class for physics constraints.
  */
  */
-class PhysicsConstraint : public Ref
+class PhysicsConstraint
 {
 {
     friend class PhysicsController;
     friend class PhysicsController;
+    friend class PhysicsRigidBody;
 
 
 public:
 public:
     /**
     /**
@@ -52,11 +54,35 @@ public:
      */
      */
     inline void setEnabled(bool enabled);
     inline void setEnabled(bool enabled);
 
 
+    /**
+     * Calculates the midpoint between the given nodes' centers of mass.
+     * 
+     * @param a The first node.
+     * @param b The second node.
+     */
+    static Vector3 centerOfMassMidpoint(Node* a, Node* b);
+
+    /**
+     * Calculates the rotation offset to the given point in the given node's local space.
+     * 
+     * @param node The node to calculate a rotation offset for.
+     * @param point The point to calculate the rotation offset to.
+     */
+    static Quaternion getRotationOffset(Node* node, const Vector3& point);
+
+    /**
+     * Calculates the translation offset to the given point in the given node's local space.
+     * 
+     * @param node The node to calculate a translation offset for.
+     * @param point The point to calculate the translation offset to.
+     */
+    static Vector3 getTranslationOffset(Node* node, const Vector3& point);
+
 protected:
 protected:
     /**
     /**
      * Constructor.
      * Constructor.
      */
      */
-    PhysicsConstraint();
+    PhysicsConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b);
 
 
     /**
     /**
      * Destructor.
      * Destructor.
@@ -64,10 +90,23 @@ protected:
     virtual ~PhysicsConstraint();
     virtual ~PhysicsConstraint();
 
 
     /**
     /**
-     * Calculates the midpoint between the two nodes.
+     * Calculates the transform to be used as the offset (i.e. "frame in" 
+     * parameter in Bullet terms) to the given constraint origin.
+     */
+    static btTransform getTransformOffset(Node* node, const Vector3& origin);
+    
+    /**
+     * Calculates the center of mass in world space of the given model.
+     */
+    static Vector3 getWorldCenterOfMass(Model* model);
+
+    /**
+     * Offsets the given vector by the given node's center of mass.
      */
      */
-    static Vector3 midpoint(Node* a, Node* b);
+    static Vector3 offsetByCenterOfMass(Node* node, const Vector3& v);
 
 
+    PhysicsRigidBody* _a;
+    PhysicsRigidBody* _b;
     btTypedConstraint* _constraint;
     btTypedConstraint* _constraint;
 };
 };
 
 

+ 65 - 57
gameplay/src/PhysicsController.cpp

@@ -11,8 +11,8 @@ namespace gameplay
 
 
 // Default gravity is 9.8 along the negative Y axis.
 // Default gravity is 9.8 along the negative Y axis.
 PhysicsController::PhysicsController()
 PhysicsController::PhysicsController()
-	: _gravity(btScalar(0.0), btScalar(-9.8), btScalar(0.0)), _collisionConfiguration(NULL), _dispatcher(NULL),
-	_overlappingPairCache(NULL), _solver(NULL), _world(NULL)
+    : _gravity(btScalar(0.0), btScalar(-9.8), btScalar(0.0)), _collisionConfiguration(NULL), _dispatcher(NULL),
+    _overlappingPairCache(NULL), _solver(NULL), _world(NULL)
 {
 {
 }
 }
 
 
@@ -22,14 +22,14 @@ PhysicsController::~PhysicsController()
 
 
 void PhysicsController::setGravity(const Vector3& gravity)
 void PhysicsController::setGravity(const Vector3& gravity)
 {
 {
-	_gravity.setX(gravity.x);
-	_gravity.setY(gravity.y);
-	_gravity.setZ(gravity.z);
+    _gravity.setX(gravity.x);
+    _gravity.setY(gravity.y);
+    _gravity.setZ(gravity.z);
 
 
-	if (_world)
-	{
-		_world->setGravity(_gravity);
-	}
+    if (_world)
+    {
+        _world->setGravity(_gravity);
+    }
 }
 }
 
 
 PhysicsFixedConstraint* PhysicsController::createFixedConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b)
 PhysicsFixedConstraint* PhysicsController::createFixedConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b)
@@ -101,87 +101,89 @@ PhysicsSpringConstraint* PhysicsController::createSpringConstraint(PhysicsRigidB
 
 
 void PhysicsController::initialize()
 void PhysicsController::initialize()
 {
 {
-	// TODO: Should any of this be configurable?
-	_collisionConfiguration = new btDefaultCollisionConfiguration();
-	_dispatcher = new btCollisionDispatcher(_collisionConfiguration);
-	_overlappingPairCache = new btDbvtBroadphase();
-	_solver = new btSequentialImpulseConstraintSolver();
+    // TODO: Should any of this be configurable?
+    _collisionConfiguration = new btDefaultCollisionConfiguration();
+    _dispatcher = new btCollisionDispatcher(_collisionConfiguration);
+    _overlappingPairCache = new btDbvtBroadphase();
+    _solver = new btSequentialImpulseConstraintSolver();
 
 
-	// Create the world.
-	_world = new btDiscreteDynamicsWorld(_dispatcher, _overlappingPairCache, _solver, _collisionConfiguration);
-	_world->setGravity(_gravity);
+    // Create the world.
+    _world = new btDiscreteDynamicsWorld(_dispatcher, _overlappingPairCache, _solver, _collisionConfiguration);
+    _world->setGravity(_gravity);
 }
 }
 
 
 void PhysicsController::finalize()
 void PhysicsController::finalize()
 {
 {
-	// Clean up the world and its various components.
-	SAFE_DELETE(_world);
-	SAFE_DELETE(_solver);
-	SAFE_DELETE(_overlappingPairCache);
-	SAFE_DELETE(_dispatcher);
-	SAFE_DELETE(_collisionConfiguration);
+    // Clean up the world and its various components.
+    SAFE_DELETE(_world);
+    SAFE_DELETE(_solver);
+    SAFE_DELETE(_overlappingPairCache);
+    SAFE_DELETE(_dispatcher);
+    SAFE_DELETE(_collisionConfiguration);
 }
 }
 
 
 void PhysicsController::pause()
 void PhysicsController::pause()
 {
 {
-	// DUMMY FUNCTION
+    // DUMMY FUNCTION
 }
 }
 
 
 void PhysicsController::resume()
 void PhysicsController::resume()
 {
 {
-	// DUMMY FUNCTION
+    // DUMMY FUNCTION
 }
 }
 
 
 void PhysicsController::update(long elapsedTime)
 void PhysicsController::update(long elapsedTime)
 {
 {
-	// Update the physics simulation, with a maximum
-	// of 10 simulation steps being performed in a given frame.
-	//
-	// Note that stepSimulation takes elapsed time in seconds
-	// so we divide by 1000 to convert from milliseconds.
-	_world->stepSimulation((float)elapsedTime * 0.001, 10);
+    // Update the physics simulation, with a maximum
+    // of 10 simulation steps being performed in a given frame.
+    //
+    // Note that stepSimulation takes elapsed time in seconds
+    // so we divide by 1000 to convert from milliseconds.
+    _world->stepSimulation((float)elapsedTime * 0.001, 10);
 }
 }
 
 
 btCollisionShape* PhysicsController::getBox(const Vector3& min, const Vector3& max, const btVector3& scale)
 btCollisionShape* PhysicsController::getBox(const Vector3& min, const Vector3& max, const btVector3& scale)
 {
 {
-	btVector3 halfExtents(scale.x() * 0.5 * abs(max.x - min.x), scale.y() * 0.5 * abs(max.y - min.y), scale.z() * 0.5 * abs(max.z - min.z));
-	btBoxShape* box = new btBoxShape(halfExtents);
-	_shapes.push_back(box);
+    btVector3 halfExtents(scale.x() * 0.5 * abs(max.x - min.x), scale.y() * 0.5 * abs(max.y - min.y), scale.z() * 0.5 * abs(max.z - min.z));
+    btBoxShape* box = new btBoxShape(halfExtents);
+    _shapes.push_back(box);
 
 
-	return box;
+    return box;
 }
 }
 
 
 btCollisionShape* PhysicsController::getSphere(float radius, const btVector3& scale)
 btCollisionShape* PhysicsController::getSphere(float radius, const btVector3& scale)
 {
 {
-	// Since sphere shapes depend only on the radius, the best we can do is take
-	// the largest dimension and apply that as the uniform scale to the rigid body.
-	float uniformScale = scale.x();
-	if (uniformScale < scale.y())
-		uniformScale = scale.y();
-	if (uniformScale < scale.z())
-		uniformScale = scale.z();
+    // Since sphere shapes depend only on the radius, the best we can do is take
+    // the largest dimension and apply that as the uniform scale to the rigid body.
+    float uniformScale = scale.x();
+    if (uniformScale < scale.y())
+        uniformScale = scale.y();
+    if (uniformScale < scale.z())
+        uniformScale = scale.z();
 
 
-	btSphereShape* sphere = new btSphereShape(uniformScale * radius);
-	_shapes.push_back(sphere);
+    btSphereShape* sphere = new btSphereShape(uniformScale * radius);
+    _shapes.push_back(sphere);
 
 
-	return sphere;
+    return sphere;
 }
 }
 
 
 btCollisionShape* PhysicsController::getTriangleMesh(float* vertexData, int vertexPositionStride, unsigned char* indexData, Mesh::IndexFormat indexFormat)
 btCollisionShape* PhysicsController::getTriangleMesh(float* vertexData, int vertexPositionStride, unsigned char* indexData, Mesh::IndexFormat indexFormat)
 {
 {
-	return NULL;
+    return NULL;
 }
 }
 
 
 btCollisionShape* PhysicsController::getHeightfield(void* data, int width, int height)
 btCollisionShape* PhysicsController::getHeightfield(void* data, int width, int height)
 {
 {
-	return NULL;
+    return NULL;
 }
 }
 
 
 void PhysicsController::setupConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b, PhysicsConstraint* constraint)
 void PhysicsController::setupConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b, PhysicsConstraint* constraint)
 {
 {
     a->addConstraint(constraint);
     a->addConstraint(constraint);
     if (b)
     if (b)
+    {
         b->addConstraint(constraint);
         b->addConstraint(constraint);
+    }
 
 
     _world->addConstraint(constraint->_constraint);
     _world->addConstraint(constraint->_constraint);
 }
 }
@@ -189,23 +191,29 @@ void PhysicsController::setupConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b
 void PhysicsController::removeConstraint(PhysicsConstraint* constraint)
 void PhysicsController::removeConstraint(PhysicsConstraint* constraint)
 {
 {
     // Find the constraint and remove it from the physics world.
     // Find the constraint and remove it from the physics world.
-	for (int i = _world->getNumConstraints() - 1; i >= 0; i--)
-	{
-		btTypedConstraint* currentConstraint = _world->getConstraint(i);
+    for (int i = _world->getNumConstraints() - 1; i >= 0; i--)
+    {
+        btTypedConstraint* currentConstraint = _world->getConstraint(i);
         if (constraint->_constraint == currentConstraint)
         if (constraint->_constraint == currentConstraint)
-		    _world->removeConstraint(currentConstraint);
-	}
+        {
+            _world->removeConstraint(currentConstraint);
+            break;
+        }
+    }
 }
 }
 
 
 void PhysicsController::removeRigidBody(PhysicsRigidBody* rigidBody)
 void PhysicsController::removeRigidBody(PhysicsRigidBody* rigidBody)
 {
 {
     // Find the rigid body and remove it from the world.
     // Find the rigid body and remove it from the world.
-	for (int i = _world->getNumCollisionObjects() - 1; i >= 0 ; i--)
-	{
-		btCollisionObject* obj = _world->getCollisionObjectArray()[i];
+    for (int i = _world->getNumCollisionObjects() - 1; i >= 0 ; i--)
+    {
+        btCollisionObject* obj = _world->getCollisionObjectArray()[i];
         if (rigidBody->_body == obj)
         if (rigidBody->_body == obj)
-		    _world->removeCollisionObject(obj);
-	}
+        {
+            _world->removeCollisionObject(obj);
+            break;
+        }
+    }
 }
 }
 
 
 }
 }

+ 44 - 43
gameplay/src/PhysicsController.h

@@ -15,22 +15,23 @@
 
 
 namespace gameplay
 namespace gameplay
 {
 {
-	
+    
 /**
 /**
  * Defines a class for controlling game physics.
  * Defines a class for controlling game physics.
  */
  */
 class PhysicsController
 class PhysicsController
 {
 {
-	friend class Game;
-	friend class PhysicsRigidBody;
+    friend class Game;
+    friend class PhysicsConstraint;
+    friend class PhysicsRigidBody;
 
 
 public:
 public:
-	/**
-	 * Sets the gravity vector for the simulated physics world.
-	 * 
-	 * @param gravity The gravity vector.
-	 */
-	void setGravity(const Vector3& gravity);
+    /**
+     * Sets the gravity vector for the simulated physics world.
+     * 
+     * @param gravity The gravity vector.
+     */
+    void setGravity(const Vector3& gravity);
 
 
     /**
     /**
      * Creates a fixed constraint.
      * Creates a fixed constraint.
@@ -144,52 +145,52 @@ public:
         const Vector3& translationOffsetA, PhysicsRigidBody* b, const Quaternion& rotationOffsetB, const Vector3& translationOffsetB);
         const Vector3& translationOffsetA, PhysicsRigidBody* b, const Quaternion& rotationOffsetB, const Vector3& translationOffsetB);
 
 
 private:
 private:
-	/**
-	 * Constructor.
-	 */
-	PhysicsController();
+    /**
+     * Constructor.
+     */
+    PhysicsController();
 
 
     /**
     /**
-	 * Destructor.
-	 */
-	~PhysicsController();
+     * Destructor.
+     */
+    ~PhysicsController();
 
 
-	/**
-	 * Controller initialize.
-	 */
-	void initialize();
+    /**
+     * Controller initialize.
+     */
+    void initialize();
 
 
-	/**
-	 * Controller finalize.
-	 */
+    /**
+     * Controller finalize.
+     */
     void finalize();
     void finalize();
 
 
-	/**
-	 * Controller pause.
-	 */
+    /**
+     * Controller pause.
+     */
     void pause();
     void pause();
 
 
-	/**
-	 * Controller resume.
-	 */
+    /**
+     * Controller resume.
+     */
     void resume();
     void resume();
 
 
-	/**
-	 * Controller update.
-	 */
+    /**
+     * Controller update.
+     */
     void update(long elapsedTime);
     void update(long elapsedTime);
 
 
     // Creates a box collision shape to be used in the creation of a rigid body.
     // Creates a box collision shape to be used in the creation of a rigid body.
-	btCollisionShape* getBox(const Vector3& min, const Vector3& max, const btVector3& scale);
+    btCollisionShape* getBox(const Vector3& min, const Vector3& max, const btVector3& scale);
 
 
     // Creates a sphere collision shape to be used in the creation of a rigid body.
     // Creates a sphere collision shape to be used in the creation of a rigid body.
-	btCollisionShape* getSphere(float radius, const btVector3& scale);
+    btCollisionShape* getSphere(float radius, const btVector3& scale);
 
 
     // Creates a triangle mesh collision shape to be used in the creation of a rigid body.
     // Creates a triangle mesh collision shape to be used in the creation of a rigid body.
-	btCollisionShape* getTriangleMesh(float* vertexData, int vertexPositionStride, unsigned char* indexData, Mesh::IndexFormat indexFormat);
+    btCollisionShape* getTriangleMesh(float* vertexData, int vertexPositionStride, unsigned char* indexData, Mesh::IndexFormat indexFormat);
 
 
     // Creates a heightfield collision shape to be used in the creation of a rigid body.
     // Creates a heightfield collision shape to be used in the creation of a rigid body.
-	btCollisionShape* getHeightfield(void* data, int width, int height);
+    btCollisionShape* getHeightfield(void* data, int width, int height);
     
     
     // Sets up the given constraint for the given two rigid bodies.
     // Sets up the given constraint for the given two rigid bodies.
     void setupConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b, PhysicsConstraint* constraint);
     void setupConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b, PhysicsConstraint* constraint);
@@ -200,13 +201,13 @@ private:
     // Removes the given rigid body from the simulated physics world.
     // Removes the given rigid body from the simulated physics world.
     void removeRigidBody(PhysicsRigidBody* rigidBody);
     void removeRigidBody(PhysicsRigidBody* rigidBody);
 
 
-	btVector3 _gravity;
-	btDefaultCollisionConfiguration* _collisionConfiguration;
-	btCollisionDispatcher* _dispatcher;
-	btBroadphaseInterface* _overlappingPairCache;
-	btSequentialImpulseConstraintSolver* _solver;
-	btDynamicsWorld* _world;
-	btAlignedObjectArray<btCollisionShape*> _shapes;
+    btVector3 _gravity;
+    btDefaultCollisionConfiguration* _collisionConfiguration;
+    btCollisionDispatcher* _dispatcher;
+    btBroadphaseInterface* _overlappingPairCache;
+    btSequentialImpulseConstraintSolver* _solver;
+    btDynamicsWorld* _world;
+    btAlignedObjectArray<btCollisionShape*> _shapes;
 };
 };
 
 
 }
 }

+ 19 - 33
gameplay/src/PhysicsGenericConstraint.cpp

@@ -5,47 +5,25 @@
 #include "PhysicsGenericConstraint.h"
 #include "PhysicsGenericConstraint.h"
 
 
 #include "Node.h"
 #include "Node.h"
+#include "PhysicsMotionState.h"
 #include "PhysicsRigidBody.h"
 #include "PhysicsRigidBody.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
 
 
 PhysicsGenericConstraint::PhysicsGenericConstraint()
 PhysicsGenericConstraint::PhysicsGenericConstraint()
+    : PhysicsConstraint(NULL, NULL)
 {
 {
     // DUMMY FUNCTION
     // DUMMY FUNCTION
 }
 }
 
 
 PhysicsGenericConstraint::PhysicsGenericConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b)
 PhysicsGenericConstraint::PhysicsGenericConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b)
+    : PhysicsConstraint(a, b)
 {
 {
     if (b)
     if (b)
     {
     {
-        // Create a translation matrix that translates to the midpoint
-        // between the two physics rigid bodies.
-        Matrix m;
-        Matrix::createTranslation(midpoint(a->_node, b->_node), &m);
-
-        // Calculate the translation and rotation offsets to the rigid bodies
-        // by transforming the translation matrix above into each rigid body's
-        // local space (multiply by the inverse world matrix and extract components).
-        Matrix mAi;
-        a->_node->getWorldMatrix().invert(&mAi);
-        mAi.multiply(m);
-
-        Matrix mBi;
-        b->_node->getWorldMatrix().invert(&mBi);
-        mBi.multiply(m);
-
-        Quaternion rA, rB;
-        mAi.getRotation(&rA);
-        mBi.getRotation(&rB);
-    
-        Vector3 tA, tB;
-        mAi.getTranslation(&tA);
-        mBi.getTranslation(&tB);
-
-        btTransform frameInA(btQuaternion(rA.x, rA.y, rA.z, rA.w), btVector3(tA.x, tA.y, tA.z));
-        btTransform frameInB(btQuaternion(rB.x, rB.y, rB.z, rB.w), btVector3(tB.x, tB.y, tB.z));
-        _constraint = new btGeneric6DofConstraint(*a->_body, *b->_body, frameInA, frameInB, true);
+        Vector3 origin = centerOfMassMidpoint(a->_node, b->_node);
+        _constraint = new btGeneric6DofConstraint(*a->_body, *b->_body, getTransformOffset(a->_node, origin), getTransformOffset(b->_node, origin), true);
     }
     }
     else
     else
     {
     {
@@ -55,19 +33,27 @@ PhysicsGenericConstraint::PhysicsGenericConstraint(PhysicsRigidBody* a, PhysicsR
 
 
 PhysicsGenericConstraint::PhysicsGenericConstraint(PhysicsRigidBody* a, const Quaternion& rotationOffsetA, const Vector3& translationOffsetA,
 PhysicsGenericConstraint::PhysicsGenericConstraint(PhysicsRigidBody* a, const Quaternion& rotationOffsetA, const Vector3& translationOffsetA,
     PhysicsRigidBody* b, const Quaternion& rotationOffsetB, const Vector3& translationOffsetB)
     PhysicsRigidBody* b, const Quaternion& rotationOffsetB, const Vector3& translationOffsetB)
+    : PhysicsConstraint(a, b)
 {
 {
+    // Take scale into account for the first node's translation offset.
+    Vector3 sA;
+    a->_node->getWorldMatrix().getScale(&sA);
+    Vector3 tA(translationOffsetA.x * sA.x, translationOffsetA.y * sA.y, translationOffsetA.z * sA.z);
+
     if (b)
     if (b)
     {
     {
-        btTransform frameInA(btQuaternion(rotationOffsetA.x, rotationOffsetA.y, rotationOffsetA.z, rotationOffsetA.w), 
-            btVector3(translationOffsetA.x, translationOffsetA.y, translationOffsetA.z));
-        btTransform frameInB(btQuaternion(rotationOffsetB.x, rotationOffsetB.y, rotationOffsetB.z, rotationOffsetB.w), 
-            btVector3(translationOffsetB.x, translationOffsetB.y, translationOffsetB.z));
+        // Take scale into account for the second node's translation offset.
+        Vector3 sB;
+        b->_node->getWorldMatrix().getScale(&sB);
+        Vector3 tB(translationOffsetB.x * sB.x, translationOffsetB.y * sB.y, translationOffsetB.z * sB.z);
+
+        btTransform frameInA(btQuaternion(rotationOffsetA.x, rotationOffsetA.y, rotationOffsetA.z, rotationOffsetA.w), btVector3(tA.x, tA.y, tA.z));
+        btTransform frameInB(btQuaternion(rotationOffsetB.x, rotationOffsetB.y, rotationOffsetB.z, rotationOffsetB.w), btVector3(tB.x, tB.y, tB.z));
         _constraint = new btGeneric6DofConstraint(*a->_body, *b->_body, frameInA, frameInB, true);
         _constraint = new btGeneric6DofConstraint(*a->_body, *b->_body, frameInA, frameInB, true);
     }
     }
     else
     else
     {
     {
-        btTransform frameInA(btQuaternion(rotationOffsetA.x, rotationOffsetA.y, rotationOffsetA.z, rotationOffsetA.w), 
-            btVector3(translationOffsetA.x, translationOffsetA.y, translationOffsetA.z));
+        btTransform frameInA(btQuaternion(rotationOffsetA.x, rotationOffsetA.y, rotationOffsetA.z, rotationOffsetA.w), btVector3(tA.x, tA.y, tA.z));
         _constraint = new btGeneric6DofConstraint(*a->_body, frameInA, true);
         _constraint = new btGeneric6DofConstraint(*a->_body, frameInA, true);
     }
     }
 }
 }

+ 16 - 6
gameplay/src/PhysicsHingeConstraint.cpp

@@ -4,6 +4,8 @@
 
 
 #include "PhysicsHingeConstraint.h"
 #include "PhysicsHingeConstraint.h"
 
 
+#include "Node.h"
+
 namespace gameplay
 namespace gameplay
 {
 {
 
 
@@ -14,19 +16,27 @@ void PhysicsHingeConstraint::setLimits(float minAngle, float maxAngle, float sof
 
 
 PhysicsHingeConstraint::PhysicsHingeConstraint(PhysicsRigidBody* a, const Quaternion& rotationOffsetA, const Vector3& translationOffsetA,
 PhysicsHingeConstraint::PhysicsHingeConstraint(PhysicsRigidBody* a, const Quaternion& rotationOffsetA, const Vector3& translationOffsetA,
     PhysicsRigidBody* b, const Quaternion& rotationOffsetB, const Vector3& translationOffsetB)
     PhysicsRigidBody* b, const Quaternion& rotationOffsetB, const Vector3& translationOffsetB)
+    : PhysicsConstraint(a, b)
 {
 {
+    // Take scale into account for the first node's translation offset.
+    Vector3 sA;
+    a->_node->getWorldMatrix().getScale(&sA);
+    Vector3 tA(translationOffsetA.x * sA.x, translationOffsetA.y * sA.y, translationOffsetA.z * sA.z);
+
     if (b)
     if (b)
     {
     {
-        btTransform frameInA(btQuaternion(rotationOffsetA.x, rotationOffsetA.y, rotationOffsetA.z, rotationOffsetA.w), 
-            btVector3(translationOffsetA.x, translationOffsetA.y, translationOffsetA.z));
-        btTransform frameInB(btQuaternion(rotationOffsetB.x, rotationOffsetB.y, rotationOffsetB.z, rotationOffsetB.w), 
-            btVector3(translationOffsetB.x, translationOffsetB.y, translationOffsetB.z));
+        // Take scale into account for the second node's translation offset.
+        Vector3 sB;
+        b->_node->getWorldMatrix().getScale(&sB);
+        Vector3 tB(translationOffsetB.x * sB.x, translationOffsetB.y * sB.y, translationOffsetB.z * sB.z);
+
+        btTransform frameInA(btQuaternion(rotationOffsetA.x, rotationOffsetA.y, rotationOffsetA.z, rotationOffsetA.w), btVector3(tA.x, tA.y, tA.z));
+        btTransform frameInB(btQuaternion(rotationOffsetB.x, rotationOffsetB.y, rotationOffsetB.z, rotationOffsetB.w), btVector3(tB.x, tB.y, tB.z));
         _constraint = new btHingeConstraint(*a->_body, *b->_body, frameInA, frameInB);
         _constraint = new btHingeConstraint(*a->_body, *b->_body, frameInA, frameInB);
     }
     }
     else
     else
     {
     {
-        btTransform frameInA(btQuaternion(rotationOffsetA.x, rotationOffsetA.y, rotationOffsetA.z, rotationOffsetA.w), 
-            btVector3(translationOffsetA.x, translationOffsetA.y, translationOffsetA.z));
+        btTransform frameInA(btQuaternion(rotationOffsetA.x, rotationOffsetA.y, rotationOffsetA.z, rotationOffsetA.w), btVector3(tA.x, tA.y, tA.z));
         _constraint = new btHingeConstraint(*a->_body, frameInA);
         _constraint = new btHingeConstraint(*a->_body, frameInA);
     }
     }
 }
 }

+ 7 - 7
gameplay/src/PhysicsMotionState.cpp

@@ -8,7 +8,7 @@ namespace gameplay
 {
 {
 
 
 PhysicsMotionState::PhysicsMotionState(Node* node, const Vector3* centerOfMassOffset) : _node(node),
 PhysicsMotionState::PhysicsMotionState(Node* node, const Vector3* centerOfMassOffset) : _node(node),
-    _needsUpdate(false), _centerOfMassOffset(btTransform::getIdentity())
+    _centerOfMassOffset(btTransform::getIdentity())
 {
 {
     // Store the initial world transform (minus the scale) for use by Bullet later on.
     // Store the initial world transform (minus the scale) for use by Bullet later on.
     Quaternion rotation;
     Quaternion rotation;
@@ -32,8 +32,8 @@ PhysicsMotionState::PhysicsMotionState(Node* node, const Vector3* centerOfMassOf
     }
     }
     else
     else
     {
     {
-		_worldTransform = btTransform(btQuaternion(rotation.x, rotation.y, rotation.z, rotation.w), 
-			btVector3(m.m[12], m.m[13], m.m[14]));
+        _worldTransform = btTransform(btQuaternion(rotation.x, rotation.y, rotation.z, rotation.w), 
+            btVector3(m.m[12], m.m[13], m.m[14]));
     }
     }
 }
 }
 
 
@@ -43,7 +43,7 @@ PhysicsMotionState::~PhysicsMotionState()
 
 
 void PhysicsMotionState::getWorldTransform(btTransform &transform) const
 void PhysicsMotionState::getWorldTransform(btTransform &transform) const
 {
 {
-	transform = _centerOfMassOffset.inverse() * _worldTransform;
+    transform = _centerOfMassOffset.inverse() * _worldTransform;
 }
 }
 
 
 void PhysicsMotionState::setWorldTransform(const btTransform &transform)
 void PhysicsMotionState::setWorldTransform(const btTransform &transform)
@@ -51,10 +51,10 @@ void PhysicsMotionState::setWorldTransform(const btTransform &transform)
     _worldTransform = transform * _centerOfMassOffset;
     _worldTransform = transform * _centerOfMassOffset;
         
         
     const btQuaternion& rot = _worldTransform.getRotation();
     const btQuaternion& rot = _worldTransform.getRotation();
-	const btVector3& pos = _worldTransform.getOrigin();
+    const btVector3& pos = _worldTransform.getOrigin();
 
 
-	_node->setRotation(rot.x(), rot.y(), rot.z(), rot.w());
-	_node->setTranslation(pos.x(), pos.y(), pos.z());
+    _node->setRotation(rot.x(), rot.y(), rot.z(), rot.w());
+    _node->setTranslation(pos.x(), pos.y(), pos.z());
 }
 }
 
 
 }
 }

+ 5 - 5
gameplay/src/PhysicsMotionState.h

@@ -18,7 +18,8 @@ namespace gameplay
  */
  */
 class PhysicsMotionState : public btMotionState
 class PhysicsMotionState : public btMotionState
 {
 {
-	friend class PhysicsRigidBody;
+    friend class PhysicsRigidBody;
+    friend class PhysicsConstraint;
 
 
 protected:
 protected:
     /**
     /**
@@ -32,7 +33,7 @@ protected:
     /**
     /**
      * Destructor.
      * Destructor.
      */
      */
-	virtual ~PhysicsMotionState();
+    virtual ~PhysicsMotionState();
 
 
     /**
     /**
      * @see btMotionState#getWorldTransform
      * @see btMotionState#getWorldTransform
@@ -45,10 +46,9 @@ protected:
     virtual void setWorldTransform(const btTransform &transform);
     virtual void setWorldTransform(const btTransform &transform);
 
 
 private:
 private:
-	Node* _node;
+    Node* _node;
     btTransform _centerOfMassOffset;
     btTransform _centerOfMassOffset;
-	btTransform _worldTransform;
-    bool _needsUpdate;
+    btTransform _worldTransform;
 };
 };
 
 
 }
 }

+ 75 - 58
gameplay/src/PhysicsRigidBody.cpp

@@ -12,18 +12,18 @@ namespace gameplay
 {
 {
 
 
 PhysicsRigidBody::PhysicsRigidBody(Node* node, PhysicsRigidBody::Type type, float mass, 
 PhysicsRigidBody::PhysicsRigidBody(Node* node, PhysicsRigidBody::Type type, float mass, 
-		float friction, float restitution, float linearDamping, float angularDamping)
+        float friction, float restitution, float linearDamping, float angularDamping)
         : _shape(NULL), _body(NULL), _node(node)
         : _shape(NULL), _body(NULL), _node(node)
 {
 {
-	switch (type)
-	{
-		case PhysicsRigidBody::PHYSICS_SHAPE_BOX:
-		{
-			const BoundingBox& box = node->getModel()->getMesh()->getBoundingBox();
+    switch (type)
+    {
+        case PhysicsRigidBody::SHAPE_BOX:
+        {
+            const BoundingBox& box = node->getModel()->getMesh()->getBoundingBox();
 
 
             PhysicsController* physics = Game::getInstance()->getPhysicsController();
             PhysicsController* physics = Game::getInstance()->getPhysicsController();
             _shape = physics->getBox(box.min, box.max, btVector3(node->getScaleX(), node->getScaleY(), node->getScaleZ()));
             _shape = physics->getBox(box.min, box.max, btVector3(node->getScaleX(), node->getScaleY(), node->getScaleZ()));
-			
+            
             // Use the center of the bounding box as the center of mass offset.
             // Use the center of the bounding box as the center of mass offset.
             Vector3 c(box.min, box.max);
             Vector3 c(box.min, box.max);
             c.scale(0.5f);
             c.scale(0.5f);
@@ -31,18 +31,18 @@ PhysicsRigidBody::PhysicsRigidBody(Node* node, PhysicsRigidBody::Type type, floa
             c.negate();
             c.negate();
 
 
             if (c.lengthSquared() > MATH_EPSILON)
             if (c.lengthSquared() > MATH_EPSILON)
-			    _body = createBulletRigidBody(_shape, mass, node, friction, restitution, linearDamping, angularDamping, &c);
+                _body = createBulletRigidBody(_shape, mass, node, friction, restitution, linearDamping, angularDamping, &c);
             else
             else
                 _body = createBulletRigidBody(_shape, mass, node, friction, restitution, linearDamping, angularDamping);
                 _body = createBulletRigidBody(_shape, mass, node, friction, restitution, linearDamping, angularDamping);
 
 
-			break;
-		}
-		case PhysicsRigidBody::PHYSICS_SHAPE_SPHERE:
-		{
-			const BoundingSphere& sphere = node->getModel()->getMesh()->getBoundingSphere();
+            break;
+        }
+        case PhysicsRigidBody::SHAPE_SPHERE:
+        {
+            const BoundingSphere& sphere = node->getModel()->getMesh()->getBoundingSphere();
 
 
-			PhysicsController* physics = Game::getInstance()->getPhysicsController();
-			_shape = physics->getSphere(sphere.radius, btVector3(node->getScaleX(), node->getScaleY(), node->getScaleZ()));
+            PhysicsController* physics = Game::getInstance()->getPhysicsController();
+            _shape = physics->getSphere(sphere.radius, btVector3(node->getScaleX(), node->getScaleY(), node->getScaleZ()));
 
 
             // Use the center of the bounding sphere as the center of mass offset.
             // Use the center of the bounding sphere as the center of mass offset.
             Vector3 c(sphere.center);
             Vector3 c(sphere.center);
@@ -53,33 +53,35 @@ PhysicsRigidBody::PhysicsRigidBody(Node* node, PhysicsRigidBody::Type type, floa
             else
             else
                 _body = createBulletRigidBody(_shape, mass, node, friction, restitution, linearDamping, angularDamping);
                 _body = createBulletRigidBody(_shape, mass, node, friction, restitution, linearDamping, angularDamping);
 
 
-			break;
-		}
-		case PhysicsRigidBody::PHYSICS_SHAPE_TRIANGLE_MESH:
-		{
-			//btTriangleIndexVertexArray meshShape(numTriangles, indexPointer, indexStride, numVertices, vertexPointer, vertexStride);
-			//_shape = btBvhTriangleMeshShape(meshShape, true);
-
-			//_body = createBulletRigidBody(_shape, mass, node, friction, restitution, linearDamping, angularDamping);
-			break;
-		}
-		case PhysicsRigidBody::PHYSICS_SHAPE_HEIGHTFIELD:
-		{
-			//_shape = btHeightfieldTerrainShape(width, length, data, scale, minHeight, maxHeight, upAxis, dataType, false);
-
-			//_body = createBulletRigidBody(_shape, mass, node, friction, restitution, linearDamping, angularDamping);
-			break;
-		}
-	}
+            break;
+        }
+        case PhysicsRigidBody::SHAPE_TRIANGLE_MESH:
+        {
+            //btTriangleIndexVertexArray meshShape(numTriangles, indexPointer, indexStride, numVertices, vertexPointer, vertexStride);
+            //_shape = btBvhTriangleMeshShape(meshShape, true);
+
+            //_body = createBulletRigidBody(_shape, mass, node, friction, restitution, linearDamping, angularDamping);
+            break;
+        }
+        case PhysicsRigidBody::SHAPE_HEIGHTFIELD:
+        {
+            //_shape = btHeightfieldTerrainShape(width, length, data, scale, minHeight, maxHeight, upAxis, dataType, false);
+
+            //_body = createBulletRigidBody(_shape, mass, node, friction, restitution, linearDamping, angularDamping);
+            break;
+        }
+    }
 }
 }
 
 
 PhysicsRigidBody::~PhysicsRigidBody()
 PhysicsRigidBody::~PhysicsRigidBody()
 {
 {
     // Clean up all constraints linked to this rigid body.
     // Clean up all constraints linked to this rigid body.
-    for (unsigned int i = 0; i < _constraints.size(); i++)
+    PhysicsConstraint* ptr = NULL;
+    while (_constraints.size() > 0)
     {
     {
-        Game::getInstance()->getPhysicsController()->removeConstraint(_constraints[i]);
-        SAFE_RELEASE(_constraints[i]);
+        ptr = _constraints.back();
+        _constraints.pop_back();
+        SAFE_DELETE(ptr);
     }
     }
 
 
     // Clean up the rigid body and its related objects.
     // Clean up the rigid body and its related objects.
@@ -104,9 +106,9 @@ void PhysicsRigidBody::applyForce(const Vector3& force, const Vector3* relativeP
     {
     {
         _body->activate();
         _body->activate();
         if (relativePosition)
         if (relativePosition)
-		    _body->applyForce(btVector3(force.x, force.y, force.z), btVector3(relativePosition->x, relativePosition->y, relativePosition->z));
-	    else
-		    _body->applyCentralForce(btVector3(force.x, force.y, force.z));
+            _body->applyForce(btVector3(force.x, force.y, force.z), btVector3(relativePosition->x, relativePosition->y, relativePosition->z));
+        else
+            _body->applyCentralForce(btVector3(force.x, force.y, force.z));
     }
     }
 }
 }
 
 
@@ -118,12 +120,12 @@ void PhysicsRigidBody::applyImpulse(const Vector3& impulse, const Vector3* relat
     {
     {
         _body->activate();
         _body->activate();
 
 
-	    if (relativePosition)
+        if (relativePosition)
         {
         {
-		    _body->applyImpulse(btVector3(impulse.x, impulse.y, impulse.z), btVector3(relativePosition->x, relativePosition->y, relativePosition->z));
+            _body->applyImpulse(btVector3(impulse.x, impulse.y, impulse.z), btVector3(relativePosition->x, relativePosition->y, relativePosition->z));
         }
         }
-	    else
-		    _body->applyCentralImpulse(btVector3(impulse.x, impulse.y, impulse.z));
+        else
+            _body->applyCentralImpulse(btVector3(impulse.x, impulse.y, impulse.z));
     }
     }
 }
 }
 
 
@@ -134,7 +136,7 @@ void PhysicsRigidBody::applyTorque(const Vector3& torque)
     if (torque.lengthSquared() > MATH_EPSILON)
     if (torque.lengthSquared() > MATH_EPSILON)
     {
     {
         _body->activate();
         _body->activate();
-	    _body->applyTorque(btVector3(torque.x, torque.y, torque.z));
+        _body->applyTorque(btVector3(torque.x, torque.y, torque.z));
     }
     }
 }
 }
 
 
@@ -152,28 +154,43 @@ void PhysicsRigidBody::applyTorqueImpulse(const Vector3& torque)
 btRigidBody* PhysicsRigidBody::createBulletRigidBody(btCollisionShape* shape, float mass, Node* node,
 btRigidBody* PhysicsRigidBody::createBulletRigidBody(btCollisionShape* shape, float mass, Node* node,
     float friction, float restitution, float linearDamping, float angularDamping, const Vector3* centerOfMassOffset)
     float friction, float restitution, float linearDamping, float angularDamping, const Vector3* centerOfMassOffset)
 {
 {
-	// If the mass is non-zero, then the object is dynamic
-	// and we need to calculate the local inertia.
-	btVector3 localInertia(0.0, 0.0, 0.0);
-	if (mass != 0.0)
-		shape->calculateLocalInertia(mass, localInertia);
-
-	// Create the Bullet physics rigid body object.
-	PhysicsMotionState* motionState = new PhysicsMotionState(node, centerOfMassOffset);
-	btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, motionState, shape, localInertia);
+    // If the mass is non-zero, then the object is dynamic
+    // and we need to calculate the local inertia.
+    btVector3 localInertia(0.0, 0.0, 0.0);
+    if (mass != 0.0)
+        shape->calculateLocalInertia(mass, localInertia);
+
+    // Create the Bullet physics rigid body object.
+    PhysicsMotionState* motionState = new PhysicsMotionState(node, centerOfMassOffset);
+    btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, motionState, shape, localInertia);
     rbInfo.m_friction = friction;
     rbInfo.m_friction = friction;
     rbInfo.m_restitution = restitution;
     rbInfo.m_restitution = restitution;
     rbInfo.m_linearDamping = linearDamping;
     rbInfo.m_linearDamping = linearDamping;
     rbInfo.m_angularDamping = angularDamping;
     rbInfo.m_angularDamping = angularDamping;
-	btRigidBody* body = new btRigidBody(rbInfo);
+    btRigidBody* body = new btRigidBody(rbInfo);
 
 
-	// Add the rigid body to the physics world.
-	PhysicsController* physics = Game::getInstance()->getPhysicsController();
-	physics->_world->addRigidBody(body);
+    // Add the rigid body to the physics world.
+    PhysicsController* physics = Game::getInstance()->getPhysicsController();
+    physics->_world->addRigidBody(body);
 
 
-	return body;
+    return body;
 }
 }
 
 
+void PhysicsRigidBody::addConstraint(PhysicsConstraint* constraint)
+{
+    _constraints.push_back(constraint);
+}
 
 
+void PhysicsRigidBody::removeConstraint(PhysicsConstraint* constraint)
+{
+    for (unsigned int i = 0; i < _constraints.size(); i++)
+    {
+        if (_constraints[i] == constraint)
+        {
+            _constraints.erase(_constraints.begin() + i);
+            break;
+        }
+    }
+}
 
 
 }
 }

+ 21 - 17
gameplay/src/PhysicsRigidBody.h

@@ -6,6 +6,7 @@
 #define PHYSICSRIGIDBODY_H_
 #define PHYSICSRIGIDBODY_H_
 
 
 #include "Mesh.h"
 #include "Mesh.h"
+#include "PhysicsConstraint.h"
 #include "Ref.h"
 #include "Ref.h"
 #include "Transform.h"
 #include "Transform.h"
 #include "Vector3.h"
 #include "Vector3.h"
@@ -22,11 +23,11 @@ class PhysicsConstraint;
 class PhysicsRigidBody : public Ref
 class PhysicsRigidBody : public Ref
 {
 {
     friend class Node;
     friend class Node;
-	friend class PhysicsController;
+    friend class PhysicsConstraint;
+    friend class PhysicsController;
     friend class PhysicsFixedConstraint;
     friend class PhysicsFixedConstraint;
     friend class PhysicsGenericConstraint;
     friend class PhysicsGenericConstraint;
     friend class PhysicsHingeConstraint;
     friend class PhysicsHingeConstraint;
-    friend class PhysicsMotionState;
     friend class PhysicsSocketConstraint;
     friend class PhysicsSocketConstraint;
     friend class PhysicsSpringConstraint;
     friend class PhysicsSpringConstraint;
 
 
@@ -34,14 +35,14 @@ public:
     /**
     /**
      * Represents the different types of rigid bodies.
      * Represents the different types of rigid bodies.
      */
      */
-	enum Type
-	{
-		PHYSICS_SHAPE_BOX,
-		PHYSICS_SHAPE_SPHERE,
-		PHYSICS_SHAPE_TRIANGLE_MESH,
-		PHYSICS_SHAPE_HEIGHTFIELD,
-        PHYSICS_SHAPE_NONE
-	};
+    enum Type
+    {
+        SHAPE_BOX,
+        SHAPE_SPHERE,
+        SHAPE_TRIANGLE_MESH,
+        SHAPE_HEIGHTFIELD,
+        SHAPE_NONE
+    };
 
 
     /**
     /**
      * Applies the given force to the rigid body (optionally, from the given relative position).
      * Applies the given force to the rigid body (optionally, from the given relative position).
@@ -57,14 +58,14 @@ public:
      * @param impulse The force impulse to be applied.
      * @param impulse The force impulse to be applied.
      * @param relativePosition The relative position from which to apply the force.
      * @param relativePosition The relative position from which to apply the force.
      */
      */
-	void applyImpulse(const Vector3& impulse, const Vector3* relativePosition = NULL);
+    void applyImpulse(const Vector3& impulse, const Vector3* relativePosition = NULL);
 
 
     /**
     /**
      * Applies the given torque to the rigid body.
      * Applies the given torque to the rigid body.
      * 
      * 
      * @param torque The torque to be applied.
      * @param torque The torque to be applied.
      */
      */
-	void applyTorque(const Vector3& torque);
+    void applyTorque(const Vector3& torque);
 
 
     /**
     /**
      * Applies the given torque impulse to the rigid body.
      * Applies the given torque impulse to the rigid body.
@@ -150,7 +151,7 @@ public:
      * @param linearDamping The linear damping; between 0.0 (minimum) and 1.0 (maximum).
      * @param linearDamping The linear damping; between 0.0 (minimum) and 1.0 (maximum).
      * @param angularDamping The angular damping; between 0.0 (minimum) and 1.0 (maximum).
      * @param angularDamping The angular damping; between 0.0 (minimum) and 1.0 (maximum).
      */
      */
-	inline void setDamping(float linearDamping, float angularDamping);
+    inline void setDamping(float linearDamping, float angularDamping);
 
 
     /**
     /**
      * Sets the rigid body's friction.
      * Sets the rigid body's friction.
@@ -178,7 +179,7 @@ public:
      * 
      * 
      * @param restitution The restitution.
      * @param restitution The restitution.
      */
      */
-	inline void setRestitution(float restitution);
+    inline void setRestitution(float restitution);
 
 
 private:
 private:
     /**
     /**
@@ -209,14 +210,17 @@ private:
 
 
     // Creates the underlying Bullet Physics rigid body object
     // Creates the underlying Bullet Physics rigid body object
     // for a PhysicsRigidBody object using the given parameters.
     // for a PhysicsRigidBody object using the given parameters.
-	static btRigidBody* createBulletRigidBody(btCollisionShape* shape, float mass, Node* node,
+    static btRigidBody* createBulletRigidBody(btCollisionShape* shape, float mass, Node* node,
         float friction, float restitution, float linearDamping, float angularDamping,
         float friction, float restitution, float linearDamping, float angularDamping,
         const Vector3* centerOfMassOffset = NULL);
         const Vector3* centerOfMassOffset = NULL);
 
 
     // Adds a constraint to this rigid body.
     // Adds a constraint to this rigid body.
-    inline void addConstraint(PhysicsConstraint* constraint);
+    void addConstraint(PhysicsConstraint* constraint);
 
 
-	btCollisionShape* _shape;
+    // Removes a constraint from this rigid body (used by the constraint destructor).
+    void removeConstraint(PhysicsConstraint* constraint);
+
+    btCollisionShape* _shape;
     btRigidBody* _body;
     btRigidBody* _body;
     Node* _node;
     Node* _node;
     std::vector<PhysicsConstraint*> _constraints;
     std::vector<PhysicsConstraint*> _constraints;

+ 8 - 13
gameplay/src/PhysicsRigidBody.inl

@@ -12,13 +12,13 @@ namespace gameplay
 
 
 inline float PhysicsRigidBody::getAngularDamping() const
 inline float PhysicsRigidBody::getAngularDamping() const
 {
 {
-	return _body->getAngularDamping();
+    return _body->getAngularDamping();
 }
 }
 
 
 inline Vector3 PhysicsRigidBody::getAngularVelocity() const
 inline Vector3 PhysicsRigidBody::getAngularVelocity() const
 {
 {
-	const btVector3& v = _body->getAngularVelocity();
-	return Vector3(v.x(), v.y(), v.z());
+    const btVector3& v = _body->getAngularVelocity();
+    return Vector3(v.x(), v.y(), v.z());
 }
 }
 
 
 inline Vector3 PhysicsRigidBody::getAnisotropicFriction() const
 inline Vector3 PhysicsRigidBody::getAnisotropicFriction() const
@@ -40,13 +40,13 @@ inline Vector3 PhysicsRigidBody::getGravity() const
 
 
 inline float PhysicsRigidBody::getLinearDamping() const
 inline float PhysicsRigidBody::getLinearDamping() const
 {
 {
-	return _body->getLinearDamping();
+    return _body->getLinearDamping();
 }
 }
 
 
 inline Vector3 PhysicsRigidBody::getLinearVelocity() const
 inline Vector3 PhysicsRigidBody::getLinearVelocity() const
 {
 {
-	const btVector3& v = _body->getLinearVelocity();
-	return Vector3(v.x(), v.y(), v.z());
+    const btVector3& v = _body->getLinearVelocity();
+    return Vector3(v.x(), v.y(), v.z());
 }
 }
 
 
 inline float PhysicsRigidBody::getRestitution() const
 inline float PhysicsRigidBody::getRestitution() const
@@ -56,7 +56,7 @@ inline float PhysicsRigidBody::getRestitution() const
 
 
 inline void PhysicsRigidBody::setAngularVelocity(const Vector3& velocity)
 inline void PhysicsRigidBody::setAngularVelocity(const Vector3& velocity)
 {
 {
-	_body->setAngularVelocity(btVector3(velocity.x, velocity.y, velocity.z));
+    _body->setAngularVelocity(btVector3(velocity.x, velocity.y, velocity.z));
 }
 }
 
 
 inline void PhysicsRigidBody::setAnisotropicFriction(const Vector3& friction)
 inline void PhysicsRigidBody::setAnisotropicFriction(const Vector3& friction)
@@ -81,7 +81,7 @@ inline void PhysicsRigidBody::setGravity(const Vector3& gravity)
 
 
 inline void PhysicsRigidBody::setLinearVelocity(const Vector3& velocity)
 inline void PhysicsRigidBody::setLinearVelocity(const Vector3& velocity)
 {
 {
-	_body->setLinearVelocity(btVector3(velocity.x, velocity.y, velocity.z));
+    _body->setLinearVelocity(btVector3(velocity.x, velocity.y, velocity.z));
 }
 }
 
 
 inline void PhysicsRigidBody::setRestitution(float restitution)
 inline void PhysicsRigidBody::setRestitution(float restitution)
@@ -89,9 +89,4 @@ inline void PhysicsRigidBody::setRestitution(float restitution)
     _body->setRestitution(restitution);
     _body->setRestitution(restitution);
 }
 }
 
 
-inline void PhysicsRigidBody::addConstraint(PhysicsConstraint* constraint)
-{
-    _constraints.push_back(constraint);
-}
-
 }
 }

+ 18 - 25
gameplay/src/PhysicsSocketConstraint.cpp

@@ -10,30 +10,15 @@ namespace gameplay
 {
 {
 
 
 PhysicsSocketConstraint::PhysicsSocketConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b)
 PhysicsSocketConstraint::PhysicsSocketConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b)
+    : PhysicsConstraint(a, b)
 {
 {
     if (b)
     if (b)
     {
     {
-        // Create a translation matrix that translates to the midpoint
-        // between the two physics rigid bodies.
-        Matrix m;
-        Matrix::createTranslation(midpoint(a->_node, b->_node), &m);
+        Vector3 origin = centerOfMassMidpoint(a->_node, b->_node);
+        btTransform frameInA = getTransformOffset(a->_node, origin);
+        btTransform frameInB = getTransformOffset(b->_node, origin);
 
 
-        // Calculate the translation offsets to the rigid bodies
-        // by transforming the translation matrix above into each rigid body's
-        // local space (multiply by the inverse world matrix and extract translation).
-        Matrix mAi;
-        a->_node->getWorldMatrix().invert(&mAi);
-        mAi.multiply(m);
-
-        Matrix mBi;
-        b->_node->getWorldMatrix().invert(&mBi);
-        mBi.multiply(m);
-    
-        Vector3 tA, tB;
-        mAi.getTranslation(&tA);
-        mBi.getTranslation(&tB);
-
-        _constraint = new btPoint2PointConstraint(*a->_body, *b->_body, btVector3(tA.x, tA.y, tA.z), btVector3(tB.x, tB.y, tB.z));
+        _constraint = new btPoint2PointConstraint(*a->_body, *b->_body, frameInA.getOrigin(), frameInB.getOrigin());
     }
     }
     else
     else
     {
     {
@@ -43,17 +28,25 @@ PhysicsSocketConstraint::PhysicsSocketConstraint(PhysicsRigidBody* a, PhysicsRig
 
 
 PhysicsSocketConstraint::PhysicsSocketConstraint(PhysicsRigidBody* a, const Vector3& translationOffsetA, 
 PhysicsSocketConstraint::PhysicsSocketConstraint(PhysicsRigidBody* a, const Vector3& translationOffsetA, 
     PhysicsRigidBody* b, const Vector3& translationOffsetB)
     PhysicsRigidBody* b, const Vector3& translationOffsetB)
+    : PhysicsConstraint(a, b)
 {
 {
+    // Take scale into account for the first node's translation offset.
+    Vector3 sA;
+    a->_node->getWorldMatrix().getScale(&sA);
+    Vector3 tA(translationOffsetA.x * sA.x, translationOffsetA.y * sA.y, translationOffsetA.z * sA.z);
+
     if (b)
     if (b)
     {
     {
-        _constraint = new btPoint2PointConstraint(*a->_body, *b->_body, 
-            btVector3(translationOffsetA.x, translationOffsetA.y, translationOffsetA.z),
-            btVector3(translationOffsetB.x, translationOffsetB.y, translationOffsetB.z));
+        // Take scale into account for the second node's translation offset.
+        Vector3 sB;
+        b->_node->getWorldMatrix().getScale(&sB);
+        Vector3 tB(translationOffsetB.x * sB.x, translationOffsetB.y * sB.y, translationOffsetB.z * sB.z);
+
+        _constraint = new btPoint2PointConstraint(*a->_body, *b->_body, btVector3(tA.x, tA.y, tA.z), btVector3(tB.x, tB.y, tB.z));
     }
     }
     else
     else
     {
     {
-        _constraint = new btPoint2PointConstraint(*a->_body, 
-            btVector3(translationOffsetA.x, translationOffsetA.y, translationOffsetA.z));
+        _constraint = new btPoint2PointConstraint(*a->_body, btVector3(tA.x, tA.y, tA.z));
     }
     }
 }
 }
 
 

+ 24 - 30
gameplay/src/PhysicsSpringConstraint.cpp

@@ -12,44 +12,38 @@ namespace gameplay
 
 
 PhysicsSpringConstraint::PhysicsSpringConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b)
 PhysicsSpringConstraint::PhysicsSpringConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b)
 {
 {
-    // Create a translation matrix that translates to the midpoint
-    // between the two physics rigid bodies.
-    Matrix m;
-    Matrix::createTranslation(midpoint(a->_node, b->_node), &m);
+    // Initialize the physics rigid body references since we don't call the PhysicsConstraint constructor that does it properly automatically.
+    _a = a;
+    _b = b;
 
 
-    // Calculate the translation and rotation offsets to the rigid bodies
-    // by transforming the translation matrix above into each rigid body's
-    // local space (multiply by the inverse world matrix and extract components).
-    Matrix mAi;
-    a->_node->getWorldMatrix().invert(&mAi);
-    mAi.multiply(m);
+    Vector3 origin = centerOfMassMidpoint(a->_node, b->_node);
+    _constraint = new btGeneric6DofSpringConstraint(*a->_body, *b->_body, getTransformOffset(a->_node, origin), getTransformOffset(b->_node, origin), true);
+}
+
+PhysicsSpringConstraint::PhysicsSpringConstraint(PhysicsRigidBody* a, const Quaternion& rotationOffsetA, const Vector3& translationOffsetA,
+    PhysicsRigidBody* b, const Quaternion& rotationOffsetB, const Vector3& translationOffsetB)
+{
+    // Initialize the physics rigid body references since we don't call the PhysicsConstraint constructor that does it properly automatically.
+    _a = a;
+    _b = b;
 
 
-    Matrix mBi;
-    b->_node->getWorldMatrix().invert(&mBi);
-    mBi.multiply(m);
+    // Take scale into account for the translation offsets.
+    Vector3 sA;
+    a->_node->getWorldMatrix().getScale(&sA);
+    Vector3 tA(translationOffsetA.x * sA.x, translationOffsetA.y * sA.y, translationOffsetA.z * sA.z);
 
 
-    Quaternion rA, rB;
-    mAi.getRotation(&rA);
-    mBi.getRotation(&rB);
-    
-    Vector3 tA, tB;
-    mAi.getTranslation(&tA);
-    mBi.getTranslation(&tB);
+    Vector3 sB;
+    b->_node->getWorldMatrix().getScale(&sB);
+    Vector3 tB(translationOffsetB.x * sB.x, translationOffsetB.y * sB.y, translationOffsetB.z * sB.z);
 
 
-    btTransform frameInA(btQuaternion(rA.x, rA.y, rA.z, rA.w), btVector3(tA.x, tA.y, tA.z));
-    btTransform frameInB(btQuaternion(rB.x, rB.y, rB.z, rB.w), btVector3(tB.x, tB.y, tB.z));
-            
+    btTransform frameInA(btQuaternion(rotationOffsetA.x, rotationOffsetA.y, rotationOffsetA.z, rotationOffsetA.w), btVector3(tA.x, tA.y, tA.z));
+    btTransform frameInB(btQuaternion(rotationOffsetB.x, rotationOffsetB.y, rotationOffsetB.z, rotationOffsetB.w), btVector3(tB.x, tB.y, tB.z));
     _constraint = new btGeneric6DofSpringConstraint(*a->_body, *b->_body, frameInA, frameInB, true);
     _constraint = new btGeneric6DofSpringConstraint(*a->_body, *b->_body, frameInA, frameInB, true);
 }
 }
 
 
-PhysicsSpringConstraint::PhysicsSpringConstraint(PhysicsRigidBody* a, const Quaternion& rotationOffsetA, const Vector3& translationOffsetA,
-    PhysicsRigidBody* b, const Quaternion& rotationOffsetB, const Vector3& translationOffsetB)
+PhysicsSpringConstraint::~PhysicsSpringConstraint()
 {
 {
-    btTransform frameInA(btQuaternion(rotationOffsetA.x, rotationOffsetA.y, rotationOffsetA.z, rotationOffsetA.w), 
-        btVector3(translationOffsetA.x, translationOffsetA.y, translationOffsetA.z));
-    btTransform frameInB(btQuaternion(rotationOffsetB.x, rotationOffsetB.y, rotationOffsetB.z, rotationOffsetB.w), 
-        btVector3(translationOffsetB.x, translationOffsetB.y, translationOffsetB.z));
-    _constraint = new btGeneric6DofSpringConstraint(*a->_body, *b->_body, frameInA, frameInB, true);
+    // DUMMY FUNCTION
 }
 }
 
 
 void PhysicsSpringConstraint::setStrength(SpringProperty property, float strength)
 void PhysicsSpringConstraint::setStrength(SpringProperty property, float strength)

+ 5 - 0
gameplay/src/PhysicsSpringConstraint.h

@@ -169,6 +169,11 @@ private:
     PhysicsSpringConstraint(PhysicsRigidBody* a, const Quaternion& rotationOffsetA, const Vector3& translationOffsetA,
     PhysicsSpringConstraint(PhysicsRigidBody* a, const Quaternion& rotationOffsetA, const Vector3& translationOffsetA,
         PhysicsRigidBody* b, const Quaternion& rotationOffsetB, const Vector3& translationOffsetB);
         PhysicsRigidBody* b, const Quaternion& rotationOffsetB, const Vector3& translationOffsetB);
 
 
+    /**
+     * Destructor.
+     */
+    ~PhysicsSpringConstraint();
+
     // Sets the strength for the given angular/linear 
     // Sets the strength for the given angular/linear 
     // X/Y/Z axis combination determined by the given index.
     // X/Y/Z axis combination determined by the given index.
     // 
     // 

+ 3 - 3
gameplay/src/Scene.cpp

@@ -164,9 +164,6 @@ void Scene::removeNode(Node* node)
     if (node->_scene != this)
     if (node->_scene != this)
         return;
         return;
 
 
-    node->remove();
-    node->_scene = NULL;
-
     if (node == _firstNode)
     if (node == _firstNode)
     {
     {
         _firstNode = node->_nextSibling;
         _firstNode = node->_nextSibling;
@@ -176,6 +173,9 @@ void Scene::removeNode(Node* node)
         _lastNode = node->_prevSibling;
         _lastNode = node->_prevSibling;
     }
     }
 
 
+    node->remove();
+    node->_scene = NULL;
+
     SAFE_RELEASE(node);
     SAFE_RELEASE(node);
 
 
     --_nodeCount;
     --_nodeCount;

+ 2 - 2
gameplay/src/Technique.cpp

@@ -10,7 +10,7 @@ namespace gameplay
 {
 {
 
 
 Technique::Technique(const char* id, Material* material)
 Technique::Technique(const char* id, Material* material)
-	: _id(id ? id : ""), _material(material)
+    : _id(id ? id : ""), _material(material)
 {
 {
     assert(material);
     assert(material);
 
 
@@ -23,7 +23,7 @@ Technique::Technique(const Technique& m)
 
 
 Technique::~Technique()
 Technique::~Technique()
 {
 {
-	// Destroy all the passes.
+    // Destroy all the passes.
     for (unsigned int i = 0, count = _passes.size(); i < count; ++i)
     for (unsigned int i = 0, count = _passes.size(); i < count; ++i)
     {
     {
         SAFE_RELEASE(_passes[i]);
         SAFE_RELEASE(_passes[i]);