Browse Source

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

Chris Culy 14 years ago
parent
commit
c9f359b075

+ 11 - 11
.gitignore

@@ -25,7 +25,7 @@
 /gameplay-encoder/Debug
 /gameplay-encoder/Release
 /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-Coverage
 /gameplay-samples/sample00-mesh/Simulator-Profile
@@ -34,7 +34,7 @@
 /gameplay-samples/sample00-mesh/Device-Profile
 /gameplay-samples/sample00-mesh/Device-Release
 /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-Coverage
 /gameplay-samples/sample01-longboard/Simulator-Profile
@@ -60,12 +60,12 @@
 /gameplay-samples/sample03-character/Device-Coverage
 /gameplay-samples/sample03-character/Device-Profile
 /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
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gameplay-encoder", "gameplay-encoder\gameplay-encoder.vcxproj", "{9D69B743-4872-4DD1-8E30-0087C64298D7}"
 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
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A} = {1032BA4B-57EB-4348-9E03-29DD63E80E4A}
 	EndProjectSection

+ 3 - 1
gameplay/gameplay.vcxproj

@@ -94,7 +94,9 @@
     <ClInclude Include="src\Frustum.h" />
     <ClInclude Include="src\Game.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.h" />
     <ClInclude Include="src\Input.h" />

+ 3 - 3
gameplay/src/AudioController.cpp

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

+ 2 - 2
gameplay/src/Game.cpp

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

+ 4 - 4
gameplay/src/Material.cpp

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

+ 0 - 7
gameplay/src/Model.cpp

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

+ 3 - 5
gameplay/src/Node.cpp

@@ -51,6 +51,7 @@ Node::~Node()
     SAFE_RELEASE(_model);
     SAFE_RELEASE(_audioSource);
     SAFE_RELEASE(_particleEmitter);
+    SAFE_RELEASE(_physicsRigidBody);
 }
 
 Node* Node::create(const char* id)
@@ -796,12 +797,9 @@ PhysicsRigidBody* Node::getPhysicsRigidBody()
 void Node::setPhysicsRigidBody(PhysicsRigidBody::Type type, float mass, float friction,
         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);
 }
 

+ 130 - 6
gameplay/src/PhysicsConstraint.cpp

@@ -4,28 +4,40 @@
 
 #include "PhysicsConstraint.h"
 
+#include "Game.h"
 #include "Node.h"
+#include "PhysicsMotionState.h"
+#include "PhysicsRigidBody.h"
 
 namespace gameplay
 {
 
-PhysicsConstraint::PhysicsConstraint() : _constraint(NULL)
+PhysicsConstraint::PhysicsConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b)
+    : _a(a), _b(b), _constraint(NULL)
 {
 }
 
 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;
     a->getWorldMatrix().getTranslation(&tA);
     b->getWorldMatrix().getTranslation(&tB);
+
+    tA = getWorldCenterOfMass(a->getModel());
+    tB = getWorldCenterOfMass(b->getModel());
     
     Vector3 d(tA, tB);
     d.scale(0.5f);
@@ -35,4 +47,116 @@ Vector3 PhysicsConstraint::midpoint(Node* a, Node* b)
     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_
 
 #include "Base.h"
-#include "Ref.h"
+#include "Model.h"
 #include "Vector3.h"
 
 namespace gameplay
 {
     class Node;
+    class PhysicsRigidBody;
 
 /**
  * Base class for physics constraints.
  */
-class PhysicsConstraint : public Ref
+class PhysicsConstraint
 {
     friend class PhysicsController;
+    friend class PhysicsRigidBody;
 
 public:
     /**
@@ -52,11 +54,35 @@ public:
      */
     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:
     /**
      * Constructor.
      */
-    PhysicsConstraint();
+    PhysicsConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b);
 
     /**
      * Destructor.
@@ -64,10 +90,23 @@ protected:
     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;
 };
 

+ 65 - 57
gameplay/src/PhysicsController.cpp

@@ -11,8 +11,8 @@ namespace gameplay
 
 // Default gravity is 9.8 along the negative Y axis.
 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)
 {
-	_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)
@@ -101,87 +101,89 @@ PhysicsSpringConstraint* PhysicsController::createSpringConstraint(PhysicsRigidB
 
 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()
 {
-	// 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()
 {
-	// DUMMY FUNCTION
+    // DUMMY FUNCTION
 }
 
 void PhysicsController::resume()
 {
-	// DUMMY FUNCTION
+    // DUMMY FUNCTION
 }
 
 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)
 {
-	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)
 {
-	// 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)
 {
-	return NULL;
+    return NULL;
 }
 
 btCollisionShape* PhysicsController::getHeightfield(void* data, int width, int height)
 {
-	return NULL;
+    return NULL;
 }
 
 void PhysicsController::setupConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b, PhysicsConstraint* constraint)
 {
     a->addConstraint(constraint);
     if (b)
+    {
         b->addConstraint(constraint);
+    }
 
     _world->addConstraint(constraint->_constraint);
 }
@@ -189,23 +191,29 @@ void PhysicsController::setupConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b
 void PhysicsController::removeConstraint(PhysicsConstraint* constraint)
 {
     // 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)
-		    _world->removeConstraint(currentConstraint);
-	}
+        {
+            _world->removeConstraint(currentConstraint);
+            break;
+        }
+    }
 }
 
 void PhysicsController::removeRigidBody(PhysicsRigidBody* rigidBody)
 {
     // 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)
-		    _world->removeCollisionObject(obj);
-	}
+        {
+            _world->removeCollisionObject(obj);
+            break;
+        }
+    }
 }
 
 }

+ 44 - 43
gameplay/src/PhysicsController.h

@@ -15,22 +15,23 @@
 
 namespace gameplay
 {
-	
+    
 /**
  * Defines a class for controlling game physics.
  */
 class PhysicsController
 {
-	friend class Game;
-	friend class PhysicsRigidBody;
+    friend class Game;
+    friend class PhysicsConstraint;
+    friend class PhysicsRigidBody;
 
 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.
@@ -144,52 +145,52 @@ public:
         const Vector3& translationOffsetA, PhysicsRigidBody* b, const Quaternion& rotationOffsetB, const Vector3& translationOffsetB);
 
 private:
-	/**
-	 * Constructor.
-	 */
-	PhysicsController();
+    /**
+     * Constructor.
+     */
+    PhysicsController();
 
     /**
-	 * Destructor.
-	 */
-	~PhysicsController();
+     * Destructor.
+     */
+    ~PhysicsController();
 
-	/**
-	 * Controller initialize.
-	 */
-	void initialize();
+    /**
+     * Controller initialize.
+     */
+    void initialize();
 
-	/**
-	 * Controller finalize.
-	 */
+    /**
+     * Controller finalize.
+     */
     void finalize();
 
-	/**
-	 * Controller pause.
-	 */
+    /**
+     * Controller pause.
+     */
     void pause();
 
-	/**
-	 * Controller resume.
-	 */
+    /**
+     * Controller resume.
+     */
     void resume();
 
-	/**
-	 * Controller update.
-	 */
+    /**
+     * Controller update.
+     */
     void update(long elapsedTime);
 
     // 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.
-	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.
-	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.
-	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.
     void setupConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b, PhysicsConstraint* constraint);
@@ -200,13 +201,13 @@ private:
     // Removes the given rigid body from the simulated physics world.
     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 "Node.h"
+#include "PhysicsMotionState.h"
 #include "PhysicsRigidBody.h"
 
 namespace gameplay
 {
 
 PhysicsGenericConstraint::PhysicsGenericConstraint()
+    : PhysicsConstraint(NULL, NULL)
 {
     // DUMMY FUNCTION
 }
 
 PhysicsGenericConstraint::PhysicsGenericConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b)
+    : PhysicsConstraint(a, 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
     {
@@ -55,19 +33,27 @@ PhysicsGenericConstraint::PhysicsGenericConstraint(PhysicsRigidBody* a, PhysicsR
 
 PhysicsGenericConstraint::PhysicsGenericConstraint(PhysicsRigidBody* a, const Quaternion& rotationOffsetA, const Vector3& translationOffsetA,
     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)
     {
-        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);
     }
     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);
     }
 }

+ 16 - 6
gameplay/src/PhysicsHingeConstraint.cpp

@@ -4,6 +4,8 @@
 
 #include "PhysicsHingeConstraint.h"
 
+#include "Node.h"
+
 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,
     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)
     {
-        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);
     }
     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);
     }
 }

+ 7 - 7
gameplay/src/PhysicsMotionState.cpp

@@ -8,7 +8,7 @@ namespace gameplay
 {
 
 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.
     Quaternion rotation;
@@ -32,8 +32,8 @@ PhysicsMotionState::PhysicsMotionState(Node* node, const Vector3* centerOfMassOf
     }
     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
 {
-	transform = _centerOfMassOffset.inverse() * _worldTransform;
+    transform = _centerOfMassOffset.inverse() * _worldTransform;
 }
 
 void PhysicsMotionState::setWorldTransform(const btTransform &transform)
@@ -51,10 +51,10 @@ void PhysicsMotionState::setWorldTransform(const btTransform &transform)
     _worldTransform = transform * _centerOfMassOffset;
         
     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
 {
-	friend class PhysicsRigidBody;
+    friend class PhysicsRigidBody;
+    friend class PhysicsConstraint;
 
 protected:
     /**
@@ -32,7 +33,7 @@ protected:
     /**
      * Destructor.
      */
-	virtual ~PhysicsMotionState();
+    virtual ~PhysicsMotionState();
 
     /**
      * @see btMotionState#getWorldTransform
@@ -45,10 +46,9 @@ protected:
     virtual void setWorldTransform(const btTransform &transform);
 
 private:
-	Node* _node;
+    Node* _node;
     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, 
-		float friction, float restitution, float linearDamping, float angularDamping)
+        float friction, float restitution, float linearDamping, float angularDamping)
         : _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();
             _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.
             Vector3 c(box.min, box.max);
             c.scale(0.5f);
@@ -31,18 +31,18 @@ PhysicsRigidBody::PhysicsRigidBody(Node* node, PhysicsRigidBody::Type type, floa
             c.negate();
 
             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
                 _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.
             Vector3 c(sphere.center);
@@ -53,33 +53,35 @@ PhysicsRigidBody::PhysicsRigidBody(Node* node, PhysicsRigidBody::Type type, floa
             else
                 _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()
 {
     // 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.
@@ -104,9 +106,9 @@ void PhysicsRigidBody::applyForce(const Vector3& force, const Vector3* relativeP
     {
         _body->activate();
         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();
 
-	    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)
     {
         _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,
     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_restitution = restitution;
     rbInfo.m_linearDamping = linearDamping;
     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_
 
 #include "Mesh.h"
+#include "PhysicsConstraint.h"
 #include "Ref.h"
 #include "Transform.h"
 #include "Vector3.h"
@@ -22,11 +23,11 @@ class PhysicsConstraint;
 class PhysicsRigidBody : public Ref
 {
     friend class Node;
-	friend class PhysicsController;
+    friend class PhysicsConstraint;
+    friend class PhysicsController;
     friend class PhysicsFixedConstraint;
     friend class PhysicsGenericConstraint;
     friend class PhysicsHingeConstraint;
-    friend class PhysicsMotionState;
     friend class PhysicsSocketConstraint;
     friend class PhysicsSpringConstraint;
 
@@ -34,14 +35,14 @@ public:
     /**
      * 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).
@@ -57,14 +58,14 @@ public:
      * @param impulse The force impulse to be applied.
      * @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.
      * 
      * @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.
@@ -150,7 +151,7 @@ public:
      * @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).
      */
-	inline void setDamping(float linearDamping, float angularDamping);
+    inline void setDamping(float linearDamping, float angularDamping);
 
     /**
      * Sets the rigid body's friction.
@@ -178,7 +179,7 @@ public:
      * 
      * @param restitution The restitution.
      */
-	inline void setRestitution(float restitution);
+    inline void setRestitution(float restitution);
 
 private:
     /**
@@ -209,14 +210,17 @@ private:
 
     // Creates the underlying Bullet Physics rigid body object
     // 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,
         const Vector3* centerOfMassOffset = NULL);
 
     // 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;
     Node* _node;
     std::vector<PhysicsConstraint*> _constraints;

+ 8 - 13
gameplay/src/PhysicsRigidBody.inl

@@ -12,13 +12,13 @@ namespace gameplay
 
 inline float PhysicsRigidBody::getAngularDamping() const
 {
-	return _body->getAngularDamping();
+    return _body->getAngularDamping();
 }
 
 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
@@ -40,13 +40,13 @@ inline Vector3 PhysicsRigidBody::getGravity() const
 
 inline float PhysicsRigidBody::getLinearDamping() const
 {
-	return _body->getLinearDamping();
+    return _body->getLinearDamping();
 }
 
 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
@@ -56,7 +56,7 @@ inline float PhysicsRigidBody::getRestitution() const
 
 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)
@@ -81,7 +81,7 @@ inline void PhysicsRigidBody::setGravity(const Vector3& gravity)
 
 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)
@@ -89,9 +89,4 @@ inline void PhysicsRigidBody::setRestitution(float 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)
+    : PhysicsConstraint(a, 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
     {
@@ -43,17 +28,25 @@ PhysicsSocketConstraint::PhysicsSocketConstraint(PhysicsRigidBody* a, PhysicsRig
 
 PhysicsSocketConstraint::PhysicsSocketConstraint(PhysicsRigidBody* a, const Vector3& translationOffsetA, 
     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)
     {
-        _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
     {
-        _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)
 {
-    // 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);
 }
 
-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)

+ 5 - 0
gameplay/src/PhysicsSpringConstraint.h

@@ -169,6 +169,11 @@ private:
     PhysicsSpringConstraint(PhysicsRigidBody* a, const Quaternion& rotationOffsetA, const Vector3& translationOffsetA,
         PhysicsRigidBody* b, const Quaternion& rotationOffsetB, const Vector3& translationOffsetB);
 
+    /**
+     * Destructor.
+     */
+    ~PhysicsSpringConstraint();
+
     // Sets the strength for the given angular/linear 
     // 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)
         return;
 
-    node->remove();
-    node->_scene = NULL;
-
     if (node == _firstNode)
     {
         _firstNode = node->_nextSibling;
@@ -176,6 +173,9 @@ void Scene::removeNode(Node* node)
         _lastNode = node->_prevSibling;
     }
 
+    node->remove();
+    node->_scene = NULL;
+
     SAFE_RELEASE(node);
 
     --_nodeCount;

+ 2 - 2
gameplay/src/Technique.cpp

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