Browse Source

Merge branch 'next' of https://github.com/blackberry-gaming/GamePlay into properties

Adam Blake 14 năm trước cách đây
mục cha
commit
eb41087fa3
76 tập tin đã thay đổi với 1887 bổ sung714 xóa
  1. 1 1
      gameplay-encoder/README.md
  2. 10 0
      gameplay-encoder/src/Animation.cpp
  3. 17 1
      gameplay-encoder/src/Animation.h
  4. 19 14
      gameplay-encoder/src/AnimationChannel.cpp
  5. 12 1
      gameplay-encoder/src/AnimationChannel.h
  6. 8 0
      gameplay-encoder/src/Base.h
  7. 72 38
      gameplay-encoder/src/DAESceneEncoder.cpp
  8. 103 53
      gameplay-encoder/src/FBXSceneEncoder.cpp
  9. 144 0
      gameplay-encoder/src/GPBFile.cpp
  10. 15 0
      gameplay-encoder/src/GPBFile.h
  11. 0 2
      gameplay-encoder/src/Mesh.cpp
  12. 2 4
      gameplay-encoder/src/Mesh.h
  13. 2 2
      gameplay-encoder/src/Node.cpp
  14. 1 1
      gameplay-encoder/src/Node.h
  15. 89 0
      gameplay-encoder/src/Transform.cpp
  16. 11 0
      gameplay-encoder/src/Transform.h
  17. 18 12
      gameplay-encoder/src/Vertex.cpp
  18. 21 7
      gameplay-encoder/src/Vertex.h
  19. 245 0
      gameplay-newproject.sh
  20. 1 3
      gameplay/.cproject
  21. 0 12
      gameplay/.project
  22. 4 2
      gameplay/src/Animation.cpp
  23. 183 88
      gameplay/src/AnimationClip.cpp
  24. 72 34
      gameplay/src/AnimationClip.h
  25. 15 19
      gameplay/src/AnimationController.cpp
  26. 43 6
      gameplay/src/AudioBuffer.cpp
  27. 2 10
      gameplay/src/Base.h
  28. 1 1
      gameplay/src/BoundingBox.h
  29. 1 1
      gameplay/src/BoundingBox.inl
  30. 1 1
      gameplay/src/BoundingSphere.h
  31. 1 1
      gameplay/src/BoundingSphere.inl
  32. 2 1
      gameplay/src/DebugNew.cpp
  33. 10 10
      gameplay/src/Font.cpp
  34. 1 1
      gameplay/src/Font.h
  35. 10 7
      gameplay/src/Game.cpp
  36. 4 12
      gameplay/src/Game.h
  37. 1 1
      gameplay/src/Matrix.cpp
  38. 9 9
      gameplay/src/Matrix.h
  39. 6 6
      gameplay/src/Matrix.inl
  40. 8 7
      gameplay/src/Mouse.h
  41. 2 2
      gameplay/src/Package.cpp
  42. 1 1
      gameplay/src/PhysicsConstraint.cpp
  43. 146 51
      gameplay/src/PhysicsController.cpp
  44. 35 3
      gameplay/src/PhysicsController.h
  45. 3 3
      gameplay/src/PhysicsGenericConstraint.cpp
  46. 8 8
      gameplay/src/PhysicsGenericConstraint.inl
  47. 3 3
      gameplay/src/PhysicsHingeConstraint.cpp
  48. 4 5
      gameplay/src/PhysicsMotionState.cpp
  49. 26 52
      gameplay/src/PhysicsRigidBody.cpp
  50. 22 24
      gameplay/src/PhysicsRigidBody.h
  51. 4 4
      gameplay/src/PhysicsRigidBody.inl
  52. 2 2
      gameplay/src/PhysicsSocketConstraint.cpp
  53. 2 2
      gameplay/src/PhysicsSpringConstraint.cpp
  54. 1 1
      gameplay/src/Plane.h
  55. 1 1
      gameplay/src/Plane.inl
  56. 14 0
      gameplay/src/Platform.h
  57. 11 1
      gameplay/src/PlatformAndroid.cpp
  58. 91 10
      gameplay/src/PlatformMacOS.mm
  59. 19 9
      gameplay/src/PlatformQNX.cpp
  60. 27 8
      gameplay/src/PlatformWin32.cpp
  61. 141 99
      gameplay/src/PlatformiOS.mm
  62. 12 11
      gameplay/src/Properties.cpp
  63. 6 1
      gameplay/src/Quaternion.h
  64. 7 1
      gameplay/src/Quaternion.inl
  65. 1 1
      gameplay/src/Ray.h
  66. 1 1
      gameplay/src/Ray.inl
  67. 52 8
      gameplay/src/SceneLoader.cpp
  68. 5 2
      gameplay/src/SceneLoader.h
  69. 2 1
      gameplay/src/Texture.cpp
  70. 14 5
      gameplay/src/Vector2.h
  71. 10 5
      gameplay/src/Vector2.inl
  72. 12 5
      gameplay/src/Vector3.h
  73. 11 5
      gameplay/src/Vector3.inl
  74. 14 5
      gameplay/src/Vector4.h
  75. 10 5
      gameplay/src/Vector4.inl
  76. 2 1
      gameplay/src/gameplay-main-ios.mm

+ 1 - 1
gameplay-encoder/README.md

@@ -27,7 +27,7 @@ You must then rebuild gameplay-encoder with the follow platform/tooling instruct
 - Add "fbxsdk-2012.2-mdd.lib" and "wininet.lib" to the Additional Dependencies (Linker/Input)
 - Add "fbxsdk-2012.2-mdd.lib" and "wininet.lib" to the Additional Dependencies (Linker/Input)
   * Example: fbxsdk-2012.2-mdd.lib;wininet.lib
   * Example: fbxsdk-2012.2-mdd.lib;wininet.lib
 - Add a post build event to copy the DLL (Build Events/Post-Build Event)
 - Add a post build event to copy the DLL (Build Events/Post-Build Event)
-  * Example: copy /Y "C:/Program Files/Autodesk/FBX/FbxSdk/2012.2/lib/vs2010/x86/fbxsdk-2012.2d.dll" "$(TargetDir)"
+  * Example: copy /Y "C:\Program Files\Autodesk\FBX\FbxSdk\2012.2\lib\vs2010\x86\fbxsdk-2012.2d.dll" "$(TargetDir)"
 - Build gameplay-encoder
 - Build gameplay-encoder
 
 
 ### Building FBX Support on Mac OS X using XCode 4
 ### Building FBX Support on Mac OS X using XCode 4

+ 10 - 0
gameplay-encoder/src/Animation.cpp

@@ -51,6 +51,15 @@ void Animation::add(AnimationChannel* animationChannel)
     _channels.push_back(animationChannel);
     _channels.push_back(animationChannel);
 }
 }
 
 
+void Animation::remove(AnimationChannel* animationChannel)
+{
+    std::vector<AnimationChannel*>::iterator it = std::find(_channels.begin(), _channels.end(), animationChannel);
+    if (it != _channels.end())
+    {
+        _channels.erase(it);
+    }
+}
+
 unsigned int Animation::getAnimationChannelCount() const
 unsigned int Animation::getAnimationChannelCount() const
 {
 {
     return _channels.size();
     return _channels.size();
@@ -58,6 +67,7 @@ unsigned int Animation::getAnimationChannelCount() const
 
 
 AnimationChannel* Animation::getAnimationChannel(unsigned int index) const
 AnimationChannel* Animation::getAnimationChannel(unsigned int index) const
 {
 {
+    assert(index < _channels.size());
     return _channels[index];
     return _channels[index];
 }
 }
 
 

+ 17 - 1
gameplay-encoder/src/Animation.h

@@ -26,8 +26,20 @@ public:
     virtual void writeBinary(FILE* file);
     virtual void writeBinary(FILE* file);
     virtual void writeText(FILE* file);
     virtual void writeText(FILE* file);
 
 
+    /**
+     * Adds the given animation channel to this animation.
+     * 
+     * @param animationChannel The animation channel to add.
+     */
     void add(AnimationChannel* animationChannel);
     void add(AnimationChannel* animationChannel);
 
 
+    /**
+     * Removes the given animation channel from this animation.
+     * 
+     * @param animationChannel The animation channel to remove.
+     */
+    void remove(AnimationChannel* animationChannel);
+
     /**
     /**
      * Returns the number of animation channels contained in this animation.
      * Returns the number of animation channels contained in this animation.
      * 
      * 
@@ -36,7 +48,11 @@ public:
     unsigned int getAnimationChannelCount() const;
     unsigned int getAnimationChannelCount() const;
 
 
     /**
     /**
-     * Returns the specified animation channel.
+     * Returns the animation channel at the given index.
+     * 
+     * @param index The index of the animation channel to get.
+     * 
+     * @return The pointer to the animation channel or NULL if not found.
      */
      */
     AnimationChannel* getAnimationChannel(unsigned int index) const;
     AnimationChannel* getAnimationChannel(unsigned int index) const;
 
 

+ 19 - 14
gameplay-encoder/src/AnimationChannel.cpp

@@ -43,7 +43,7 @@ void AnimationChannel::writeText(FILE* file)
 {
 {
     fprintElementStart(file);
     fprintElementStart(file);
     fprintfElement(file, "targetId", _targetId);
     fprintfElement(file, "targetId", _targetId);
-    fprintfElement(file, "targetAttrib", _targetAttrib);
+    fprintf(file, "<%s>%u %s</%s>\n", "targetAttrib", _targetAttrib, Transform::getPropertyString(_targetAttrib), "targetAttrib");
     fprintfElement(file, "%f ", "keytimes", _keytimes);
     fprintfElement(file, "%f ", "keytimes", _keytimes);
     fprintfElement(file, "%f ", "values", _keyValues);
     fprintfElement(file, "%f ", "values", _keyValues);
     fprintfElement(file, "%f ", "tangentsIn", _tangentsIn);
     fprintfElement(file, "%f ", "tangentsIn", _tangentsIn);
@@ -130,27 +130,29 @@ void AnimationChannel::setInterpolations(const std::vector<unsigned int>& values
 
 
 void AnimationChannel::removeDuplicates()
 void AnimationChannel::removeDuplicates()
 {
 {
-    if (_targetAttrib == Transform::ANIMATE_SCALE_ROTATE_TRANSLATE)
+    size_t propSize = Transform::getPropertySize(_targetAttrib);
+
+    if (propSize > 1 && !_interpolations.empty() && _interpolations[0] == LINEAR)
     {
     {
         size_t prevIndex = 0;
         size_t prevIndex = 0;
 
 
         std::vector<float>::iterator prevStart = _keyValues.begin();
         std::vector<float>::iterator prevStart = _keyValues.begin();
-        std::vector<float>::iterator prevEnd   = _keyValues.begin() + 9;
+        std::vector<float>::iterator prevEnd = prevStart + propSize - 1;
         
         
         size_t i = 1;
         size_t i = 1;
         for (i = 1; i < _keytimes.size(); ++i)
         for (i = 1; i < _keytimes.size(); ++i)
         {
         {
-            std::vector<float>::iterator start = _keyValues.begin() + i * 10;
-            std::vector<float>::iterator end = _keyValues.begin() + (i * 10 + 9);
+            std::vector<float>::iterator start = _keyValues.begin() + i * propSize;
+            std::vector<float>::iterator end = start + propSize - 1;
 
 
-            if (!equal(prevStart, prevEnd, start))
+            if (!equal(prevStart, prevEnd, start) || i == _keytimes.size() - 1)
             {
             {
                 if (i - prevIndex > 2)
                 if (i - prevIndex > 2)
                 {
                 {
-                    deleteRange(prevIndex+1, i);
+                    deleteRange(prevIndex+1, i, propSize);
                     i = prevIndex;
                     i = prevIndex;
-                    prevStart = _keyValues.begin() + i * 10;
-                    prevEnd = _keyValues.begin() + (i * 10 + 9);
+                    prevStart = _keyValues.begin() + i * propSize;
+                    prevEnd = prevStart + propSize - 1;
                 }
                 }
                 else
                 else
                 {
                 {
@@ -162,7 +164,7 @@ void AnimationChannel::removeDuplicates()
         }
         }
         if (i - 1 - prevIndex >= 2)
         if (i - 1 - prevIndex >= 2)
         {
         {
-            deleteRange(prevIndex+1, i);
+            deleteRange(prevIndex+1, i, propSize);
         }
         }
     }
     }
 }
 }
@@ -270,13 +272,14 @@ unsigned int AnimationChannel::getInterpolationType(const char* str)
     return value;
     return value;
 }
 }
 
 
-void AnimationChannel::deleteRange(size_t begin, size_t end)
+void AnimationChannel::deleteRange(size_t begin, size_t end, size_t propSize)
 {
 {
+    assert(end > begin);
     // delete range
     // delete range
     printf("delete %lu to %lu\n", begin, end - 1);
     printf("delete %lu to %lu\n", begin, end - 1);
 
 
-    std::vector<float>::iterator a = _keyValues.begin() + begin * 10;
-    std::vector<float>::iterator b = _keyValues.begin() + end * 10;
+    std::vector<float>::iterator a = _keyValues.begin() + begin * propSize;
+    std::vector<float>::iterator b = _keyValues.begin() + end * propSize;
     _keyValues.erase(a, b);
     _keyValues.erase(a, b);
 
 
     a = _keytimes.begin() + begin;
     a = _keytimes.begin() + begin;
@@ -286,9 +289,11 @@ void AnimationChannel::deleteRange(size_t begin, size_t end)
     if (_interpolations.size() > 1)
     if (_interpolations.size() > 1)
     {
     {
         std::vector<unsigned int>::iterator a = _interpolations.begin() + begin;
         std::vector<unsigned int>::iterator a = _interpolations.begin() + begin;
-        std::vector<unsigned int>::iterator b = _interpolations.begin() + end * 10;
+        std::vector<unsigned int>::iterator b = _interpolations.begin() + end * propSize;
         _interpolations.erase(a, b);
         _interpolations.erase(a, b);
     }
     }
+
+    // TODO: also remove key frames from _tangentsIn and _tangentsOut once other curve types are supported.
 }
 }
 
 
 }
 }

+ 12 - 1
gameplay-encoder/src/AnimationChannel.h

@@ -60,6 +60,9 @@ public:
     const std::vector<float>& getTangentsOut() const;
     const std::vector<float>& getTangentsOut() const;
     const std::vector<unsigned int>& getInterpolationTypes() const;
     const std::vector<unsigned int>& getInterpolationTypes() const;
 
 
+    /**
+     * Removes duplicate key frames from the animation channel.
+     */
     void removeDuplicates();
     void removeDuplicates();
 
 
     void convertToQuaternion();
     void convertToQuaternion();
@@ -77,7 +80,15 @@ public:
 
 
 private:
 private:
 
 
-    void deleteRange(size_t begin, size_t end);
+    /**
+     * Deletes all key frames from key time index begin to key time index end (exclusive).
+     * 
+     * @param begin The start index to delete.
+     * @param end The index to delete up to but not including.
+     * @param propSize The size of the animation propery to delete. Example: Translate(x,y,z) is size 3.
+     */
+    void deleteRange(size_t begin, size_t end, size_t propSize);
+
 private:
 private:
 
 
     std::string _targetId;
     std::string _targetId;

+ 8 - 0
gameplay-encoder/src/Base.h

@@ -78,6 +78,14 @@ void fillArray(float values[], float value, size_t length);
 
 
 #define ISZERO(x) (fabs(x) < 0.000001f)
 #define ISZERO(x) (fabs(x) < 0.000001f)
 
 
+// Object deletion macro
+#define SAFE_DELETE(x) \
+    if (x) \
+    { \
+        delete x; \
+        x = NULL; \
+    }
+
 #ifdef NDEBUG
 #ifdef NDEBUG
 #define DEBUGPRINT(x)
 #define DEBUGPRINT(x)
 #define DEBUGPRINT_VARG(x, ...)
 #define DEBUGPRINT_VARG(x, ...)

+ 72 - 38
gameplay-encoder/src/DAESceneEncoder.cpp

@@ -627,6 +627,7 @@ bool DAESceneEncoder::loadTarget(const domChannelRef& channelRef, AnimationChann
                     Quaternion rotation;
                     Quaternion rotation;
                     Vector3 translation;
                     Vector3 translation;
                     matrix.decompose(&scale, &rotation, &translation);
                     matrix.decompose(&scale, &rotation, &translation);
+                    rotation.normalize();
 
 
                     size_t k = i * 10;
                     size_t k = i * 10;
                     floats[k+0] = scale.x;
                     floats[k+0] = scale.x;
@@ -1240,9 +1241,9 @@ void DAESceneEncoder::loadSkeleton(domInstance_controller::domSkeleton* skeleton
     for (std::vector<std::string>::const_iterator i = jointNames.begin(); i != jointNames.end(); i++)
     for (std::vector<std::string>::const_iterator i = jointNames.begin(); i != jointNames.end(); i++)
     {
     {
         Object* obj = _gamePlayFile.getFromRefTable(*i);
         Object* obj = _gamePlayFile.getFromRefTable(*i);
-        if (obj)
+        if (obj && obj->getTypeId() == Object::NODE_ID)
         {
         {
-            Node* node = (Node*)obj;
+            Node* node = static_cast<Node*>(obj);
             _joints.push_back(node);
             _joints.push_back(node);
         }
         }
     }
     }
@@ -1673,10 +1674,9 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
             {
             {
                 maxOffset = offset;
                 maxOffset = offset;
             }
             }
-            int type = polygonInputs[k]->type;
-
             unsigned int polyIndex = (unsigned int) polyInts.get(poly + offset);
             unsigned int polyIndex = (unsigned int) polyInts.get(poly + offset);
-            switch (type)
+
+            switch (polygonInputs[k]->type)
             {
             {
             case POSITION:
             case POSITION:
                 vertex = Vertex(); // TODO
                 vertex = Vertex(); // TODO
@@ -1707,16 +1707,52 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
                 vertex.normal.z = (float)source.get(polyIndex * 3 + 2);
                 vertex.normal.z = (float)source.get(polyIndex * 3 + 2);
                 break;
                 break;
 
 
-            // TODO: Handle reading of per-vertex colors.
-            // HOW do we know how many color components to read?
-            // We must examine the Collada input accessor and read the stride/count to verify this - not ONLY for Color, but we should be doing this for ALL components (i.e. Position, Normal, etc).
-//            case Color:
-//                vertex.hasColor = true;
-//                vertex.Diffuse.R = (float)source.get(polyIndex * 3);
-//                vertex.Diffuse.G = (float)source.get(polyIndex * 3 + 1);
-//                vertex.Diffuse.B = (float)source.get(polyIndex * 3 + 2);
-//                vertex.Diffuse.A = (float)source.get(polyIndex * 3 + 3);
-//                break;
+            // TODO: We must examine the Collada input accessor and read the stride/count to verify this - not ONLY for Color, but we should be doing this for ALL components (i.e. Position, Normal, etc).
+            case COLOR:
+            {
+                domAccessor* accessor = polygonInputs[k]->accessor;
+                if (accessor)
+                {
+                    vertex.hasDiffuse = true;
+                    vertex.diffuse.w = 1.0f;
+                    unsigned int stride = (unsigned int)polygonInputs[k]->accessor->getStride();
+                    unsigned int index = polyIndex * stride;
+
+                    const domParam_Array& paramArray = accessor->getParam_array();
+                    const size_t paramArrayCount = paramArray.getCount();
+
+                    for (size_t i = 0; i < paramArrayCount; ++i)
+                    {
+                        const domParamRef& param = paramArray.get(i);
+                        const char* name = param->getName();
+                        if (name)
+                        {
+                            switch (name[0])
+                            {
+                            case 'r':
+                            case 'R':
+                                vertex.diffuse.x = (float)source.get(index + i); // red
+                                break;
+                            case 'g':
+                            case 'G':
+                                vertex.diffuse.y = (float)source.get(index + i); // green
+                                break;
+                            case 'b':
+                            case 'B':
+                                vertex.diffuse.z = (float)source.get(index + i); // blue
+                                break;
+                            case 'a':
+                            case 'A':
+                                vertex.diffuse.w = (float)source.get(index + i); // alpha
+                                break;
+                            default:
+                                break;
+                            }
+                        }
+                    }
+                }
+                break;
+            }
 
 
             case TANGENT:
             case TANGENT:
                 vertex.hasTangent = true;
                 vertex.hasTangent = true;
@@ -1786,7 +1822,7 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
     }
     }
     
     
     bool hasNormals = mesh->vertices[0].hasNormal;
     bool hasNormals = mesh->vertices[0].hasNormal;
-    bool hasColors = mesh->vertices[0].hasColor;
+    bool hasDiffuses = mesh->vertices[0].hasDiffuse;
     bool hasTangents = mesh->vertices[0].hasTangent;
     bool hasTangents = mesh->vertices[0].hasTangent;
     bool hasBinormals = mesh->vertices[0].hasBinormal;
     bool hasBinormals = mesh->vertices[0].hasBinormal;
     bool hasTexCoords = mesh->vertices[0].hasTexCoord;
     bool hasTexCoords = mesh->vertices[0].hasTexCoord;
@@ -1796,38 +1832,38 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
     // It should be the same order as how the Vertex data is written.
     // It should be the same order as how the Vertex data is written.
 
 
     // Position
     // Position
-    mesh->addVetexAttribute(POSITION, 3);
+    mesh->addVetexAttribute(POSITION, Vertex::POSITION_COUNT);
     
     
     // Normals
     // Normals
     if (hasNormals)
     if (hasNormals)
     {
     {
-        mesh->addVetexAttribute(NORMAL, 3);
+        mesh->addVetexAttribute(NORMAL, Vertex::NORMAL_COUNT);
     }
     }
     // Tangents
     // Tangents
     if (hasTangents)
     if (hasTangents)
     {
     {
-        mesh->addVetexAttribute(TANGENT, 3);
+        mesh->addVetexAttribute(TANGENT, Vertex::TANGENT_COUNT);
     }
     }
     // Binormals
     // Binormals
     if (hasBinormals)
     if (hasBinormals)
     {
     {
-        mesh->addVetexAttribute(BINORMAL, 3);
+        mesh->addVetexAttribute(BINORMAL, Vertex::BINORMAL_COUNT);
     }
     }
     // Texture Coordinates
     // Texture Coordinates
     if (hasTexCoords)
     if (hasTexCoords)
     {
     {
-        mesh->addVetexAttribute(TEXCOORD0, 2);
+        mesh->addVetexAttribute(TEXCOORD0, Vertex::TEXCOORD_COUNT);
     }
     }
     // Diffuse Color
     // Diffuse Color
-    if (hasColors)
+    if (hasDiffuses)
     {
     {
-        mesh->addVetexAttribute(COLOR, 3);
+        mesh->addVetexAttribute(COLOR, Vertex::DIFFUSE_COUNT);
     }
     }
     // Skinning BlendWeights BlendIndices
     // Skinning BlendWeights BlendIndices
-    if (hasWeights /*_vertexBlendWeights && _vertexBlendIndices*/)
+    if (hasWeights)
     {
     {
-        mesh->addVetexAttribute(BLENDWEIGHTS, 4);
-        mesh->addVetexAttribute(BLENDINDICES, 4);
+        mesh->addVetexAttribute(BLENDWEIGHTS, Vertex::BLEND_WEIGHTS_COUNT);
+        mesh->addVetexAttribute(BLENDINDICES, Vertex::BLEND_INDICES_COUNT);
     }
     }
 
 
     _gamePlayFile.addMesh(mesh);
     _gamePlayFile.addMesh(mesh);
@@ -1846,7 +1882,6 @@ void DAESceneEncoder::warning(const char* message)
 
 
 int DAESceneEncoder::getVertexUsageType(const std::string& semantic)
 int DAESceneEncoder::getVertexUsageType(const std::string& semantic)
 {
 {
-    int type = -1;
     if (semantic.length() > 0)
     if (semantic.length() > 0)
     {
     {
         switch (semantic[0])
         switch (semantic[0])
@@ -1854,48 +1889,47 @@ int DAESceneEncoder::getVertexUsageType(const std::string& semantic)
         case 'P':
         case 'P':
             if (equals(semantic, "POSITION"))
             if (equals(semantic, "POSITION"))
             {
             {
-                type = POSITION;
+                return POSITION;
             }
             }
-            break;
         case 'N':
         case 'N':
             if (equals(semantic, "NORMAL"))
             if (equals(semantic, "NORMAL"))
             {
             {
-                type = NORMAL;
+                return NORMAL;
             }
             }
         case 'C':
         case 'C':
             if (equals(semantic, "COLOR"))
             if (equals(semantic, "COLOR"))
             {
             {
-                type = COLOR;
+                return COLOR;
             }
             }
         case 'T':
         case 'T':
             if (equals(semantic, "TANGENT"))
             if (equals(semantic, "TANGENT"))
             {
             {
-                type = TANGENT;
+                return TANGENT;
             }
             }
             else if (equals(semantic, "TEXCOORD"))
             else if (equals(semantic, "TEXCOORD"))
             {
             {
-                type = TEXCOORD0;
+                return TEXCOORD0;
             }
             }
             else if (equals(semantic, "TEXTANGENT"))
             else if (equals(semantic, "TEXTANGENT"))
             {
             {
                 // Treat TEXTANGENT as TANGENT
                 // Treat TEXTANGENT as TANGENT
-                type = TANGENT;
+                return TANGENT;
             }
             }
             else if (equals(semantic, "TEXBINORMAL"))
             else if (equals(semantic, "TEXBINORMAL"))
             {
             {
                 // Treat TEXBINORMAL as BINORMAL
                 // Treat TEXBINORMAL as BINORMAL
-                type = BINORMAL;
+                return BINORMAL;
             }
             }
         case 'B':
         case 'B':
             if (equals(semantic, "BINORMAL"))
             if (equals(semantic, "BINORMAL"))
             {
             {
-                type = BINORMAL;
+                return BINORMAL;
             }
             }
         default:
         default:
-            break;
+            return -1;
         }
         }
     }
     }
-    return type;
+    return -1;
 }
 }
 
 
 DAESceneEncoder::DAEPolygonInput::DAEPolygonInput(void) :
 DAESceneEncoder::DAEPolygonInput::DAEPolygonInput(void) :

+ 103 - 53
gameplay-encoder/src/FBXSceneEncoder.cpp

@@ -15,7 +15,7 @@ using namespace gameplay;
  * 
  * 
  * @return The aspect ratio from the camera.
  * @return The aspect ratio from the camera.
  */
  */
-float getAspectRatio(KFbxCamera* fbxCamera);
+static float getAspectRatio(KFbxCamera* fbxCamera);
 
 
 /**
 /**
  * Returns the field of view Y from the given camera.
  * Returns the field of view Y from the given camera.
@@ -24,7 +24,7 @@ float getAspectRatio(KFbxCamera* fbxCamera);
  * 
  * 
  * @return The field of view Y.
  * @return The field of view Y.
  */
  */
-float getFieldOfView(KFbxCamera* fbxCamera);
+static float getFieldOfView(KFbxCamera* fbxCamera);
 
 
 /**
 /**
  * Loads the texture coordinates from given mesh's polygon part into the vertex.
  * Loads the texture coordinates from given mesh's polygon part into the vertex.
@@ -34,7 +34,7 @@ float getFieldOfView(KFbxCamera* fbxCamera);
  * @param posInPoly The position in the polygon.
  * @param posInPoly The position in the polygon.
  * @param vertex The vertex to copy the texture coordinates to.
  * @param vertex The vertex to copy the texture coordinates to.
  */
  */
-void loadTextureCoords(KFbxMesh* fbxMesh, int polyIndex, int posInPoly, Vertex* vertex);
+static void loadTextureCoords(KFbxMesh* fbxMesh, int polyIndex, int posInPoly, Vertex* vertex);
 
 
 /**
 /**
  * Loads the normal from the mesh and adds it to the given vertex.
  * Loads the normal from the mesh and adds it to the given vertex.
@@ -43,7 +43,7 @@ void loadTextureCoords(KFbxMesh* fbxMesh, int polyIndex, int posInPoly, Vertex*
  * @param vertexIndex The vertex index in the mesh.
  * @param vertexIndex The vertex index in the mesh.
  * @param vertex The vertex to copy to.
  * @param vertex The vertex to copy to.
  */
  */
-void loadNormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
+static void loadNormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
 
 
 /**
 /**
  * Loads the tangent from the mesh and adds it to the given vertex.
  * Loads the tangent from the mesh and adds it to the given vertex.
@@ -52,7 +52,7 @@ void loadNormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
  * @param vertexIndex The index of the vertex within fbxMesh.
  * @param vertexIndex The index of the vertex within fbxMesh.
  * @param vertex The vertex to copy to.
  * @param vertex The vertex to copy to.
  */
  */
-void loadTangent(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
+static void loadTangent(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
 
 
 /**
 /**
  * Loads the binormal from the mesh and adds it to the given vertex.
  * Loads the binormal from the mesh and adds it to the given vertex.
@@ -61,7 +61,16 @@ void loadTangent(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
  * @param vertexIndex The index of the vertex within fbxMesh.
  * @param vertexIndex The index of the vertex within fbxMesh.
  * @param vertex The vertex to copy to.
  * @param vertex The vertex to copy to.
  */
  */
-void loadBinormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
+static void loadBinormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
+
+/**
+ * Loads the vertex diffuse color from the mesh and adds it to the given vertex.
+ * 
+ * @param fbxMesh The mesh to load from.
+ * @param vertexIndex The index of the vertex within fbxMesh.
+ * @param vertex The vertex to copy to.
+ */
+static void loadVertexColor(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
 
 
 /**
 /**
  * Loads the blend weight and blend indices data into the vertex.
  * Loads the blend weight and blend indices data into the vertex.
@@ -69,7 +78,7 @@ void loadBinormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
  * @param vertexWeights List of vertex weights. The x member contains the blendIndices. The y member contains the blendWeights.
  * @param vertexWeights List of vertex weights. The x member contains the blendIndices. The y member contains the blendWeights.
  * @param vertex The vertex to copy the blend data to.
  * @param vertex The vertex to copy the blend data to.
  */
  */
-void loadBlendData(const std::vector<Vector2>& vertexWeights, Vertex* vertex);
+static void loadBlendData(const std::vector<Vector2>& vertexWeights, Vertex* vertex);
 
 
 /**
 /**
  * Loads the blend weights and blend indices from the given mesh.
  * Loads the blend weights and blend indices from the given mesh.
@@ -81,17 +90,17 @@ void loadBlendData(const std::vector<Vector2>& vertexWeights, Vertex* vertex);
  * 
  * 
  * @return True if this mesh has a mesh skin, false otherwise.
  * @return True if this mesh has a mesh skin, false otherwise.
  */
  */
-bool loadBlendWeights(KFbxMesh* fbxMesh, std::vector<std::vector<Vector2> >& weights);
+static bool loadBlendWeights(KFbxMesh* fbxMesh, std::vector<std::vector<Vector2> >& weights);
 
 
 /**
 /**
  * Copies from an FBX matrix to a float[16] array.
  * Copies from an FBX matrix to a float[16] array.
  */
  */
-void copyMatrix(const KFbxMatrix& fbxMatrix, float* matrix);
+static void copyMatrix(const KFbxMatrix& fbxMatrix, float* matrix);
 
 
 /**
 /**
  * Copies from an FBX matrix to a gameplay matrix.
  * Copies from an FBX matrix to a gameplay matrix.
  */
  */
-void copyMatrix(const KFbxMatrix& fbxMatrix, Matrix& matrix);
+static void copyMatrix(const KFbxMatrix& fbxMatrix, Matrix& matrix);
 
 
 /**
 /**
  * Finds the min and max start time and stop time of the given animation curve.
  * Finds the min and max start time and stop time of the given animation curve.
@@ -105,7 +114,7 @@ void copyMatrix(const KFbxMatrix& fbxMatrix, Matrix& matrix);
  * @param stopTime The max stop time. (in/out)
  * @param stopTime The max stop time. (in/out)
  * @param frameRate The frame rate. (in/out)
  * @param frameRate The frame rate. (in/out)
  */
  */
-void findMinMaxTime(KFbxAnimCurve* animCurve, float* startTime, float* stopTime, float* frameRate);
+static void findMinMaxTime(KFbxAnimCurve* animCurve, float* startTime, float* stopTime, float* frameRate);
 
 
 /**
 /**
  * Appends a key frame of the given node's transform at the given time.
  * Appends a key frame of the given node's transform at the given time.
@@ -115,7 +124,7 @@ void findMinMaxTime(KFbxAnimCurve* animCurve, float* startTime, float* stopTime,
  * @param keyTimes The list of key times to append to.
  * @param keyTimes The list of key times to append to.
  * @param keyValues The list of key values to append to.
  * @param keyValues The list of key values to append to.
  */
  */
-void appendKeyFrame(KFbxNode* fbxNode, float time, std::vector<float>* keyTimes, std::vector<float>* keyValues);
+static void appendKeyFrame(KFbxNode* fbxNode, float time, std::vector<float>* keyTimes, std::vector<float>* keyValues);
 
 
 /**
 /**
  * Decomposes the given node's matrix transform at the given time and copies to scale, rotation and translation.
  * Decomposes the given node's matrix transform at the given time and copies to scale, rotation and translation.
@@ -126,7 +135,7 @@ void appendKeyFrame(KFbxNode* fbxNode, float time, std::vector<float>* keyTimes,
  * @param rotation The rotation to copy to.
  * @param rotation The rotation to copy to.
  * @param translation The translation to copy to.
  * @param translation The translation to copy to.
  */
  */
-void decompose(KFbxNode* fbxNode, float time, Vector3* scale, Quaternion* rotation, Vector3* translation);
+static void decompose(KFbxNode* fbxNode, float time, Vector3* scale, Quaternion* rotation, Vector3* translation);
 
 
 /**
 /**
  * Creates an animation channel that targets the given node and target attribute using the given key times and key values.
  * Creates an animation channel that targets the given node and target attribute using the given key times and key values.
@@ -138,7 +147,7 @@ void decompose(KFbxNode* fbxNode, float time, Vector3* scale, Quaternion* rotati
  * 
  * 
  * @return The newly created animation channel.
  * @return The newly created animation channel.
  */
  */
-AnimationChannel* createAnimationChannel(KFbxNode* fbxNode, unsigned int targetAttrib, const std::vector<float>& keyTimes, const std::vector<float>& keyValues);
+static AnimationChannel* createAnimationChannel(KFbxNode* fbxNode, unsigned int targetAttrib, const std::vector<float>& keyTimes, const std::vector<float>& keyValues);
 
 
 void addScaleChannel(Animation* animation, KFbxNode* fbxNode, float startTime, float stopTime);
 void addScaleChannel(Animation* animation, KFbxNode* fbxNode, float startTime, float stopTime);
 
 
@@ -778,7 +787,7 @@ Mesh* FBXSceneEncoder::loadMesh(KFbxMesh* fbxMesh)
             loadNormal(fbxMesh, vertexIndex, &vertex);
             loadNormal(fbxMesh, vertexIndex, &vertex);
             loadTangent(fbxMesh, vertexIndex, &vertex);
             loadTangent(fbxMesh, vertexIndex, &vertex);
             loadBinormal(fbxMesh, vertexIndex, &vertex);
             loadBinormal(fbxMesh, vertexIndex, &vertex);
-            // TODO: loadDiffuseColors
+            loadVertexColor(fbxMesh, vertexIndex, &vertex);
 
 
             if (hasSkin)
             if (hasSkin)
             {
             {
@@ -819,39 +828,39 @@ Mesh* FBXSceneEncoder::loadMesh(KFbxMesh* fbxMesh)
     // It should be the same order as how the Vertex data is written.
     // It should be the same order as how the Vertex data is written.
 
 
     // Position
     // Position
-    mesh->addVetexAttribute(POSITION, 3);
+    mesh->addVetexAttribute(POSITION, Vertex::POSITION_COUNT);
 
 
     const Vertex& vertex = mesh->vertices[0];
     const Vertex& vertex = mesh->vertices[0];
     // Normals
     // Normals
     if (vertex.hasNormal)
     if (vertex.hasNormal)
     {
     {
-        mesh->addVetexAttribute(NORMAL, 3);
+        mesh->addVetexAttribute(NORMAL, Vertex::NORMAL_COUNT);
     }
     }
     // Tangents
     // Tangents
     if (vertex.hasTangent)
     if (vertex.hasTangent)
     {
     {
-        mesh->addVetexAttribute(TANGENT, 3);
+        mesh->addVetexAttribute(TANGENT, Vertex::TANGENT_COUNT);
     }
     }
     // Binormals
     // Binormals
     if (vertex.hasBinormal)
     if (vertex.hasBinormal)
     {
     {
-        mesh->addVetexAttribute(BINORMAL, 3);
+        mesh->addVetexAttribute(BINORMAL, Vertex::BINORMAL_COUNT);
     }
     }
     // Texture Coordinates
     // Texture Coordinates
     if (vertex.hasTexCoord)
     if (vertex.hasTexCoord)
     {
     {
-        mesh->addVetexAttribute(TEXCOORD0, 2);
+        mesh->addVetexAttribute(TEXCOORD0, Vertex::TEXCOORD_COUNT);
     }
     }
     // Diffuse Color
     // Diffuse Color
-    if (vertex.hasColor)
+    if (vertex.hasDiffuse)
     {
     {
-        mesh->addVetexAttribute(COLOR, 3);
+        mesh->addVetexAttribute(COLOR, Vertex::DIFFUSE_COUNT);
     }
     }
     // Skinning BlendWeights BlendIndices
     // Skinning BlendWeights BlendIndices
     if (vertex.hasWeights)
     if (vertex.hasWeights)
     {
     {
-        mesh->addVetexAttribute(BLENDWEIGHTS, 4);
-        mesh->addVetexAttribute(BLENDINDICES, 4);
+        mesh->addVetexAttribute(BLENDWEIGHTS, Vertex::BLEND_WEIGHTS_COUNT);
+        mesh->addVetexAttribute(BLENDINDICES, Vertex::BLEND_INDICES_COUNT);
     }
     }
 
 
     _gamePlayFile.addMesh(mesh);
     _gamePlayFile.addMesh(mesh);
@@ -974,23 +983,23 @@ void loadTextureCoords(KFbxMesh* fbxMesh, int polyIndex, int posInPoly, Vertex*
     if (fbxMesh->GetElementUVCount() > 0)
     if (fbxMesh->GetElementUVCount() > 0)
     {
     {
         // Get only the first UV coordinates.
         // Get only the first UV coordinates.
-        KFbxGeometryElementUV* leUV = fbxMesh->GetElementUV(0);
-        switch (leUV->GetMappingMode())
+        KFbxGeometryElementUV* uv = fbxMesh->GetElementUV(0);
+        switch (uv->GetMappingMode())
         {
         {
         case KFbxGeometryElement::eBY_CONTROL_POINT:
         case KFbxGeometryElement::eBY_CONTROL_POINT:
-            switch (leUV->GetReferenceMode())
+            switch (uv->GetReferenceMode())
             {
             {
             case KFbxGeometryElement::eDIRECT:
             case KFbxGeometryElement::eDIRECT:
                 vertex->hasTexCoord = true;
                 vertex->hasTexCoord = true;
-                vertex->texCoord.x = (float)leUV->GetDirectArray().GetAt(polyIndex)[0];
-                vertex->texCoord.y = (float)leUV->GetDirectArray().GetAt(polyIndex)[1];
+                vertex->texCoord.x = (float)uv->GetDirectArray().GetAt(polyIndex)[0];
+                vertex->texCoord.y = (float)uv->GetDirectArray().GetAt(polyIndex)[1];
                 break;
                 break;
             case KFbxGeometryElement::eINDEX_TO_DIRECT:
             case KFbxGeometryElement::eINDEX_TO_DIRECT:
                 {
                 {
-                    int id = leUV->GetIndexArray().GetAt(polyIndex);
+                    int id = uv->GetIndexArray().GetAt(polyIndex);
                     vertex->hasTexCoord = true;
                     vertex->hasTexCoord = true;
-                    vertex->texCoord.x = (float)leUV->GetDirectArray().GetAt(id)[0];
-                    vertex->texCoord.y = (float)leUV->GetDirectArray().GetAt(id)[1];
+                    vertex->texCoord.x = (float)uv->GetDirectArray().GetAt(id)[0];
+                    vertex->texCoord.y = (float)uv->GetDirectArray().GetAt(id)[1];
                 }
                 }
                 break;
                 break;
             default:
             default:
@@ -1000,13 +1009,13 @@ void loadTextureCoords(KFbxMesh* fbxMesh, int polyIndex, int posInPoly, Vertex*
         case KFbxGeometryElement::eBY_POLYGON_VERTEX:
         case KFbxGeometryElement::eBY_POLYGON_VERTEX:
             {
             {
                 int lTextureUVIndex = fbxMesh->GetTextureUVIndex(polyIndex, posInPoly);
                 int lTextureUVIndex = fbxMesh->GetTextureUVIndex(polyIndex, posInPoly);
-                switch (leUV->GetReferenceMode())
+                switch (uv->GetReferenceMode())
                 {
                 {
                 case KFbxGeometryElement::eDIRECT:
                 case KFbxGeometryElement::eDIRECT:
                 case KFbxGeometryElement::eINDEX_TO_DIRECT:
                 case KFbxGeometryElement::eINDEX_TO_DIRECT:
                     vertex->hasTexCoord = true;
                     vertex->hasTexCoord = true;
-                    vertex->texCoord.x = (float)leUV->GetDirectArray().GetAt(lTextureUVIndex)[0];
-                    vertex->texCoord.y = (float)leUV->GetDirectArray().GetAt(lTextureUVIndex)[1];
+                    vertex->texCoord.x = (float)uv->GetDirectArray().GetAt(lTextureUVIndex)[0];
+                    vertex->texCoord.y = (float)uv->GetDirectArray().GetAt(lTextureUVIndex)[1];
                     break;
                     break;
                 default:
                 default:
                     break;
                     break;
@@ -1024,14 +1033,14 @@ void loadNormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
     if (fbxMesh->GetElementNormalCount() > 0)
     if (fbxMesh->GetElementNormalCount() > 0)
     {
     {
         // Get only the first
         // Get only the first
-        KFbxGeometryElementNormal* leNormal = fbxMesh->GetElementNormal(0);
-        if (leNormal->GetMappingMode() == KFbxGeometryElement::eBY_POLYGON_VERTEX)
+        KFbxGeometryElementNormal* normal = fbxMesh->GetElementNormal(0);
+        if (normal->GetMappingMode() == KFbxGeometryElement::eBY_POLYGON_VERTEX)
         {
         {
-            switch (leNormal->GetReferenceMode())
+            switch (normal->GetReferenceMode())
             {
             {
             case KFbxGeometryElement::eDIRECT:
             case KFbxGeometryElement::eDIRECT:
                 {
                 {
-                    KFbxVector4 vec4 = leNormal->GetDirectArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = normal->GetDirectArray().GetAt(vertexIndex);
                     vertex->hasNormal = true;
                     vertex->hasNormal = true;
                     vertex->normal.x = (float)vec4[0];
                     vertex->normal.x = (float)vec4[0];
                     vertex->normal.y = (float)vec4[1];
                     vertex->normal.y = (float)vec4[1];
@@ -1040,8 +1049,8 @@ void loadNormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
                 break;
                 break;
             case KFbxGeometryElement::eINDEX_TO_DIRECT:
             case KFbxGeometryElement::eINDEX_TO_DIRECT:
                 {
                 {
-                    int id = leNormal->GetIndexArray().GetAt(vertexIndex);
-                    KFbxVector4 vec4 = leNormal->GetDirectArray().GetAt(id);
+                    int id = normal->GetIndexArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = normal->GetDirectArray().GetAt(id);
                     vertex->hasNormal = true;
                     vertex->hasNormal = true;
                     vertex->normal.x = (float)vec4[0];
                     vertex->normal.x = (float)vec4[0];
                     vertex->normal.y = (float)vec4[1];
                     vertex->normal.y = (float)vec4[1];
@@ -1060,14 +1069,14 @@ void loadTangent(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
     if (fbxMesh->GetElementTangentCount() > 0)
     if (fbxMesh->GetElementTangentCount() > 0)
     {
     {
         // Get only the first tangent
         // Get only the first tangent
-        KFbxGeometryElementTangent* leTangent = fbxMesh->GetElementTangent(0);
-        if (leTangent->GetMappingMode() == KFbxGeometryElement::eBY_POLYGON_VERTEX)
+        KFbxGeometryElementTangent* tangent = fbxMesh->GetElementTangent(0);
+        if (tangent->GetMappingMode() == KFbxGeometryElement::eBY_POLYGON_VERTEX)
         {
         {
-            switch (leTangent->GetReferenceMode())
+            switch (tangent->GetReferenceMode())
             {
             {
             case KFbxGeometryElement::eDIRECT:
             case KFbxGeometryElement::eDIRECT:
                 {
                 {
-                    KFbxVector4 vec4 = leTangent->GetDirectArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = tangent->GetDirectArray().GetAt(vertexIndex);
                     vertex->hasTangent = true;
                     vertex->hasTangent = true;
                     vertex->tangent.x = (float)vec4[0];
                     vertex->tangent.x = (float)vec4[0];
                     vertex->tangent.y = (float)vec4[1];
                     vertex->tangent.y = (float)vec4[1];
@@ -1076,8 +1085,8 @@ void loadTangent(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
                 break;
                 break;
             case KFbxGeometryElement::eINDEX_TO_DIRECT:
             case KFbxGeometryElement::eINDEX_TO_DIRECT:
                 {
                 {
-                    int id = leTangent->GetIndexArray().GetAt(vertexIndex);
-                    KFbxVector4 vec4 = leTangent->GetDirectArray().GetAt(id);
+                    int id = tangent->GetIndexArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = tangent->GetDirectArray().GetAt(id);
                     vertex->hasTangent = true;
                     vertex->hasTangent = true;
                     vertex->tangent.x = (float)vec4[0];
                     vertex->tangent.x = (float)vec4[0];
                     vertex->tangent.y = (float)vec4[1];
                     vertex->tangent.y = (float)vec4[1];
@@ -1096,14 +1105,14 @@ void loadBinormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
     if (fbxMesh->GetElementBinormalCount() > 0)
     if (fbxMesh->GetElementBinormalCount() > 0)
     {
     {
         // Get only the first binormal.
         // Get only the first binormal.
-        KFbxGeometryElementBinormal* leBinormal = fbxMesh->GetElementBinormal(0);
-        if (leBinormal->GetMappingMode() == KFbxGeometryElement::eBY_POLYGON_VERTEX)
+        KFbxGeometryElementBinormal* binormal = fbxMesh->GetElementBinormal(0);
+        if (binormal->GetMappingMode() == KFbxGeometryElement::eBY_POLYGON_VERTEX)
         {
         {
-            switch (leBinormal->GetReferenceMode())
+            switch (binormal->GetReferenceMode())
             {
             {
             case KFbxGeometryElement::eDIRECT:
             case KFbxGeometryElement::eDIRECT:
                 {
                 {
-                    KFbxVector4 vec4 = leBinormal->GetDirectArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = binormal->GetDirectArray().GetAt(vertexIndex);
                     vertex->hasBinormal = true;
                     vertex->hasBinormal = true;
                     vertex->binormal.x = (float)vec4[0];
                     vertex->binormal.x = (float)vec4[0];
                     vertex->binormal.y = (float)vec4[1];
                     vertex->binormal.y = (float)vec4[1];
@@ -1112,8 +1121,8 @@ void loadBinormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
                 break;
                 break;
             case KFbxGeometryElement::eINDEX_TO_DIRECT:
             case KFbxGeometryElement::eINDEX_TO_DIRECT:
                 {
                 {
-                    int id = leBinormal->GetIndexArray().GetAt(vertexIndex);
-                    KFbxVector4 vec4 = leBinormal->GetDirectArray().GetAt(id);
+                    int id = binormal->GetIndexArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = binormal->GetDirectArray().GetAt(id);
                     vertex->hasBinormal = true;
                     vertex->hasBinormal = true;
                     vertex->binormal.x = (float)vec4[0];
                     vertex->binormal.x = (float)vec4[0];
                     vertex->binormal.y = (float)vec4[1];
                     vertex->binormal.y = (float)vec4[1];
@@ -1127,6 +1136,46 @@ void loadBinormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
     }
     }
 }
 }
 
 
+void loadVertexColor(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
+{
+    if (fbxMesh->GetElementVertexColorCount() > 0)
+    {
+        // Get only the first vertex color.
+        KFbxGeometryElementVertexColor* vertexColor = fbxMesh->GetElementVertexColor(0);
+        if (vertexColor->GetMappingMode() == KFbxGeometryElement::eBY_POLYGON_VERTEX)
+        {
+            switch (vertexColor->GetReferenceMode())
+            {
+            case KFbxGeometryElement::eDIRECT:
+                {
+                    KFbxColor color = vertexColor->GetDirectArray().GetAt(vertexIndex);
+
+                    vertex->hasDiffuse = true;
+                    vertex->diffuse.x = (float)color.mRed;
+                    vertex->diffuse.y = (float)color.mGreen;
+                    vertex->diffuse.z = (float)color.mBlue;
+                    vertex->diffuse.w = (float)color.mAlpha;
+                }
+                break;
+            case KFbxGeometryElement::eINDEX_TO_DIRECT:
+                {
+                    int id = vertexColor->GetIndexArray().GetAt(vertexIndex);
+                    KFbxColor color = vertexColor->GetDirectArray().GetAt(id);
+
+                    vertex->hasDiffuse = true;
+                    vertex->diffuse.x = (float)color.mRed;
+                    vertex->diffuse.y = (float)color.mGreen;
+                    vertex->diffuse.z = (float)color.mBlue;
+                    vertex->diffuse.w = (float)color.mAlpha;
+                }
+                break;
+            default:
+                break;
+            }
+        }
+    }
+}
+
 void loadBlendData(const std::vector<Vector2>& vertexWeights, Vertex* vertex)
 void loadBlendData(const std::vector<Vector2>& vertexWeights, Vertex* vertex)
 {
 {
     size_t size = vertexWeights.size();
     size_t size = vertexWeights.size();
@@ -1225,6 +1274,7 @@ void appendKeyFrame(KFbxNode* fbxNode, float time, std::vector<float>* keyTimes,
     Quaternion rotation;
     Quaternion rotation;
     Vector3 translation;
     Vector3 translation;
     matrix.decompose(&scale, &rotation, &translation);
     matrix.decompose(&scale, &rotation, &translation);
+    rotation.normalize();
 
 
     keyTimes->push_back(time);
     keyTimes->push_back(time);
     keyValues->push_back(scale.x);
     keyValues->push_back(scale.x);

+ 144 - 0
gameplay-encoder/src/GPBFile.cpp

@@ -1,11 +1,19 @@
 #include "Base.h"
 #include "Base.h"
 #include "GPBFile.h"
 #include "GPBFile.h"
+#include "Transform.h"
+
+#define EPSILON 1.2e-7f;
 
 
 namespace gameplay
 namespace gameplay
 {
 {
 
 
 static GPBFile* __instance = NULL;
 static GPBFile* __instance = NULL;
 
 
+/**
+ * Returns true if the given value is close to one.
+ */
+static bool isAlmostOne(float value);
+
 GPBFile::GPBFile(void)
 GPBFile::GPBFile(void)
     : _file(NULL), _animationsAdded(false)
     : _file(NULL), _animationsAdded(false)
 {
 {
@@ -245,6 +253,14 @@ void GPBFile::adjust()
         }
         }
     }
     }
 
 
+    for (std::list<Node*>::const_iterator i = _nodes.begin(); i != _nodes.end(); ++i)
+    {
+        computeBounds(*i);
+    }
+
+    // try to convert joint transform animations into rotation animations
+    //optimizeTransformAnimations();
+
     // TODO:
     // TODO:
     // remove ambient _lights
     // remove ambient _lights
     // for each node
     // for each node
@@ -259,4 +275,132 @@ void GPBFile::adjust()
     //   This can be merged into one animation. Same for scale animations.
     //   This can be merged into one animation. Same for scale animations.
 }
 }
 
 
+void GPBFile::computeBounds(Node* node)
+{
+    assert(node);
+    if (Model* model = node->getModel())
+    {
+        if (Mesh* mesh = model->getMesh())
+        {
+            mesh->computeBounds();
+        }
+        if (MeshSkin* skin = model->getSkin())
+        {
+            skin->computeBounds();
+        }
+    }
+    for (Node* child = node->getFirstChild(); child != NULL; child = child->getNextSibling())
+    {
+        computeBounds(child);
+    }
+}
+
+void GPBFile::optimizeTransformAnimations()
+{
+    const unsigned int animationCount = _animations.getAnimationCount();
+    for (unsigned int animationIndex = 0; animationIndex < animationCount; ++animationIndex)
+    {
+        Animation* animation = _animations.getAnimation(animationIndex);
+        assert(animation);
+        const int channelCount = animation->getAnimationChannelCount();
+        // loop backwards because we will be adding and removing channels
+        for (int channelIndex = channelCount -1; channelIndex >= 0 ; --channelIndex)
+        {
+            AnimationChannel* channel = animation->getAnimationChannel(channelIndex);
+            assert(channel);
+            // get target node
+            const Object* obj = _refTable.get(channel->getTargetId());
+            if (obj && obj->getTypeId() == Object::NODE_ID)
+            {
+                const Node* node = static_cast<const Node*>(obj);
+                if (node->isJoint() && channel->getTargetAttribute() == Transform::ANIMATE_SCALE_ROTATE_TRANSLATE)
+                {
+                    decomposeTransformAnimationChannel(animation, channel);
+
+                    animation->remove(channel);
+                    SAFE_DELETE(channel);
+                }
+            }
+        }
+    }
+}
+
+
+void GPBFile::decomposeTransformAnimationChannel(Animation* animation, const AnimationChannel* channel)
+{
+    const std::vector<float>& keyTimes = channel->getKeyTimes();
+    const std::vector<float>& keyValues = channel->getKeyValues();
+    const size_t keyTimesSize = keyTimes.size();
+    const size_t keyValuesSize = keyValues.size();
+
+    std::vector<float> scaleKeyValues;
+    std::vector<float> rotateKeyValues;
+    std::vector<float> translateKeyValues;
+                    
+    scaleKeyValues.reserve(keyTimesSize * 3);
+    rotateKeyValues.reserve(keyTimesSize * 4);
+    translateKeyValues.reserve(keyTimesSize * 3);
+
+    for (size_t kv = 0; kv < keyValuesSize; kv += 10)
+    {
+        scaleKeyValues.push_back(keyValues[kv]);
+        scaleKeyValues.push_back(keyValues[kv+1]);
+        scaleKeyValues.push_back(keyValues[kv+2]);
+
+        rotateKeyValues.push_back(keyValues[kv+3]);
+        rotateKeyValues.push_back(keyValues[kv+4]);
+        rotateKeyValues.push_back(keyValues[kv+5]);
+        rotateKeyValues.push_back(keyValues[kv+6]);
+
+        translateKeyValues.push_back(keyValues[kv+7]);
+        translateKeyValues.push_back(keyValues[kv+8]);
+        translateKeyValues.push_back(keyValues[kv+9]);
+    }
+
+    // replace transform animation channel with translate, rotate and scale animation channels
+
+    // Don't add the scale channel if all the key values are close to 1.0
+    size_t oneCount = (size_t)std::count_if(scaleKeyValues.begin(), scaleKeyValues.end(), isAlmostOne);
+    if (scaleKeyValues.size() != oneCount)
+    {
+        AnimationChannel* scaleChannel = new AnimationChannel();
+        scaleChannel->setTargetId(channel->getTargetId());
+        scaleChannel->setKeyTimes(channel->getKeyTimes());
+        scaleChannel->setTangentsIn(channel->getTangentsIn());
+        scaleChannel->setTangentsOut(channel->getTangentsOut());
+        scaleChannel->setInterpolations(channel->getInterpolationTypes());
+        scaleChannel->setTargetAttribute(Transform::ANIMATE_SCALE);
+        scaleChannel->setKeyValues(scaleKeyValues);
+        scaleChannel->removeDuplicates();
+        animation->add(scaleChannel);
+    }
+
+    AnimationChannel* rotateChannel = new AnimationChannel();
+    rotateChannel->setTargetId(channel->getTargetId());
+    rotateChannel->setKeyTimes(channel->getKeyTimes());
+    rotateChannel->setTangentsIn(channel->getTangentsIn());
+    rotateChannel->setTangentsOut(channel->getTangentsOut());
+    rotateChannel->setInterpolations(channel->getInterpolationTypes());
+    rotateChannel->setTargetAttribute(Transform::ANIMATE_ROTATE);
+    rotateChannel->setKeyValues(rotateKeyValues);
+    rotateChannel->removeDuplicates();
+    animation->add(rotateChannel);
+
+    AnimationChannel* translateChannel = new AnimationChannel();
+    translateChannel->setTargetId(channel->getTargetId());
+    translateChannel->setKeyTimes(channel->getKeyTimes());
+    translateChannel->setTangentsIn(channel->getTangentsIn());
+    translateChannel->setTangentsOut(channel->getTangentsOut());
+    translateChannel->setInterpolations(channel->getInterpolationTypes());
+    translateChannel->setTargetAttribute(Transform::ANIMATE_TRANSLATE);
+    translateChannel->setKeyValues(translateKeyValues);
+    translateChannel->removeDuplicates();
+    animation->add(translateChannel);
+}
+
+static bool isAlmostOne(float value)
+{
+    return std::abs(value - 1.0f) < EPSILON;
+}
+
 }
 }

+ 15 - 0
gameplay-encoder/src/GPBFile.h

@@ -98,6 +98,21 @@ public:
      */
      */
     void adjust();
     void adjust();
 
 
+private:
+    /**
+     * Computes the bounds of all meshes in the node hierarchy.
+     */
+    void computeBounds(Node* node);
+    void optimizeTransformAnimations();
+
+    /**
+     * Decomposes an ANIMATE_SCALE_ROTATE_TRANSLATE channel into 3 new channels. (Scale, Rotate and Translate)
+     * 
+     * @param animation The animation that the channel belongs to.
+     * @param channel The animation channel to decompose.
+     */
+    void decomposeTransformAnimationChannel(Animation* animation, const AnimationChannel* channel);
+
 private:
 private:
 
 
     FILE* _file;
     FILE* _file;

+ 0 - 2
gameplay-encoder/src/Mesh.cpp

@@ -273,7 +273,6 @@ void Mesh::writeBinaryVertices(FILE* file)
     }
     }
 
 
     // Write bounds
     // Write bounds
-    computeBounds();
     write(&bounds.min.x, 3, file);
     write(&bounds.min.x, 3, file);
     write(&bounds.max.x, 3, file);
     write(&bounds.max.x, 3, file);
     write(&bounds.center.x, 3, file);
     write(&bounds.center.x, 3, file);
@@ -302,7 +301,6 @@ void Mesh::writeText(FILE* file)
     fprintf(file, "</vertices>\n");
     fprintf(file, "</vertices>\n");
 
 
     // write bounds
     // write bounds
-    computeBounds();
     fprintf(file, "<bounds>\n");
     fprintf(file, "<bounds>\n");
     fprintf(file, "<min>\n");
     fprintf(file, "<min>\n");
     writeVectorText(bounds.min, file);
     writeVectorText(bounds.min, file);

+ 2 - 4
gameplay-encoder/src/Mesh.h

@@ -65,16 +65,14 @@ public:
      */
      */
     void generateHeightmap(const char* filename);
     void generateHeightmap(const char* filename);
 
 
+    void computeBounds();
+
     Model* model;
     Model* model;
     std::vector<Vertex> vertices;
     std::vector<Vertex> vertices;
     std::vector<MeshPart*> parts;
     std::vector<MeshPart*> parts;
     BoundingVolume bounds;
     BoundingVolume bounds;
     std::map<Vertex, unsigned int> vertexLookupTable;
     std::map<Vertex, unsigned int> vertexLookupTable;
 
 
-private:
-
-    void computeBounds();
-
 private:
 private:
     std::vector<VertexElement> _vertexFormat;
     std::vector<VertexElement> _vertexFormat;
 
 

+ 2 - 2
gameplay-encoder/src/Node.cpp

@@ -296,7 +296,7 @@ void Node::setIsJoint(bool value)
     _joint = value;
     _joint = value;
 }
 }
 
 
-bool Node::isJoint()
+bool Node::isJoint() const
 {
 {
     return _joint;
     return _joint;
 }
 }
@@ -324,7 +324,7 @@ Node* Node::getFirstCameraNode() const
 {
 {
     if (hasCamera())
     if (hasCamera())
     {
     {
-        return (Node*)this;
+        return const_cast<Node*>(this);
     }
     }
     for (Node* node = getFirstChild(); node != NULL; node = node->getNextSibling())
     for (Node* node = getFirstChild(); node != NULL; node = node->getNextSibling())
     {
     {

+ 1 - 1
gameplay-encoder/src/Node.h

@@ -155,7 +155,7 @@ public:
     /**
     /**
      * Returns true if this is a joint node.
      * Returns true if this is a joint node.
      */
      */
-    bool isJoint();
+    bool isJoint() const;
 
 
     Node* getFirstCameraNode() const;
     Node* getFirstCameraNode() const;
 
 

+ 89 - 0
gameplay-encoder/src/Transform.cpp

@@ -1,2 +1,91 @@
 #include "Base.h"
 #include "Base.h"
 #include "Transform.h"
 #include "Transform.h"
+
+namespace gameplay
+{
+
+const char* Transform::getPropertyString(unsigned int prop)
+{
+    switch (prop)
+    {
+        case ANIMATE_SCALE:
+            return "ANIMATE_SCALE";
+        case ANIMATE_SCALE_X:
+            return "ANIMATE_SCALE_X";
+        case ANIMATE_SCALE_Y: 
+            return "ANIMATE_SCALE_Y";
+        case ANIMATE_SCALE_Z:
+            return "ANIMATE_SCALE_Z";
+        case ANIMATE_SCALE_XY: 
+            return "ANIMATE_SCALE_XY";
+        case ANIMATE_SCALE_XZ: 
+            return "ANIMATE_SCALE_XZ";
+        case ANIMATE_SCALE_YZ:
+            return "ANIMATE_SCALE_YZ";
+        case ANIMATE_ROTATE:
+            return "ANIMATE_ROTATE";
+        case ANIMATE_TRANSLATE: 
+            return "ANIMATE_TRANSLATE";
+        case ANIMATE_TRANSLATE_X:
+            return "ANIMATE_TRANSLATE_X";
+        case ANIMATE_TRANSLATE_Y: 
+            return "ANIMATE_TRANSLATE_Y";
+        case ANIMATE_TRANSLATE_Z: 
+            return "ANIMATE_TRANSLATE_Z";
+        case ANIMATE_TRANSLATE_XY: 
+            return "ANIMATE_TRANSLATE_XY";
+        case ANIMATE_TRANSLATE_XZ: 
+            return "ANIMATE_TRANSLATE_XZ";
+        case ANIMATE_TRANSLATE_YZ: 
+            return "ANIMATE_TRANSLATE_YZ";
+        case ANIMATE_ROTATE_TRANSLATE: 
+            return "ANIMATE_ROTATE_TRANSLATE";
+        case ANIMATE_SCALE_ROTATE_TRANSLATE: 
+            return "ANIMATE_SCALE_ROTATE_TRANSLATE";
+        case ANIMATE_ROTATE_X: 
+            return "ANIMATE_ROTATE_X";
+        case ANIMATE_ROTATE_Y: 
+            return "ANIMATE_ROTATE_Y";
+        case ANIMATE_ROTATE_Z: 
+            return "ANIMATE_ROTATE_Z";
+        default:
+            return "";
+    }
+}
+
+unsigned int Transform::getPropertySize(unsigned int prop)
+{
+    switch (prop)
+    {
+        case ANIMATE_SCALE_ROTATE_TRANSLATE: 
+            return 10;
+        case ANIMATE_ROTATE_TRANSLATE: 
+            return 7;
+        case ANIMATE_ROTATE:
+            return 4;
+        case ANIMATE_SCALE:
+        case ANIMATE_TRANSLATE: 
+            return 3;   
+        case ANIMATE_SCALE_XY: 
+        case ANIMATE_SCALE_XZ: 
+        case ANIMATE_SCALE_YZ:
+        case ANIMATE_TRANSLATE_XY: 
+        case ANIMATE_TRANSLATE_XZ: 
+        case ANIMATE_TRANSLATE_YZ: 
+            return 2;
+        case ANIMATE_SCALE_X:
+        case ANIMATE_SCALE_Y:
+        case ANIMATE_SCALE_Z:
+        case ANIMATE_TRANSLATE_X:
+        case ANIMATE_TRANSLATE_Y:
+        case ANIMATE_TRANSLATE_Z:
+        case ANIMATE_ROTATE_X: 
+        case ANIMATE_ROTATE_Y: 
+        case ANIMATE_ROTATE_Z: 
+            return 1;
+        default:
+            return 0;
+    }
+}
+
+}

+ 11 - 0
gameplay-encoder/src/Transform.h

@@ -50,6 +50,17 @@ public:
         ANIMATE_ROTATE_Y = 19,
         ANIMATE_ROTATE_Y = 19,
         ANIMATE_ROTATE_Z = 20
         ANIMATE_ROTATE_Z = 20
     };
     };
+
+    /**
+     * Returns the string representation of the given TransformProperty.
+     */
+    static const char* getPropertyString(unsigned int prop);
+
+    /**
+     * Returns the number of floats for the given property or zero if not a valid property.
+     */
+    static unsigned int getPropertySize(unsigned int prop);
+
 };
 };
 
 
 }
 }

+ 18 - 12
gameplay-encoder/src/Vertex.cpp

@@ -5,7 +5,7 @@ namespace gameplay
 {
 {
 
 
 Vertex::Vertex(void)
 Vertex::Vertex(void)
-    : hasNormal(false), hasTangent(false), hasBinormal(false), hasTexCoord(false), hasColor(false), hasWeights(false)
+    : hasNormal(false), hasTangent(false), hasBinormal(false), hasTexCoord(false), hasDiffuse(false), hasWeights(false)
 {
 {
 }
 }
 
 
@@ -15,17 +15,19 @@ Vertex::~Vertex(void)
 
 
 unsigned int Vertex::byteSize() const
 unsigned int Vertex::byteSize() const
 {
 {
-    unsigned int count = 3;
+    unsigned int count = POSITION_COUNT;
     if (hasNormal)
     if (hasNormal)
-        count += 3;
+        count += NORMAL_COUNT;
     if (hasTangent)
     if (hasTangent)
-        count += 3;
+        count += TANGENT_COUNT;
     if (hasBinormal)
     if (hasBinormal)
-        count += 3;
+        count += BINORMAL_COUNT;
     if (hasTexCoord)
     if (hasTexCoord)
-        count += 2;
+        count += TEXCOORD_COUNT;
     if (hasWeights)
     if (hasWeights)
-        count += 8;
+        count += BLEND_WEIGHTS_COUNT + BLEND_INDICES_COUNT;
+    if (hasDiffuse)
+        count += DIFFUSE_COUNT;
     return count * sizeof(float);
     return count * sizeof(float);
 }
 }
 
 
@@ -48,11 +50,10 @@ void Vertex::writeBinary(FILE* file) const
     {
     {
         writeVectorBinary(texCoord, file);
         writeVectorBinary(texCoord, file);
     }
     }
-    // TODO add vertex color?
-    //if (hasColor)
-    //{
-    //    writeVectorBinary(color, file);
-    //}
+    if (hasDiffuse)
+    {
+        writeVectorBinary(diffuse, file);
+    }
     if (hasWeights)
     if (hasWeights)
     {
     {
         writeVectorBinary(blendWeights, file);
         writeVectorBinary(blendWeights, file);
@@ -84,6 +85,11 @@ void Vertex::writeText(FILE* file) const
         write("// texCoord\n", file);
         write("// texCoord\n", file);
         writeVectorText(texCoord, file);
         writeVectorText(texCoord, file);
     }
     }
+    if (hasDiffuse)
+    {
+        write("// diffuse\n", file);
+        writeVectorText(diffuse, file);
+    }
     if (hasWeights)
     if (hasWeights)
     {
     {
         write("// blendWeights\n", file);
         write("// blendWeights\n", file);

+ 21 - 7
gameplay-encoder/src/Vertex.h

@@ -13,6 +13,15 @@ class Vertex
 {
 {
 public:
 public:
 
 
+    static const unsigned int POSITION_COUNT = 3;
+    static const unsigned int NORMAL_COUNT = 3;
+    static const unsigned int TANGENT_COUNT = 3;
+    static const unsigned int BINORMAL_COUNT = 3;
+    static const unsigned int TEXCOORD_COUNT = 2;
+    static const unsigned int DIFFUSE_COUNT = 4;
+    static const unsigned int BLEND_WEIGHTS_COUNT = 4;
+    static const unsigned int BLEND_INDICES_COUNT = 4;
+
     /**
     /**
      * Constructor.
      * Constructor.
      */
      */
@@ -28,11 +37,12 @@ public:
     Vector3 tangent;
     Vector3 tangent;
     Vector3 binormal;
     Vector3 binormal;
     Vector2 texCoord;
     Vector2 texCoord;
+    Vector4 diffuse;
 
 
     Vector4 blendWeights;
     Vector4 blendWeights;
     Vector4 blendIndices;
     Vector4 blendIndices;
 
 
-    bool hasNormal, hasTangent, hasBinormal, hasTexCoord, hasColor, hasWeights;
+    bool hasNormal, hasTangent, hasBinormal, hasTexCoord, hasDiffuse, hasWeights;
 
 
     inline bool operator<(const Vertex& v) const
     inline bool operator<(const Vertex& v) const
     {
     {
@@ -46,15 +56,19 @@ public:
                     {
                     {
                         if (texCoord == v.texCoord)
                         if (texCoord == v.texCoord)
                         {
                         {
-                            if (blendWeights == v.blendWeights)
+                            if (diffuse == v.diffuse)
                             {
                             {
-                                if (blendIndices == v.blendIndices)
+                                if (blendWeights == v.blendWeights)
                                 {
                                 {
-                                    return false;
+                                    if (blendIndices == v.blendIndices)
+                                    {
+                                        return false;
+                                    }
+                                    return blendIndices < v.blendIndices;
                                 }
                                 }
-                                return blendIndices < v.blendIndices;
+                                return blendWeights < v.blendWeights;
                             }
                             }
-                            return blendWeights < v.blendWeights;
+                            return diffuse < v.diffuse;
                         }
                         }
                         return texCoord < v.texCoord;
                         return texCoord < v.texCoord;
                     }
                     }
@@ -70,7 +84,7 @@ public:
     inline bool operator==(const Vertex& v) const
     inline bool operator==(const Vertex& v) const
     {
     {
         return position==v.position && normal==v.normal && tangent==v.tangent && binormal==v.binormal && texCoord==v.texCoord &&
         return position==v.position && normal==v.normal && tangent==v.tangent && binormal==v.binormal && texCoord==v.texCoord &&
-            blendWeights==v.blendWeights && blendIndices==v.blendIndices;
+            diffuse==v.diffuse && blendWeights==v.blendWeights && blendIndices==v.blendIndices;
     }
     }
 
 
     /**
     /**

+ 245 - 0
gameplay-newproject.sh

@@ -0,0 +1,245 @@
+#/bin/bash
+# ********************************************************************
+#
+# generate-project.sh
+#
+# This script generates a set of gameplay project files.
+# The new project will be based of the gameplay-template project and 
+# it will be generated with the name and location that is specified
+# as input parameters.
+#
+# IMPORTANT: This script must be run from the root of the gameplay
+# source tree.
+#
+# ********************************************************************
+
+echo
+echo "1. Enter a name for the new project."
+echo
+echo "   This name will be given to the project"
+echo "   executable and a folder with this name"
+echo "   will be created to store all project files."
+echo
+read -p "Project Name: " "" projName 
+if [[ "$projName" == "" ]]; then
+	echo
+	echo "ERROR: No project name specified."
+	echo
+	exit -1;
+fi
+echo 
+
+echo
+echo "2. Enter a game title."
+echo
+echo "   On some platforms, this title is used to"
+echo "   identify the game during installation and"
+echo "   on shortcuts/icons."
+echo
+read -p "Title: " "" title 
+if [[ "$title" == "" ]]; then
+	echo
+	echo "ERROR: No game title specified."
+	echo
+	exit -1;
+fi
+echo 
+
+echo
+echo "3. Enter a short game description."
+echo
+read -p "Description: " "" desc
+if [[ "$desc" == "" ]]; then
+	desc=$title
+fi
+echo 
+
+echo
+echo "4. Enter a unique identifier for your project."
+echo
+echo "   This should be a human readable package name,"
+echo "   containing at least two words separated by a"
+echo "   period (eg. com.surname.gamename)."
+echo
+read -p "Unique ID: " "" uuid
+if [[ "$uuid" == "" ]]; then
+	echo
+	echo "ERROR: No uuid specified."
+	echo
+	exit -1;
+fi
+echo 
+
+echo
+echo "5. Enter author name."
+echo
+echo "   On BlackBerry targets, this is used for"
+echo "   signing and must match the developer name"
+echo "   of your development certificate."
+echo
+read -p "Author: " "" author
+if [[ "$author" == "" ]]; then
+	echo
+	echo "ERROR: No author specified."
+	echo
+	exit -1;
+fi
+echo 
+
+echo
+echo "6. Enter your game's main class name."
+echo
+echo "   Your initial game header and source file"
+echo "   will be given this name and a class with"
+echo "   this name will be created in these files."
+echo
+read -p "Class name: " "" className
+if [[ "$className" == "" ]]; then
+	echo
+	echo "ERROR: No class name specified."
+	echo
+	exit -1;
+fi
+echo 
+
+echo
+echo "7. Enter the project path."
+echo
+echo "   This can be a relative path, absolute path,"
+echo "   or empty for the current folder. Note that"
+echo "   a project folder named $projName will also"
+echo "   be created inside this folder."
+echo
+read -p "Path: " "" location
+if [[ "$location" == "" ]]; then
+	projPath=$projName
+else
+	projPath="$location/$projName"
+fi
+echo
+
+
+# Verify Path and eliminate double '//'
+projPath=`echo "$projPath" | sed 's_//_/_g'`
+if [ -e $projPath ]; then
+	echo
+	echo "ERROR: Path '$projPath' already exists, aborting."
+	echo
+	exit -2
+fi
+
+# Generate relative path from project folder to gameplay folder
+gpPathAbs=`pwd`
+common_path=$projPath
+back=
+while [ "${gpPathAbs#$common_path}" = "${gpPathAbs}" ]; do
+	common_path=$(dirname $common_path)
+	back="../${back}"
+done
+gpPath=${back}${gpPathAbs#$common_path/}
+
+# Make required source folder directories
+mkdir -p "$projPath/src"
+mkdir -p "$projPath/res"
+
+# Below does copy, then uses 'sed' with -i for inplace editing
+# Alternative below uses sed to do a input then output skipping the copy
+# sed "s/TEMPLATE_PROJECT/$projectName/g" "gameplay-template/gameplay-template.vcxproj" > "$projPath/$projName.vcxproj"
+
+#############################################
+# Copy Microsoft Virtual Studio project files
+cp "gameplay-template/gameplay-template.vcxproj" "$projPath/$projName.vcxproj"
+sed -i "" "s*TEMPLATE_PROJECT*$projectName*g" "$projPath/$projName.vcxproj"
+sed -i "" "s*TemplateGame*$className*g" "$projPath/$projName.vcxproj"
+sed -i "" "s*GAMEPLAY_PATH*$gpPath*g" "$projPath/$projName.vcxproj"
+
+cp "gameplay-template/gameplay-template.vcxproj.filters" "$projPath/$projName.vcxproj.filters"
+sed -i "" "s*TemplateGame*$className*g" "$projPath/$projName.vcxproj.filters"
+
+cp "gameplay-template/gameplay-template.vcxproj.user" "$projPath/$projName.vcxproj.user"
+sed -i "" "s*GAMEPLAY_PATH*$gpPath*g" "$projPath/$projName.vcxproj.user"
+
+
+#############################################
+# Copy Apple XCode project files
+mkdir -p "$projPath/$projName.xcodeproj"
+cp "gameplay-template/gameplay-template.xcodeproj/project.pbxproj" "$projPath/$projName.xcodeproj/project.pbxproj"
+sed -i "" "s*TEMPLATE_PROJECT*$projName*g" "$projPath/$projName.xcodeproj/project.pbxproj"
+sed -i "" "s*TemplateGame*$className*g" "$projPath/$projName.xcodeproj/project.pbxproj"
+sed -i "" "s*GAMEPLAY_PATH*$gpPath*g" "$projPath/$projName.xcodeproj/project.pbxproj"
+
+cp "gameplay-template/TEMPLATE_PROJECT-macos.plist" "$projPath/$projName-macos.plist"
+sed -i "" "s*TEMPLATE_UUID*$uuid*g" "$projPath/$projName-macos.plist"
+sed -i "" "s*TEMPLATE_AUTHOR*$author*g" "$projPath/$projName-macos.plist"
+
+cp "gameplay-template/TEMPLATE_PROJECT-ios.plist" "$projPath/$projName-ios.plist"
+sed -i "" "s*TEMPLATE_UUID*$uuid*g" "$projPath/$projName-ios.plist"
+sed -i "" "s*TEMPLATE_AUTHOR*$author*g" "$projPath/$projName-ios.plist"
+
+#############################################
+# Copy BlackBerry NDK project files
+cp "gameplay-template/template.cproject" "$projPath/.cproject"
+sed -i "" "s*TEMPLATE_PROJECT*$projName*g" "$projPath/.cproject"
+sed -i "" "s*TEMPLATE_UUID*$uuid*g" "$projPath/.cproject"
+sed -i "" "s*GAMEPLAY_PATH*$gpPath*g" "$projPath/.cproject"
+
+cp "gameplay-template/template.project" "$projPath/.project"
+sed -i "" "s*TEMPLATE_PROJECT*$projName*g" "$projPath/.project"
+
+cp "gameplay-template/template.bar-descriptor.xml" "$projPath/bar-descriptor.xml"
+sed -i "" "s*TEMPLATE_PROJECT*$projName*g" "$projPath/bar-descriptor.xml"
+sed -i "" "s*TEMPLATE_TITLE*$title*g" "$projPath/bar-descriptor.xml"
+sed -i "" "s*TEMPLATE_UUID*$uuid*g" "$projPath/bar-descriptor.xml"
+sed -i "" "s*TEMPLATE_AUTHOR*$author*g" "$projPath/bar-descriptor.xml"
+sed -i "" "s*TEMPLATE_DESCRIPTION*$desc*g" "$projPath/bar-descriptor.xml"
+
+#############################################
+# Copy Android NDK project files
+mkdir -p "$projPath/android"
+mkdir -p "$projPath/android/jni"
+mkdir -p "$projPath/android/res/values"
+
+cp "gameplay-template/android/template.AndroidManifest.xml" "$projPath/android/AndroidManifest.xml"
+sed -i "" "s*TEMPLATE_PROJECT*$projName*g" "$projPath/android/AndroidManifest.xml"
+sed -i "" "s*TEMPLATE_UUID*$uuid*g" "$projPath/android/AndroidManifest.xml"
+
+cp "gameplay-template/android/template.build.xml" "$projPath/android/build.xml"
+sed -i "" "s*TEMPLATE_PROJECT*$projName*g" "$projPath/android/build.xml"
+
+# Does not exist
+#cp "gameplay-template/android/template.project" "$projPath/android/.project"
+#sed -i "" "s*TEMPLATE_PROJECT*$projName*g" "$projPath/android/.project"
+
+#cp "gameplay-template/android/template.classpath" "$projPath/android/.classpath"
+
+cp "gameplay-template/android/jni/Application.mk" "$projPath/android/jni/Application.mk"
+
+cp "gameplay-template/android/jni/template.Android.mk" "$projPath/android/jni/Android.mk"
+sed -i "" "s*TEMPLATE_PROJECT*$projName*g" "$projPath/android/jni/Android.mk"
+sed -i "" "s*TemplateGame*$className*g" "$projPath/android/jni/Android.mk"
+
+#cp "gameplay-template/android/jni/main.cpp" "$projPath/android/jni/main.cpp"
+
+cp "gameplay-template/android/res/values/template.strings.xml" "$projPath/android/res/values/strings.xml"
+sed -i "" "s*TEMPLATE_TITLE*$title*g" "$projPath/android/res/values/strings.xml"
+
+
+#############################################
+# Copy source files
+#############################################
+cp "gameplay-template/src/TemplateGame.h" "$projPath/src/$className.h"
+cp "gameplay-template/src/TemplateGame.cpp" "$projPath/src/$className.cpp"
+sed -i "" "s*TemplateGame*$className*g" "$projPath/src/$className.h"
+sed -i "" "s*TemplateGame*$className*g" "$projPath/src/$className.cpp"
+
+# Copy resource files
+cp "gameplay-template/res/"* "$projPath/res/"
+#cp "gameplay-template/res/shaders/colored."* "$projPath/res/"
+
+# Copy icon
+cp "gameplay-template/icon.png" "$projPath/icon.png"
+
+# Open the new project folder
+open $projPath
+
+exit 0

+ 1 - 3
gameplay/.cproject

@@ -9,8 +9,6 @@
 				<extensions>
 				<extensions>
 					<extension id="com.qnx.tools.ide.qde.core.QDEBynaryParser" point="org.eclipse.cdt.core.BinaryParser"/>
 					<extension id="com.qnx.tools.ide.qde.core.QDEBynaryParser" point="org.eclipse.cdt.core.BinaryParser"/>
 					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
 					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
-					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
-					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
 				</extensions>
 				</extensions>
 			</storageModule>
 			</storageModule>
 			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
 			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
@@ -19,7 +17,7 @@
 						<toolChain id="com.qnx.qcc.toolChain.staticLib.debug.1686166742" name="QNX QCC" superClass="com.qnx.qcc.toolChain">
 						<toolChain id="com.qnx.qcc.toolChain.staticLib.debug.1686166742" name="QNX QCC" superClass="com.qnx.qcc.toolChain">
 							<option id="com.qnx.qcc.option.cpu.545743487" name="Target CPU:" superClass="com.qnx.qcc.option.cpu" value="com.qnx.qcc.option.gen.cpu.armle-v7" valueType="enumerated"/>
 							<option id="com.qnx.qcc.option.cpu.545743487" name="Target CPU:" superClass="com.qnx.qcc.option.cpu" value="com.qnx.qcc.option.gen.cpu.armle-v7" valueType="enumerated"/>
 							<targetPlatform archList="all" binaryParser="com.qnx.tools.ide.qde.core.QDEBynaryParser" id="com.qnx.qcc.targetPlatform.158841187" osList="all" superClass="com.qnx.qcc.targetPlatform"/>
 							<targetPlatform archList="all" binaryParser="com.qnx.tools.ide.qde.core.QDEBynaryParser" id="com.qnx.qcc.targetPlatform.158841187" osList="all" superClass="com.qnx.qcc.targetPlatform"/>
-							<builder buildPath="${workspace_loc:/gameplay/Device-Debug}" id="cdt.managedbuild.target.gnu.builder.base.2098111998" keepEnvironmentInBuildfile="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base"/>
+							<builder buildPath="${workspace_loc:/gameplay/Device-Debug}" id="org.eclipse.cdt.build.core.internal.builder.159190287" superClass="org.eclipse.cdt.build.core.internal.builder"/>
 							<tool id="com.qnx.qcc.tool.compiler.96907942" name="QCC Compiler" superClass="com.qnx.qcc.tool.compiler">
 							<tool id="com.qnx.qcc.tool.compiler.96907942" name="QCC Compiler" superClass="com.qnx.qcc.tool.compiler">
 								<option id="com.qnx.qcc.option.compile.debug.1765481355" name="Debug (-g)" superClass="com.qnx.qcc.option.compile.debug" value="true" valueType="boolean"/>
 								<option id="com.qnx.qcc.option.compile.debug.1765481355" name="Debug (-g)" superClass="com.qnx.qcc.option.compile.debug" value="true" valueType="boolean"/>
 								<option id="com.qnx.qcc.option.compiler.security.311918799" name="Enhanced Security (-fstack-protector-all)" superClass="com.qnx.qcc.option.compiler.security" value="true" valueType="boolean"/>
 								<option id="com.qnx.qcc.option.compiler.security.311918799" name="Enhanced Security (-fstack-protector-all)" superClass="com.qnx.qcc.option.compiler.security" value="true" valueType="boolean"/>

+ 0 - 12
gameplay/.project

@@ -17,10 +17,6 @@
 					<key>org.eclipse.cdt.make.core.append_environment</key>
 					<key>org.eclipse.cdt.make.core.append_environment</key>
 					<value>true</value>
 					<value>true</value>
 				</dictionary>
 				</dictionary>
-				<dictionary>
-					<key>org.eclipse.cdt.make.core.autoBuildTarget</key>
-					<value>all</value>
-				</dictionary>
 				<dictionary>
 				<dictionary>
 					<key>org.eclipse.cdt.make.core.buildArguments</key>
 					<key>org.eclipse.cdt.make.core.buildArguments</key>
 					<value></value>
 					<value></value>
@@ -33,10 +29,6 @@
 					<key>org.eclipse.cdt.make.core.buildLocation</key>
 					<key>org.eclipse.cdt.make.core.buildLocation</key>
 					<value>${workspace_loc:/gameplay/Device-Debug}</value>
 					<value>${workspace_loc:/gameplay/Device-Debug}</value>
 				</dictionary>
 				</dictionary>
-				<dictionary>
-					<key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
-					<value>clean</value>
-				</dictionary>
 				<dictionary>
 				<dictionary>
 					<key>org.eclipse.cdt.make.core.contents</key>
 					<key>org.eclipse.cdt.make.core.contents</key>
 					<value>org.eclipse.cdt.make.core.activeConfigSettings</value>
 					<value>org.eclipse.cdt.make.core.activeConfigSettings</value>
@@ -53,10 +45,6 @@
 					<key>org.eclipse.cdt.make.core.enableFullBuild</key>
 					<key>org.eclipse.cdt.make.core.enableFullBuild</key>
 					<value>true</value>
 					<value>true</value>
 				</dictionary>
 				</dictionary>
-				<dictionary>
-					<key>org.eclipse.cdt.make.core.fullBuildTarget</key>
-					<value>all</value>
-				</dictionary>
 				<dictionary>
 				<dictionary>
 					<key>org.eclipse.cdt.make.core.stopOnError</key>
 					<key>org.eclipse.cdt.make.core.stopOnError</key>
 					<value>true</value>
 					<value>true</value>

+ 4 - 2
gameplay/src/Animation.cpp

@@ -31,7 +31,8 @@ Animation::~Animation()
 {
 {
     if (_defaultClip)
     if (_defaultClip)
     {
     {
-        _defaultClip->stop();
+        if (_defaultClip->isClipStateBitSet(AnimationClip::CLIP_IS_PLAYING_BIT))
+            _controller->unschedule(_defaultClip);
         SAFE_RELEASE(_defaultClip);
         SAFE_RELEASE(_defaultClip);
     }
     }
 
 
@@ -42,7 +43,8 @@ Animation::~Animation()
         while (clipIter != _clips->end())
         while (clipIter != _clips->end())
         {   
         {   
             AnimationClip* clip = *clipIter;
             AnimationClip* clip = *clipIter;
-            clip->stop();
+            if (clip->isClipStateBitSet(AnimationClip::CLIP_IS_PLAYING_BIT))
+                _controller->unschedule(clip);
             SAFE_RELEASE(clip);
             SAFE_RELEASE(clip);
             clipIter++;
             clipIter++;
         }
         }

+ 183 - 88
gameplay/src/AnimationClip.cpp

@@ -9,10 +9,10 @@ namespace gameplay
 {
 {
 
 
 AnimationClip::AnimationClip(const char* id, Animation* animation, unsigned long startTime, unsigned long endTime)
 AnimationClip::AnimationClip(const char* id, Animation* animation, unsigned long startTime, unsigned long endTime)
-    : _id(id), _animation(animation), _startTime(startTime), _endTime(endTime), _duration(_endTime - _startTime), _repeatCount(1.0f), 
-      _activeDuration(_duration * _repeatCount), _speed(1.0f), _isPlaying(false), _timeStarted(0), _elapsedTime(0), 
-      _crossFadeToClip(NULL), _crossFadeOutElapsed(0), _crossFadeOutDuration(0), _blendWeight(1.0f), _isFadingOutStarted(false), 
-      _isFadingOut(false), _isFadingIn(false), _beginListeners(NULL), _endListeners(NULL), _listeners(NULL)
+    : _id(id), _animation(animation), _startTime(startTime), _endTime(endTime), _duration(_endTime - _startTime), 
+      _stateBits(0x00), _repeatCount(1.0f), _activeDuration(_duration * _repeatCount), _speed(1.0f), _timeStarted(0), 
+      _elapsedTime(0), _crossFadeToClip(NULL), _crossFadeOutElapsed(0), _crossFadeOutDuration(0), _blendWeight(1.0f), 
+      _beginListeners(NULL), _endListeners(NULL), _listeners(NULL), _listenerItr(NULL)
 {
 {
     assert(0 <= startTime && startTime <= animation->_duration && 0 <= endTime && endTime <= animation->_duration);
     assert(0 <= startTime && startTime <= animation->_duration && 0 <= endTime && endTime <= animation->_duration);
     
     
@@ -36,7 +36,29 @@ AnimationClip::~AnimationClip()
     SAFE_RELEASE(_crossFadeToClip);
     SAFE_RELEASE(_crossFadeToClip);
     SAFE_DELETE(_beginListeners);
     SAFE_DELETE(_beginListeners);
     SAFE_DELETE(_endListeners);
     SAFE_DELETE(_endListeners);
-    SAFE_DELETE(_listeners);
+
+    if (_listeners)
+    {
+        *_listenerItr = _listeners->begin();
+        while (*_listenerItr != _listeners->end())
+        {
+            ListenerEvent* lEvt = **_listenerItr;
+            SAFE_DELETE(lEvt);
+            ++*_listenerItr;
+        }
+        SAFE_DELETE(_listeners);
+    }
+    SAFE_DELETE(_listenerItr);
+}
+
+AnimationClip::ListenerEvent::ListenerEvent(Listener* listener, unsigned long eventTime)
+{
+    _listener = listener;
+    _eventTime = eventTime;
+}
+
+AnimationClip::ListenerEvent::~ListenerEvent()
+{
 }
 }
 
 
 const char* AnimationClip::getID() const
 const char* AnimationClip::getID() const
@@ -107,6 +129,11 @@ unsigned long AnimationClip::getActiveDuration() const
     return _activeDuration;
     return _activeDuration;
 }
 }
 
 
+unsigned long AnimationClip::getDuration() const
+{
+    return _duration;
+}
+
 void AnimationClip::setSpeed(float speed)
 void AnimationClip::setSpeed(float speed)
 {
 {
     _speed = speed;
     _speed = speed;
@@ -129,22 +156,39 @@ float AnimationClip::getBlendWeight() const
 
 
 bool AnimationClip::isPlaying() const
 bool AnimationClip::isPlaying() const
 {
 {
-    return _isPlaying;
+    return isClipStateBitSet(CLIP_IS_PLAYING_BIT);
 }
 }
 
 
 void AnimationClip::play()
 void AnimationClip::play()
 {
 {
-    _animation->_controller->schedule(this);
+    if (isClipStateBitSet(CLIP_IS_PLAYING_BIT))
+    {
+        // If the clip is set to be removed, reset the flag.
+        if (isClipStateBitSet(CLIP_IS_MARKED_FOR_REMOVAL_BIT))
+            resetClipStateBit(CLIP_IS_MARKED_FOR_REMOVAL_BIT);
+
+        // Set the state bit to restart.
+        setClipStateBit(CLIP_IS_RESTARTED_BIT);
+    }
+    else
+    {
+        setClipStateBit(CLIP_IS_PLAYING_BIT);
+        _animation->_controller->schedule(this);
+    }
+    
     _timeStarted = Game::getGameTime();
     _timeStarted = Game::getGameTime();
 }
 }
 
 
 void AnimationClip::stop()
 void AnimationClip::stop()
 {
 {
-    _animation->_controller->unschedule(this);
-    if (_isPlaying)
+    if (isClipStateBitSet(CLIP_IS_PLAYING_BIT))
     {
     {
-        _isPlaying = false;
-        onEnd();
+        // If the clip was slated to be restarted, reset this flag.
+        if (isClipStateBitSet(CLIP_IS_RESTARTED_BIT))
+            resetClipStateBit(CLIP_IS_RESTARTED_BIT);
+
+        // Mark the clip to removed from the AnimationController.
+        setClipStateBit(CLIP_IS_MARKED_FOR_REMOVAL_BIT);
     }
     }
 }
 }
 
 
@@ -152,27 +196,37 @@ void AnimationClip::crossFade(AnimationClip* clip, unsigned long duration)
 {
 {
     assert(clip);
     assert(clip);
 
 
+    // Check if the given clip is fading into this clip.
+    // We should reset the clip from fading out, and this one from fading in 
+    // in order to start the crossfade back the other way.
+    if (clip->isClipStateBitSet(CLIP_IS_FADING_OUT_BIT) && clip->_crossFadeToClip == this)
+    {
+        clip->resetClipStateBit(CLIP_IS_FADING_OUT_BIT);
+        clip->_crossFadeToClip->resetClipStateBit(CLIP_IS_FADING_IN_BIT);
+        SAFE_RELEASE(clip->_crossFadeToClip);
+    }
+
     // If I already have a clip I'm fading to and it's not the same as the given clip release it.
     // If I already have a clip I'm fading to and it's not the same as the given clip release it.
     // Assign the new clip and increase it's ref count.
     // Assign the new clip and increase it's ref count.
-    // TODO: Do I need to anything else to the crossFade clip here before releasing?
     if (_crossFadeToClip)
     if (_crossFadeToClip)
+    {
         SAFE_RELEASE(_crossFadeToClip);
         SAFE_RELEASE(_crossFadeToClip);
-        
+    }
+
+    // Set and initialize the crossfade clip
     _crossFadeToClip = clip;
     _crossFadeToClip = clip;
     _crossFadeToClip->addRef();
     _crossFadeToClip->addRef();
-        
-    // Set the crossfade clip to fading in, and initialize it's blend weight to zero.
-    _crossFadeToClip->_isFadingIn = true;
+    _crossFadeToClip->setClipStateBit(CLIP_IS_FADING_IN_BIT);
     _crossFadeToClip->_blendWeight = 0.0f;
     _crossFadeToClip->_blendWeight = 0.0f;
     
     
-    // Set this clip to fade out, set the fade duration and reset the fade elapsed time.
-    _isFadingOut = true;
-    _crossFadeOutElapsed = 0;
+    // Set and intiliaze this clip to fade out
+    setClipStateBit(CLIP_IS_FADING_OUT_STARTED_BIT);
+    setClipStateBit(CLIP_IS_FADING_OUT_BIT);
+    _crossFadeOutElapsed = 0L;
     _crossFadeOutDuration = duration;
     _crossFadeOutDuration = duration;
-    _isFadingOutStarted = true;
     
     
     // If this clip is currently not playing, we should start playing it.
     // If this clip is currently not playing, we should start playing it.
-    if (!_isPlaying)
+    if (!isClipStateBitSet(CLIP_IS_PLAYING_BIT))
         play();
         play();
 
 
     // Start playing the cross fade clip.
     // Start playing the cross fade clip.
@@ -182,38 +236,40 @@ void AnimationClip::crossFade(AnimationClip* clip, unsigned long duration)
 void AnimationClip::addListener(AnimationClip::Listener* listener, unsigned long eventTime)
 void AnimationClip::addListener(AnimationClip::Listener* listener, unsigned long eventTime)
 {
 {
     assert(listener);
     assert(listener);
-    assert(eventTime < _duration);
+    assert(eventTime < _activeDuration);
 
 
-    listener->_listenerTime = eventTime;
+    ListenerEvent* listenerEvent = new ListenerEvent(listener, eventTime);
 
 
     if (!_listeners)
     if (!_listeners)
     {
     {
-        _listeners = new ListenerList;
-        _listeners->_list.push_front(listener);
-        if (_isPlaying)
-            _listeners->_listItr = _listeners->_list.begin();
+        _listeners = new std::list<ListenerEvent*>;
+        _listeners->push_front(listenerEvent);
+
+        _listenerItr = new std::list<ListenerEvent*>::iterator;
+        if (isClipStateBitSet(CLIP_IS_PLAYING_BIT))
+            *_listenerItr = _listeners->begin();
     }
     }
     else
     else
     {
     {
-        for (std::list<Listener*>::iterator itr = _listeners->_list.begin(); itr != _listeners->_list.begin(); itr++)
+        for (std::list<ListenerEvent*>::iterator itr = _listeners->begin(); itr != _listeners->end(); itr++)
         {
         {
-            if (eventTime < (*itr)->_listenerTime)
+            if (eventTime < (*itr)->_eventTime)
             {
             {
-                itr = _listeners->_list.insert(itr, listener);
+                itr = _listeners->insert(itr, listenerEvent);
 
 
                 // If playing, update the iterator if we need to.
                 // If playing, update the iterator if we need to.
                 // otherwise, it will just be set the next time the clip gets played.
                 // otherwise, it will just be set the next time the clip gets played.
-                if (_isPlaying)
+                if (isClipStateBitSet(CLIP_IS_PLAYING_BIT))
                 {
                 {
                     unsigned long currentTime = _elapsedTime % _duration;
                     unsigned long currentTime = _elapsedTime % _duration;
-                    if ((_speed >= 0.0f && currentTime < eventTime && eventTime < (*_listeners->_listItr)->_listenerTime) || 
-                        (_speed <= 0 && currentTime > eventTime && eventTime > (*_listeners->_listItr)->_listenerTime))
-                        _listeners->_listItr = itr;
+                    if ((_speed >= 0.0f && currentTime < eventTime && (*_listenerItr == _listeners->end() || eventTime < (**_listenerItr)->_eventTime)) || 
+                        (_speed <= 0 && currentTime > eventTime && (*_listenerItr == _listeners->begin() || eventTime > (**_listenerItr)->_eventTime)))
+                        *_listenerItr = itr;
                 }
                 }
-
                 return;
                 return;
             }
             }
         }
         }
+        _listeners->push_back(listenerEvent);
     }
     }
 }
 }
 
 
@@ -235,21 +291,43 @@ void AnimationClip::addEndListener(AnimationClip::Listener* listener)
 
 
 bool AnimationClip::update(unsigned long elapsedTime, std::list<AnimationTarget*>* activeTargets)
 bool AnimationClip::update(unsigned long elapsedTime, std::list<AnimationTarget*>* activeTargets)
 {
 {
-    if (!_isPlaying)
+    if (isClipStateBitSet(CLIP_IS_MARKED_FOR_REMOVAL_BIT))
+    {   // If the marked for removal bit is set, it means stop() was called on the AnimationClip at some point
+        // after the last update call. Reset the flag, and return true so the AnimationClip is removed from the 
+        // running clips on the AnimationController.
+        onEnd();
+        return true;
+    }
+    else if (!isClipStateBitSet(CLIP_IS_STARTED_BIT))
+    {
         onBegin();
         onBegin();
-    else 
+    }
+    else
+    {
         _elapsedTime += elapsedTime * _speed;
         _elapsedTime += elapsedTime * _speed;
 
 
+        if (_repeatCount == REPEAT_INDEFINITE && _elapsedTime <= 0)
+            _elapsedTime = _activeDuration + _elapsedTime;
+    }
+
     unsigned long currentTime = 0L;
     unsigned long currentTime = 0L;
     // Check to see if clip is complete.
     // Check to see if clip is complete.
     if (_repeatCount != REPEAT_INDEFINITE && ((_speed >= 0.0f && _elapsedTime >= (long) _activeDuration) || (_speed <= 0.0f && _elapsedTime <= 0L)))
     if (_repeatCount != REPEAT_INDEFINITE && ((_speed >= 0.0f && _elapsedTime >= (long) _activeDuration) || (_speed <= 0.0f && _elapsedTime <= 0L)))
     {
     {
-        _isPlaying = false;
+        resetClipStateBit(CLIP_IS_STARTED_BIT);
         if (_speed >= 0.0f)
         if (_speed >= 0.0f)
         {
         {
-            currentTime = _activeDuration % _duration; // Get's the fractional part of the final repeat.
-            if (currentTime == 0L)
-                currentTime = _duration;
+            // If _duration == 0, we have a "pose". Just set currentTime to 0.
+            if (_duration == 0)
+            {
+                currentTime = 0L;
+            }
+            else
+            {
+                currentTime = _activeDuration % _duration; // Get's the fractional part of the final repeat.
+                if (currentTime == 0L)
+                    currentTime = _duration;
+            }
         }
         }
         else
         else
         {
         {
@@ -258,31 +336,43 @@ bool AnimationClip::update(unsigned long elapsedTime, std::list<AnimationTarget*
     }
     }
     else
     else
     {
     {
-        // Gets portion/fraction of the repeat.
-        currentTime = _elapsedTime % _duration;
+        // If _duration == 0, we have a "pose". Just set currentTime to 0.
+        if (_duration == 0)
+            currentTime = 0L;
+        else // Gets portion/fraction of the repeat.
+            currentTime = _elapsedTime % _duration;
     }
     }
 
 
     // Notify any listeners of Animation events.
     // Notify any listeners of Animation events.
     if (_listeners)
     if (_listeners)
     {
     {
-        while (_listeners->_listItr != _listeners->_list.end() && (_speed >= 0.0f && currentTime % _duration >= (*_listeners->_listItr)->_listenerTime) || 
-                                                     (_speed <= 0.0f && currentTime % _duration <= (*_listeners->_listItr)->_listenerTime))
+        if (_speed >= 0.0f)
         {
         {
-            
-            (*_listeners->_listItr)->animationEvent(this, Listener::DEFAULT);
-            (_listeners->_listItr)++;
+            while (*_listenerItr != _listeners->end() && _elapsedTime >= (long) (**_listenerItr)->_eventTime)
+            {
+                (**_listenerItr)->_listener->animationEvent(this, Listener::DEFAULT);
+                ++*_listenerItr;
+            }
+        }
+        else
+        {
+            while (*_listenerItr != _listeners->begin() && _elapsedTime <= (long) (**_listenerItr)->_eventTime)
+            {
+                (**_listenerItr)->_listener->animationEvent(this, Listener::DEFAULT);
+                --*_listenerItr;
+            }
         }
         }
     }
     }
 
 
     // Add back in start time, and divide by the total animation's duration to get the actual percentage complete
     // Add back in start time, and divide by the total animation's duration to get the actual percentage complete
     float percentComplete = (float)(_startTime + currentTime) / (float) _animation->_duration;
     float percentComplete = (float)(_startTime + currentTime) / (float) _animation->_duration;
     
     
-    if (_isFadingOut)
+    if (isClipStateBitSet(CLIP_IS_FADING_OUT_BIT))
     {
     {
-        if (_isFadingOutStarted) // Calculate elapsed time since the fade out begin.
+        if (isClipStateBitSet(CLIP_IS_FADING_OUT_STARTED_BIT)) // Calculate elapsed time since the fade out begin.
         {
         {
-            _crossFadeOutElapsed = (Game::getGameTime() - _crossFadeToClip->_timeStarted) * _speed; 
-            _isFadingOutStarted = false;
+            _crossFadeOutElapsed = (Game::getGameTime() - _crossFadeToClip->_timeStarted) * abs(_speed); 
+            resetClipStateBit(CLIP_IS_FADING_OUT_STARTED_BIT);
         }
         }
         else
         else
         {
         {
@@ -296,7 +386,7 @@ bool AnimationClip::update(unsigned long elapsedTime, std::list<AnimationTarget*
             float tempBlendWeight = (float) (_crossFadeOutDuration - _crossFadeOutElapsed) / (float) _crossFadeOutDuration;
             float tempBlendWeight = (float) (_crossFadeOutDuration - _crossFadeOutElapsed) / (float) _crossFadeOutDuration;
             
             
             // If this clip is fading in, adjust the crossfade clip's weight to be a percentage of your current blend weight
             // If this clip is fading in, adjust the crossfade clip's weight to be a percentage of your current blend weight
-            if (_isFadingIn)
+            if (isClipStateBitSet(CLIP_IS_FADING_IN_BIT))
             {
             {
                 _crossFadeToClip->_blendWeight = (1.0f - tempBlendWeight) * _blendWeight;
                 _crossFadeToClip->_blendWeight = (1.0f - tempBlendWeight) * _blendWeight;
                 _blendWeight -= _crossFadeToClip->_blendWeight;
                 _blendWeight -= _crossFadeToClip->_blendWeight;
@@ -310,21 +400,12 @@ bool AnimationClip::update(unsigned long elapsedTime, std::list<AnimationTarget*
         }
         }
         else
         else
         {   // Fade is done.
         {   // Fade is done.
-            // Set the crossFadeToClip's blend weight to 1
             _crossFadeToClip->_blendWeight = 1.0f;
             _crossFadeToClip->_blendWeight = 1.0f;
-            
-            // Adjust the crossfade clip's blend weight if this clip is also fading in.
-            if (_isFadingIn)
-                _crossFadeToClip->_blendWeight *= _blendWeight;
-
-            // The crossfade clip is no longer fading in
-            _crossFadeToClip->_isFadingIn = false;
-
-            // Release the crossfade clip, mark ourselves as done and set our blend weight to 0.
+            _blendWeight = 0.0f;
+            resetClipStateBit(CLIP_IS_STARTED_BIT);            
+            resetClipStateBit(CLIP_IS_FADING_OUT_BIT);
+            _crossFadeToClip->resetClipStateBit(CLIP_IS_FADING_IN_BIT);
             SAFE_RELEASE(_crossFadeToClip);
             SAFE_RELEASE(_crossFadeToClip);
-            _blendWeight = 0.0f; 
-            _isFadingOut = false;
-            _isPlaying = false;
         }
         }
     }
     }
     
     
@@ -352,46 +433,34 @@ bool AnimationClip::update(unsigned long elapsedTime, std::list<AnimationTarget*
     }
     }
 
 
     // When ended. Probably should move to it's own method so we can call it when the clip is ended early.
     // When ended. Probably should move to it's own method so we can call it when the clip is ended early.
-    if (!_isPlaying)
+    if (isClipStateBitSet(CLIP_IS_MARKED_FOR_REMOVAL_BIT) || !isClipStateBitSet(CLIP_IS_STARTED_BIT))
     {
     {
         onEnd();
         onEnd();
-        // Notify end listeners if any.
-        if (_endListeners)
-        {
-            std::vector<Listener*>::iterator listener = _endListeners->begin();
-            while (listener != _endListeners->end())
-            {
-                (*listener)->animationEvent(this, Listener::END);
-                listener++;
-            }
-        }
+        return true;
     }
     }
 
 
-    return !_isPlaying;
+    return false;
 }
 }
 
 
 void AnimationClip::onBegin()
 void AnimationClip::onBegin()
 {
 {
     // Initialize animation to play.
     // Initialize animation to play.
-    _isPlaying = true;
-
+    setClipStateBit(CLIP_IS_STARTED_BIT);
     if (_speed >= 0)
     if (_speed >= 0)
     {
     {
-        _elapsedTime = 0;
+        _elapsedTime = (Game::getGameTime() - _timeStarted) * _speed;
 
 
         if (_listeners)
         if (_listeners)
-            _listeners->_listItr = _listeners->_list.begin();
+            *_listenerItr = _listeners->begin(); 
     }
     }
     else
     else
     {
     {
-        _elapsedTime = _activeDuration;
+        _elapsedTime = _activeDuration + (Game::getGameTime() - _timeStarted) * _speed;
 
 
         if (_listeners)
         if (_listeners)
-            _listeners->_listItr = _listeners->_list.end();
+            *_listenerItr = _listeners->end();
     }
     }
-
-    _elapsedTime += (Game::getGameTime() - _timeStarted) * _speed;
-
+    
     // Notify begin listeners.. if any.
     // Notify begin listeners.. if any.
     if (_beginListeners)
     if (_beginListeners)
     {
     {
@@ -407,7 +476,33 @@ void AnimationClip::onBegin()
 void AnimationClip::onEnd()
 void AnimationClip::onEnd()
 {
 {
     _blendWeight = 1.0f;
     _blendWeight = 1.0f;
-    _timeStarted = 0;
+    resetClipStateBit(CLIP_ALL_BITS);
+
+    // Notify end listeners if any.
+    if (_endListeners)
+    {
+        std::vector<Listener*>::iterator listener = _endListeners->begin();
+        while (listener != _endListeners->end())
+        {
+            (*listener)->animationEvent(this, Listener::END);
+            listener++;
+        }
+    }
+}
+
+bool AnimationClip::isClipStateBitSet(char bit) const
+{
+    return (_stateBits & bit) == bit;
+}
+
+void AnimationClip::setClipStateBit(char bit)
+{
+    _stateBits |= bit;
+}
+
+void AnimationClip::resetClipStateBit(char bit)
+{
+    _stateBits &= ~bit;
 }
 }
 
 
 }
 }

+ 72 - 34
gameplay/src/AnimationClip.h

@@ -32,12 +32,11 @@ public:
      */
      */
     class Listener
     class Listener
     {
     {
-        friend AnimationClip;
+        friend class AnimationClip;
 
 
     public:
     public:
 
 
         Listener() 
         Listener() 
-            : _listenerTime(0L)
         {
         {
         }
         }
 
 
@@ -66,9 +65,6 @@ public:
          * Handles when animation event occurs.
          * Handles when animation event occurs.
          */
          */
         virtual void animationEvent(AnimationClip* clip, EventType type) = 0;
         virtual void animationEvent(AnimationClip* clip, EventType type) = 0;
-
-    private:
-        unsigned long _listenerTime;
     };
     };
 
 
     /**
     /**
@@ -138,6 +134,13 @@ public:
      */
      */
     unsigned long getActiveDuration() const;
     unsigned long getActiveDuration() const;
 
 
+    /**
+     * Gets the AnimationClip's duration.
+     *
+     * @return the AnimationClip's duration.
+     */
+    unsigned long getDuration() const;
+
     /**
     /**
      * Set the AnimationClip's running speed. 
      * Set the AnimationClip's running speed. 
      *
      *
@@ -217,6 +220,38 @@ public:
     void addListener(AnimationClip::Listener* listener, unsigned long eventTime);
     void addListener(AnimationClip::Listener* listener, unsigned long eventTime);
 
 
 private:
 private:
+    /**
+     * State bits.
+     */
+    static const char CLIP_IS_PLAYING_BIT = 0x01;             // Bit representing whether AnimationClip is a running clip in AnimationController
+    static const char CLIP_IS_STARTED_BIT = 0x02;             // Bit representing whether the AnimationClip has actually been started (ie: received first call to update())
+    static const char CLIP_IS_FADING_OUT_STARTED_BIT = 0x04;  // Bit representing that a cross fade has started.
+    static const char CLIP_IS_FADING_OUT_BIT = 0x08;          // Bit representing whether the clip is fading out.
+    static const char CLIP_IS_FADING_IN_BIT = 0x10;           // Bit representing whether the clip is fading out.
+    static const char CLIP_IS_MARKED_FOR_REMOVAL_BIT = 0x20;  // Bit representing whether the clip has ended and should be removed from the AnimationController.
+    static const char CLIP_IS_RESTARTED_BIT = 0x40;           // Bit representing if the clip should be restarted by the AnimationController.
+    static const char CLIP_ALL_BITS = 0x7F;                   // Bit mask for all the state bits.
+
+    /**
+     * ListenerEvent.
+     *
+     * Internal structure used for storing the event time at which an AnimationClip::Listener should be called back.
+     */
+    struct ListenerEvent
+    {
+        /** 
+         * Constructor.
+         */
+        ListenerEvent(Listener* listener, unsigned long eventTime);
+
+        /**
+         * Destructor.
+         */
+        ~ListenerEvent();
+
+        Listener* _listener;        // This listener to call back when this event is triggered.
+        unsigned long _eventTime;   // The time at which the listener will be called back at during the playback of the AnimationClip.
+    };
 
 
     /**
     /**
      * Constructor.
      * Constructor.
@@ -254,38 +289,41 @@ private:
     void onEnd();
     void onEnd();
 
 
     /**
     /**
-     * A list that keeps a pointer to the next listener event to be triggered.
+     * Determines whether the given bit is set in the AnimationClip's state.
      */
      */
-    struct ListenerList
-    {
-        std::list<Listener*> _list;
-        std::list<Listener*>::iterator _listItr;
-    };
+    bool isClipStateBitSet(char bit) const;
 
 
-    std::string _id;                                // AnimationClip ID.
-    Animation* _animation;                          // The Animation this clip is created from.
-    unsigned long _startTime;                       // Start time of the clip.
-    unsigned long _endTime;                         // End time of the clip.
-    unsigned long _duration;                        // The total duration.
-    float _repeatCount;                             // The clip's repeat count.
-    unsigned long _activeDuration;                  // The active duration of the clip.
-    float _speed;                                   // The speed that the clip is playing. Default is 1.0. Negative goes in reverse.
-    bool _isPlaying;                                // A flag to indicate whether the clip is playing.
-    unsigned long _timeStarted;                     // The game time when this clip was actually started.
-    long _elapsedTime;                              // Time elapsed while the clip is running.
-    AnimationClip* _crossFadeToClip;                // The clip to cross fade to.
-    unsigned long _crossFadeOutElapsed;             // The amount of time that has elapsed for the crossfade.
-    unsigned long _crossFadeOutDuration;            // The duration of the cross fade.
-    float _blendWeight;                             // The clip's blendweight.
-    bool _isFadingOutStarted;                       // Flag to indicate if the cross fade started.
-    bool _isFadingOut;                              // Flag to indicate if the clip is fading out.
-    bool _isFadingIn;                               // Flag to indicate if the clip is fading in.
-    std::vector<AnimationValue*> _values;           // AnimationValue holder.
-    std::vector<Listener*>* _beginListeners;        // Collection of begin listeners on the clip.
-    std::vector<Listener*>* _endListeners;          // Collection of end listeners on the clip.
-    ListenerList* _listeners;                       // Collection of listeners on the clip.
+    /**
+     * Sets the given bit in the AnimationClip's state.
+     */
+    void setClipStateBit(char bit);
+
+    /**
+     * Resets the given bit in the AnimationClip's state.
+     */
+    void resetClipStateBit(char bit);
+
+    std::string _id;                                    // AnimationClip ID.
+    Animation* _animation;                              // The Animation this clip is created from.
+    unsigned long _startTime;                           // Start time of the clip.
+    unsigned long _endTime;                             // End time of the clip.
+    unsigned long _duration;                            // The total duration.
+    char _stateBits;                                    // Bit flag used to keep track of the clip's current state.
+    float _repeatCount;                                 // The clip's repeat count.
+    unsigned long _activeDuration;                      // The active duration of the clip.
+    float _speed;                                       // The speed that the clip is playing. Default is 1.0. Negative goes in reverse.
+    unsigned long _timeStarted;                         // The game time when this clip was actually started.
+    long _elapsedTime;                                  // Time elapsed while the clip is running.
+    AnimationClip* _crossFadeToClip;                    // The clip to cross fade to.
+    unsigned long _crossFadeOutElapsed;                 // The amount of time that has elapsed for the crossfade.
+    unsigned long _crossFadeOutDuration;                // The duration of the cross fade.
+    float _blendWeight;                                 // The clip's blendweight.
+    std::vector<AnimationValue*> _values;               // AnimationValue holder.
+    std::vector<Listener*>* _beginListeners;            // Collection of begin listeners on the clip.
+    std::vector<Listener*>* _endListeners;              // Collection of end listeners on the clip.
+    std::list<ListenerEvent*>* _listeners;              // Ordered collection of listeners on the clip.
+    std::list<ListenerEvent*>::iterator* _listenerItr;  // Iterator that points to the next listener event to be triggered.
 };
 };
 
 
 }
 }
-
 #endif
 #endif

+ 15 - 19
gameplay/src/AnimationController.cpp

@@ -111,10 +111,8 @@ void AnimationController::stopAllAnimations()
     while (clipIter != _runningClips.end())
     while (clipIter != _runningClips.end())
     {
     {
         AnimationClip* clip = *clipIter;
         AnimationClip* clip = *clipIter;
-        clip->_isPlaying = false;
-        clip->onEnd();
-        SAFE_RELEASE(clip);
         clipIter++;
         clipIter++;
+        clip->stop();
     }
     }
     _runningClips.clear();
     _runningClips.clear();
 
 
@@ -147,7 +145,7 @@ Animation* AnimationController::createAnimation(const char* id, AnimationTarget*
     
     
     char delimeter = ' ';
     char delimeter = ' ';
     unsigned int startOffset = 0;
     unsigned int startOffset = 0;
-    unsigned int endOffset = std::string::npos;
+    unsigned int endOffset = (unsigned int)std::string::npos;
     
     
     unsigned long* keyTimes = new unsigned long[keyCount];
     unsigned long* keyTimes = new unsigned long[keyCount];
     for (unsigned int i = 0; i < keyCount; i++)
     for (unsigned int i = 0; i < keyCount; i++)
@@ -165,7 +163,7 @@ Animation* AnimationController::createAnimation(const char* id, AnimationTarget*
     }
     }
 
 
     startOffset = 0;
     startOffset = 0;
-    endOffset = std::string::npos;
+    endOffset = (unsigned int)std::string::npos;
     
     
     int componentCount = target->getAnimationPropertyComponentCount(propertyId);
     int componentCount = target->getAnimationPropertyComponentCount(propertyId);
     assert(componentCount > 0);
     assert(componentCount > 0);
@@ -193,7 +191,7 @@ Animation* AnimationController::createAnimation(const char* id, AnimationTarget*
     {
     {
         keyIn = new float[components];
         keyIn = new float[components];
         startOffset = 0;
         startOffset = 0;
-        endOffset = std::string::npos;
+        endOffset = (unsigned int)std::string::npos;
         for (unsigned int i = 0; i < components; i++)
         for (unsigned int i = 0; i < components; i++)
         {
         {
             endOffset = static_cast<std::string>(keyInStr).find_first_of(delimeter, startOffset);
             endOffset = static_cast<std::string>(keyInStr).find_first_of(delimeter, startOffset);
@@ -215,7 +213,7 @@ Animation* AnimationController::createAnimation(const char* id, AnimationTarget*
     {   
     {   
         keyOut = new float[components];
         keyOut = new float[components];
         startOffset = 0;
         startOffset = 0;
-        endOffset = std::string::npos;
+        endOffset = (unsigned int)std::string::npos;
         for (unsigned int i = 0; i < components; i++)
         for (unsigned int i = 0; i < components; i++)
         {
         {
             endOffset = static_cast<std::string>(keyOutStr).find_first_of(delimeter, startOffset);
             endOffset = static_cast<std::string>(keyOutStr).find_first_of(delimeter, startOffset);
@@ -294,18 +292,8 @@ void AnimationController::schedule(AnimationClip* clip)
     {
     {
         _state = RUNNING;
         _state = RUNNING;
     }
     }
-    
-    if (clip->_isPlaying)
-    {
-        _runningClips.remove(clip);
-        clip->_isPlaying = false;
-        clip->onEnd();
-    }
-    else
-    {
-        clip->addRef();
-    }
 
 
+    clip->addRef();
     _runningClips.push_back(clip);
     _runningClips.push_back(clip);
 }
 }
 
 
@@ -338,7 +326,15 @@ void AnimationController::update(long elapsedTime)
     while (clipIter != _runningClips.end())
     while (clipIter != _runningClips.end())
     {
     {
         AnimationClip* clip = (*clipIter);
         AnimationClip* clip = (*clipIter);
-        if (clip->update(elapsedTime, &_activeTargets))
+        if (clip->isClipStateBitSet(AnimationClip::CLIP_IS_RESTARTED_BIT))
+        {   // If the CLIP_IS_RESTARTED_BIT is set, we should end the clip and 
+            // move it from where it is in the running clips list to the back.
+            clip->onEnd();
+            clip->setClipStateBit(AnimationClip::CLIP_IS_PLAYING_BIT);
+            _runningClips.push_back(clip);
+            clipIter = _runningClips.erase(clipIter);
+        }
+        else if (clip->update(elapsedTime, &_activeTargets))
         {
         {
             SAFE_RELEASE(clip);
             SAFE_RELEASE(clip);
             clipIter = _runningClips.erase(clipIter);
             clipIter = _runningClips.erase(clipIter);

+ 43 - 6
gameplay/src/AudioBuffer.cpp

@@ -179,6 +179,12 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
     if (fread(stream, 1, 8, file) != 8 || memcmp(stream, "fmt ", 4) != 0 )
     if (fread(stream, 1, 8, file) != 8 || memcmp(stream, "fmt ", 4) != 0 )
         return false;
         return false;
     
     
+    unsigned int section_size;
+    section_size  = stream[7]<<24;
+    section_size |= stream[6]<<16;
+    section_size |= stream[5]<<8;
+    section_size |= stream[4];
+
     // Check for a valid pcm format.
     // Check for a valid pcm format.
     if (fread(stream, 1, 2, file) != 2 || stream[1] != 0 || stream[0] != 1)
     if (fread(stream, 1, 2, file) != 2 || stream[1] != 0 || stream[0] != 1)
     {
     {
@@ -216,7 +222,6 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
     bits  = stream[1]<<8;
     bits  = stream[1]<<8;
     bits |= stream[0];
     bits |= stream[0];
     
     
-
     // Now convert the given channel count and bit depth into an OpenAL format. 
     // Now convert the given channel count and bit depth into an OpenAL format. 
     ALuint format = 0;
     ALuint format = 0;
     if (bits == 8)
     if (bits == 8)
@@ -239,13 +244,45 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
         return false;
         return false;
     }
     }
     
     
-    // Read the data chunk, which will hold the decoded sample data 
-    if (fread(stream, 1, 4, file) != 4 || memcmp(stream, "data", 4) != 0)
+    // Check against the size of the format header as there may be more data that we need to read
+    if (section_size > 16)
     {
     {
-        LOG_ERROR("WAV file has no data.");
-        return false;
+    	unsigned int length = section_size - 16;
+
+    	// extension size is 2 bytes
+    	if (fread(stream, 1, length, file) != length)
+    		return false;
     }
     }
-    
+
+    if (fread(stream, 1, 4, file) != 4)
+    	return false;
+
+    // read the next chunk, could be fact section or the data section
+    if (memcmp(stream, "fact", 4) == 0)
+    {
+    	if (fread(stream, 1, 4, file) != 4)
+    		return false;
+
+    	section_size  = stream[3]<<24;
+    	section_size |= stream[2]<<16;
+    	section_size |= stream[1]<<8;
+    	section_size |= stream[0];
+
+    	// read in the rest of the fact section
+    	if (fread(stream, 1, section_size, file) != section_size)
+    		return false;
+
+    	if (fread(stream, 1, 4, file) != 4)
+    		return false;
+    }
+
+    // should now be the data section which holds the decoded sample data
+    if (memcmp(stream, "data", 4) != 0)
+    {
+    	LOG_ERROR("WAV file has no data.");
+    	return false;
+    }
+
     // Read how much data is remaining and buffer it up.
     // Read how much data is remaining and buffer it up.
     unsigned int dataSize;
     unsigned int dataSize;
     fread(&dataSize, sizeof(int), 1, file);
     fread(&dataSize, sizeof(int), 1, file);

+ 2 - 10
gameplay/src/Base.h

@@ -17,6 +17,7 @@
 #include <string>
 #include <string>
 #include <vector>
 #include <vector>
 #include <list>
 #include <list>
+#include <set>
 #include <stack>
 #include <stack>
 #include <map>
 #include <map>
 #include <algorithm>
 #include <algorithm>
@@ -108,7 +109,6 @@ extern void printError(const char* format, ...);
 
 
 // Object deletion macro
 // Object deletion macro
 #define SAFE_DELETE(x) \
 #define SAFE_DELETE(x) \
-    if (x) \
     { \
     { \
         delete x; \
         delete x; \
         x = NULL; \
         x = NULL; \
@@ -116,7 +116,6 @@ extern void printError(const char* format, ...);
 
 
 // Array deletion macro
 // Array deletion macro
 #define SAFE_DELETE_ARRAY(x) \
 #define SAFE_DELETE_ARRAY(x) \
-    if (x) \
     { \
     { \
         delete[] x; \
         delete[] x; \
         x = NULL; \
         x = NULL; \
@@ -145,6 +144,7 @@ extern void printError(const char* format, ...);
 #define MATH_PIOVER4                M_PI_4
 #define MATH_PIOVER4                M_PI_4
 #define MATH_PIX2                   6.28318530717958647693f
 #define MATH_PIX2                   6.28318530717958647693f
 #define MATH_EPSILON                0.000001f
 #define MATH_EPSILON                0.000001f
+#define MATH_CLAMP(x, lo, hi)       ((x < lo) ? lo : ((x > hi) ? hi : x))
 #ifndef M_1_PI
 #ifndef M_1_PI
 #define M_1_PI                      0.31830988618379067154
 #define M_1_PI                      0.31830988618379067154
 #endif
 #endif
@@ -191,13 +191,9 @@ extern void printError(const char* format, ...);
     extern PFNGLISVERTEXARRAYOESPROC glIsVertexArray;
     extern PFNGLISVERTEXARRAYOESPROC glIsVertexArray;
     #define glClearDepth glClearDepthf
     #define glClearDepth glClearDepthf
     #define OPENGL_ES
     #define OPENGL_ES
-    #define WINDOW_WIDTH    1024
-    #define WINDOW_HEIGHT   600
 #elif WIN32
 #elif WIN32
     #define WIN32_LEAN_AND_MEAN
     #define WIN32_LEAN_AND_MEAN
     #include <GL/glew.h>
     #include <GL/glew.h>
-    #define WINDOW_WIDTH    1024
-    #define WINDOW_HEIGHT   600
 #elif __APPLE__
 #elif __APPLE__
     #include "TargetConditionals.h"
     #include "TargetConditionals.h"
     #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
     #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
@@ -209,8 +205,6 @@ extern void printError(const char* format, ...);
         #define glIsVertexArray glIsVertexArrayOES
         #define glIsVertexArray glIsVertexArrayOES
         #define glClearDepth glClearDepthf
         #define glClearDepth glClearDepthf
         #define OPENGL_ES
         #define OPENGL_ES
-        #define WINDOW_WIDTH    480
-        #define WINDOW_HEIGHT   360
     #elif TARGET_OS_MAC
     #elif TARGET_OS_MAC
         #include <OpenGL/gl.h>
         #include <OpenGL/gl.h>
         #include <OpenGL/glext.h>
         #include <OpenGL/glext.h>
@@ -218,8 +212,6 @@ extern void printError(const char* format, ...);
         #define glDeleteVertexArrays glDeleteVertexArraysAPPLE
         #define glDeleteVertexArrays glDeleteVertexArraysAPPLE
         #define glGenVertexArrays glGenVertexArraysAPPLE
         #define glGenVertexArrays glGenVertexArraysAPPLE
         #define glIsVertexArray glIsVertexArrayAPPLE
         #define glIsVertexArray glIsVertexArrayAPPLE
-        #define WINDOW_WIDTH    960
-        #define WINDOW_HEIGHT   640
     #else
     #else
         #error "Unsupported Apple Device"
         #error "Unsupported Apple Device"
     #endif
     #endif

+ 1 - 1
gameplay/src/BoundingBox.h

@@ -191,7 +191,7 @@ public:
  * @param box The bounding box to transform.
  * @param box The bounding box to transform.
  * @return The resulting transformed bounding box.
  * @return The resulting transformed bounding box.
  */
  */
-inline BoundingBox operator*(const Matrix& matrix, const BoundingBox& box);
+inline const BoundingBox operator*(const Matrix& matrix, const BoundingBox& box);
 
 
 }
 }
 
 

+ 1 - 1
gameplay/src/BoundingBox.inl

@@ -9,7 +9,7 @@ inline BoundingBox& BoundingBox::operator*=(const Matrix& matrix)
     return *this;
     return *this;
 }
 }
 
 
-inline BoundingBox operator*(const Matrix& matrix, const BoundingBox& box)
+inline const BoundingBox operator*(const Matrix& matrix, const BoundingBox& box)
 {
 {
     BoundingBox b(box);
     BoundingBox b(box);
     b.transform(matrix);
     b.transform(matrix);

+ 1 - 1
gameplay/src/BoundingSphere.h

@@ -183,7 +183,7 @@ private:
  * @param sphere The bounding sphere to transform.
  * @param sphere The bounding sphere to transform.
  * @return The resulting transformed bounding sphere.
  * @return The resulting transformed bounding sphere.
  */
  */
-inline BoundingSphere operator*(const Matrix& matrix, const BoundingSphere& sphere);
+inline const BoundingSphere operator*(const Matrix& matrix, const BoundingSphere& sphere);
 
 
 }
 }
 
 

+ 1 - 1
gameplay/src/BoundingSphere.inl

@@ -9,7 +9,7 @@ inline BoundingSphere& BoundingSphere::operator*=(const Matrix& matrix)
     return *this;
     return *this;
 }
 }
 
 
-inline BoundingSphere operator*(const Matrix& matrix, const BoundingSphere& sphere)
+inline const BoundingSphere operator*(const Matrix& matrix, const BoundingSphere& sphere)
 {
 {
     BoundingSphere s(sphere);
     BoundingSphere s(sphere);
     s.transform(matrix);
     s.transform(matrix);

+ 2 - 1
gameplay/src/DebugNew.cpp

@@ -109,7 +109,8 @@ void* debugAlloc(std::size_t size, const char* file, int line)
 
 
 void debugFree(void* p)
 void debugFree(void* p)
 {
 {
-    assert(p);
+    if (p == 0)
+        return;
 
 
     // Backup passed in pointer to access memory allocation record
     // Backup passed in pointer to access memory allocation record
     void* mem = ((unsigned char*)p) - sizeof(MemoryAllocationRecord);
     void* mem = ((unsigned char*)p) - sizeof(MemoryAllocationRecord);

+ 10 - 10
gameplay/src/Font.cpp

@@ -177,10 +177,10 @@ void Font::begin()
 void Font::drawText(const char* text, int x, int y, const Vector4& color, unsigned int size, bool rightToLeft)
 void Font::drawText(const char* text, int x, int y, const Vector4& color, unsigned int size, bool rightToLeft)
 {
 {
     float scale = (float)size / _size;
     float scale = (float)size / _size;
-    char* cursor = NULL;
+    const char* cursor = NULL;
     if (rightToLeft)
     if (rightToLeft)
     {
     {
-        cursor = const_cast<char*>(text);
+        cursor = text;
     }
     }
 
 
     int xPos = x, yPos = y;
     int xPos = x, yPos = y;
@@ -289,7 +289,7 @@ void Font::drawText(const char* text, int x, int y, const Vector4& color, unsign
 void Font::drawText(const char* text, const Rectangle& area, const Vector4& color, unsigned int size, Justify justify, bool wrap, bool rightToLeft)
 void Font::drawText(const char* text, const Rectangle& area, const Vector4& color, unsigned int size, Justify justify, bool wrap, bool rightToLeft)
 {
 {
     float scale = (float)size / _size;
     float scale = (float)size / _size;
-    char* token = const_cast<char*>(text);
+    const char* token = text;
     const int length = strlen(text);
     const int length = strlen(text);
     int yPos = area.y;
     int yPos = area.y;
 
 
@@ -305,7 +305,7 @@ void Font::drawText(const char* text, const Rectangle& area, const Vector4& colo
         hAlign = ALIGN_LEFT;
         hAlign = ALIGN_LEFT;
     }
     }
 
 
-    token = const_cast<char*>(text);
+    token = text;
 
 
     // For alignments other than top-left, need to calculate the y position to begin drawing from
     // For alignments other than top-left, need to calculate the y position to begin drawing from
     // and the starting x position of each line.  For right-to-left text, need to determine
     // and the starting x position of each line.  For right-to-left text, need to determine
@@ -476,12 +476,12 @@ void Font::drawText(const char* text, const Rectangle& area, const Vector4& colo
         xPos = *xPositionsIt++;
         xPos = *xPositionsIt++;
     }
     }
 
 
-    token = const_cast<char*>(text);
+    token = text;
     
     
     int iteration = 1;
     int iteration = 1;
     unsigned int lineLength;
     unsigned int lineLength;
     unsigned int currentLineLength = 0;
     unsigned int currentLineLength = 0;
-    char* lineStart;
+    const char* lineStart;
     std::vector<unsigned int>::const_iterator lineLengthsIt;
     std::vector<unsigned int>::const_iterator lineLengthsIt;
     if (rightToLeft)
     if (rightToLeft)
     {
     {
@@ -651,7 +651,7 @@ void Font::measureText(const char* text, unsigned int size, unsigned int* width,
 {
 {
     float scale = (float)size / _size;
     float scale = (float)size / _size;
     const int length = strlen(text);
     const int length = strlen(text);
-    char* token = const_cast<char*>(text);
+    const char* token = text;
 
 
     *width = 0;
     *width = 0;
     *height = 0;
     *height = 0;
@@ -691,7 +691,7 @@ void Font::measureText(const char* text, const Rectangle& viewport, unsigned int
         hAlign = ALIGN_LEFT;
         hAlign = ALIGN_LEFT;
     }
     }
 
 
-    char* token = const_cast<char*>(text);
+    const char* token = text;
     std::vector<bool> emptyLines;
     std::vector<bool> emptyLines;
     std::vector<Vector2> lines;
     std::vector<Vector2> lines;
 
 
@@ -1027,7 +1027,7 @@ unsigned int Font::getTokenWidth(const char* token, unsigned int length, unsigne
 
 
 unsigned int Font::getReversedTokenLength(const char* token, const char* bufStart)
 unsigned int Font::getReversedTokenLength(const char* token, const char* bufStart)
 {
 {
-    char* cursor = const_cast<char*>(token);
+    const char* cursor = token;
     char c = cursor[0];
     char c = cursor[0];
     unsigned int length = 0;
     unsigned int length = 0;
 
 
@@ -1046,7 +1046,7 @@ unsigned int Font::getReversedTokenLength(const char* token, const char* bufStar
     return length;
     return length;
 }
 }
 
 
-bool Font::handleDelimiters(char** token, const unsigned int size, const int iteration, const int areaX, int* xPos, int* yPos, unsigned int* lineLength,
+bool Font::handleDelimiters(const char** token, const unsigned int size, const int iteration, const int areaX, int* xPos, int* yPos, unsigned int* lineLength,
                       std::vector<int>::const_iterator* xPositionsIt, std::vector<int>::const_iterator xPositionsEnd)
                       std::vector<int>::const_iterator* xPositionsIt, std::vector<int>::const_iterator xPositionsEnd)
 {
 {
     char delimiter = *token[0];
     char delimiter = *token[0];

+ 1 - 1
gameplay/src/Font.h

@@ -198,7 +198,7 @@ private:
     unsigned int getReversedTokenLength(const char* token, const char* bufStart);
     unsigned int getReversedTokenLength(const char* token, const char* bufStart);
 
 
     // Returns false if EOF was reached, true otherwise.
     // Returns false if EOF was reached, true otherwise.
-    bool handleDelimiters(char** token, const unsigned int size, const int iteration, const int areaX, int* xPos, int* yPos, unsigned int* lineLength,
+    bool handleDelimiters(const char** token, const unsigned int size, const int iteration, const int areaX, int* xPos, int* yPos, unsigned int* lineLength,
                           std::vector<int>::const_iterator* xPositionsIt, std::vector<int>::const_iterator xPositionsEnd);
                           std::vector<int>::const_iterator* xPositionsIt, std::vector<int>::const_iterator xPositionsEnd);
     void addLineInfo(const Rectangle& area, int lineWidth, int lineLength, Justify hAlign,
     void addLineInfo(const Rectangle& area, int lineWidth, int lineLength, Justify hAlign,
                      std::vector<int>* xPositions, std::vector<unsigned int>* lineLengths, bool rightToLeft);
                      std::vector<int>* xPositions, std::vector<unsigned int>* lineLengths, bool rightToLeft);

+ 10 - 7
gameplay/src/Game.cpp

@@ -68,8 +68,15 @@ int Game::run(int width, int height)
     if (_state != UNINITIALIZED)
     if (_state != UNINITIALIZED)
         return -1;
         return -1;
 
 
-    _width = width;
-    _height = height;
+    if (width == -1)
+        _width = Platform::getDisplayWidth();
+    else
+        _width = width;
+    
+    if (height == -1)
+        _height = Platform::getDisplayHeight();
+    else
+        _height = height;
 
 
     // Start up game systems.
     // Start up game systems.
     if (!startup())
     if (!startup())
@@ -251,13 +258,9 @@ void Game::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactI
 {
 {
 }
 }
 
 
-bool Game::mouseEvent(Mouse::MouseEvent evt, int x, int y)
+bool Game::mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
 {
 {
     return false;
     return false;
 }
 }
 
 
-void Game::mouseWheelEvent(int x, int y, int delta)
-{
-}
-
 }
 }

+ 4 - 12
gameplay/src/Game.h

@@ -96,8 +96,8 @@ public:
     /**
     /**
      * Call this method to initialize the game, and begin running the game.
      * Call this method to initialize the game, and begin running the game.
      *
      *
-     * @param width The width of the game window to run at.
-     * @param height The height of the game window to run at.
+     * @param width The width of the game window to run at. Default is -1 meaning native resolution width.
+     * @param height The height of the game window to run at. Default is -1 meaning native resolution height.
      * 
      * 
      * @return Zero for normal termination, or non-zero if an error occurred.
      * @return Zero for normal termination, or non-zero if an error occurred.
      */
      */
@@ -224,21 +224,13 @@ public:
      * @param evt The mouse event that occurred.
      * @param evt The mouse event that occurred.
      * @param x The x position of the mouse in pixels. Left edge is zero.
      * @param x The x position of the mouse in pixels. Left edge is zero.
      * @param y The y position of the mouse in pixels. Top edge is zero.
      * @param y The y position of the mouse in pixels. Top edge is zero.
+     * @param wheelDelta The number of mouse wheel ticks. Positive is up (forward), negative is down (backward).
      *
      *
      * @return True if the mouse event is consumed or false if it is not consumed.
      * @return True if the mouse event is consumed or false if it is not consumed.
      *
      *
      * @see Mouse::MouseEvent
      * @see Mouse::MouseEvent
      */
      */
-    virtual bool mouseEvent(Mouse::MouseEvent evt, int x, int y);
-
-    /**
-     * Mouse callback on mouse wheel events.
-     *
-     * @param x The x position of the mouse in pixels. Left edge is zero.
-     * @param y The y position of the mouse in pixels. Top edge is zero.
-     * @param delta The number of mouse wheel ticks. Positive is up (forward), negative is down (backward).
-     */
-    virtual void mouseWheelEvent(int x, int y, int delta);
+    virtual bool mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta);
 
 
     /**
     /**
      * Sets muli-touch is to be enabled/disabled. Default is disabled.
      * Sets muli-touch is to be enabled/disabled. Default is disabled.

+ 1 - 1
gameplay/src/Matrix.cpp

@@ -460,7 +460,7 @@ bool Matrix::decompose(Vector3* scale, Quaternion* rotation, Vector3* translatio
     // Now calculate the rotation from the resulting matrix (axes).
     // Now calculate the rotation from the resulting matrix (axes).
     float trace = xaxis.x + yaxis.y + zaxis.z + 1.0f;
     float trace = xaxis.x + yaxis.y + zaxis.z + 1.0f;
 
 
-    if (trace > MATH_TOLERANCE)
+    if (trace > MATH_EPSILON)
     {
     {
         float s = 0.5f / sqrt(trace);
         float s = 0.5f / sqrt(trace);
         rotation->w = 0.25f / s;
         rotation->w = 0.25f / s;

+ 9 - 9
gameplay/src/Matrix.h

@@ -831,7 +831,7 @@ public:
      * @param m The matrix to add.
      * @param m The matrix to add.
      * @return The matrix sum.
      * @return The matrix sum.
      */
      */
-    inline Matrix operator+(const Matrix& m) const;
+    inline const Matrix operator+(const Matrix& m) const;
     
     
     /**
     /**
      * Adds the given matrix to this matrix.
      * Adds the given matrix to this matrix.
@@ -842,14 +842,14 @@ public:
     inline Matrix& operator+=(const Matrix& m);
     inline Matrix& operator+=(const Matrix& m);
 
 
     /**
     /**
-     * Calculates the sum of this matrix with the given matrix.
+     * Calculates the difference of this matrix with the given matrix.
      * 
      * 
      * Note: this does not modify this matrix.
      * Note: this does not modify this matrix.
      * 
      * 
-     * @param m The matrix to add.
-     * @return The matrix sum.
+     * @param m The matrix to subtract.
+     * @return The matrix difference.
      */
      */
-    inline Matrix operator-(const Matrix& m) const;
+    inline const Matrix operator-(const Matrix& m) const;
 
 
     /**
     /**
      * Subtracts the given matrix from this matrix.
      * Subtracts the given matrix from this matrix.
@@ -866,7 +866,7 @@ public:
      * 
      * 
      * @return The negation of this matrix.
      * @return The negation of this matrix.
      */
      */
-    inline Matrix operator-() const;
+    inline const Matrix operator-() const;
 
 
     /**
     /**
      * Calculates the matrix product of this matrix with the given matrix.
      * Calculates the matrix product of this matrix with the given matrix.
@@ -876,7 +876,7 @@ public:
      * @param m The matrix to multiply by.
      * @param m The matrix to multiply by.
      * @return The matrix product.
      * @return The matrix product.
      */
      */
-    inline Matrix operator*(const Matrix& m) const;
+    inline const Matrix operator*(const Matrix& m) const;
 
 
     /**
     /**
      * Right-multiplies this matrix by the given matrix.
      * Right-multiplies this matrix by the given matrix.
@@ -907,7 +907,7 @@ inline Vector3& operator*=(Vector3& v, const Matrix& m);
  * @param v The vector to transform.
  * @param v The vector to transform.
  * @return The resulting transformed vector.
  * @return The resulting transformed vector.
  */
  */
-inline Vector3 operator*(const Matrix& m, const Vector3& v);
+inline const Vector3 operator*(const Matrix& m, const Vector3& v);
 
 
 /**
 /**
  * Transforms the given vector by the given matrix.
  * Transforms the given vector by the given matrix.
@@ -929,7 +929,7 @@ inline Vector4& operator*=(Vector4& v, const Matrix& m);
  * @param v The vector to transform.
  * @param v The vector to transform.
  * @return The resulting transformed vector.
  * @return The resulting transformed vector.
  */
  */
-inline Vector4 operator*(const Matrix& m, const Vector4& v);
+inline const Vector4 operator*(const Matrix& m, const Vector4& v);
 
 
 }
 }
 
 

+ 6 - 6
gameplay/src/Matrix.inl

@@ -3,7 +3,7 @@
 namespace gameplay
 namespace gameplay
 {
 {
 
 
-inline Matrix Matrix::operator+(const Matrix& m) const
+inline const Matrix Matrix::operator+(const Matrix& m) const
 {
 {
     Matrix result(*this);
     Matrix result(*this);
     result.add(m);
     result.add(m);
@@ -16,7 +16,7 @@ inline Matrix& Matrix::operator+=(const Matrix& m)
     return *this;
     return *this;
 }
 }
 
 
-inline Matrix Matrix::operator-(const Matrix& m) const
+inline const Matrix Matrix::operator-(const Matrix& m) const
 {
 {
     Matrix result(*this);
     Matrix result(*this);
     result.subtract(m);
     result.subtract(m);
@@ -29,14 +29,14 @@ inline Matrix& Matrix::operator-=(const Matrix& m)
     return *this;
     return *this;
 }
 }
 
 
-inline Matrix Matrix::operator-() const
+inline const Matrix Matrix::operator-() const
 {
 {
     Matrix m(*this);
     Matrix m(*this);
     m.negate();
     m.negate();
     return m;
     return m;
 }
 }
 
 
-inline Matrix Matrix::operator*(const Matrix& m) const
+inline const Matrix Matrix::operator*(const Matrix& m) const
 {
 {
     Matrix result(*this);
     Matrix result(*this);
     result.multiply(m);
     result.multiply(m);
@@ -55,7 +55,7 @@ inline Vector3& operator*=(Vector3& v, const Matrix& m)
     return v;
     return v;
 }
 }
 
 
-inline Vector3 operator*(const Matrix& m, const Vector3& v)
+inline const Vector3 operator*(const Matrix& m, const Vector3& v)
 {
 {
     Vector3 x;
     Vector3 x;
     m.transformVector(v, &x);
     m.transformVector(v, &x);
@@ -68,7 +68,7 @@ inline Vector4& operator*=(Vector4& v, const Matrix& m)
     return v;
     return v;
 }
 }
 
 
-inline Vector4 operator*(const Matrix& m, const Vector4& v)
+inline const Vector4 operator*(const Matrix& m, const Vector4& v)
 {
 {
     Vector4 x;
     Vector4 x;
     m.transformVector(v, &x);
     m.transformVector(v, &x);

+ 8 - 7
gameplay/src/Mouse.h

@@ -16,13 +16,14 @@ public:
      */
      */
     enum MouseEvent
     enum MouseEvent
     {
     {
-        MOUSE_LEFT_BUTTON_PRESS,
-        MOUSE_LEFT_BUTTON_RELEASE,
-        MOUSE_MIDDLE_BUTTON_PRESS,
-        MOUSE_MIDDLE_BUTTON_RELEASE,
-        MOUSE_RIGHT_BUTTON_PRESS,
-        MOUSE_RIGHT_BUTTON_RELEASE,
-        MOUSE_MOVE
+        MOUSE_PRESS_LEFT_BUTTON,
+        MOUSE_RELEASE_LEFT_BUTTON,
+        MOUSE_PRESS_MIDDLE_BUTTON,
+        MOUSE_RELEASE_MIDDLE_BUTTON,
+        MOUSE_PRESS_RIGHT_BUTTON,
+        MOUSE_RELEASE_RIGHT_BUTTON,
+        MOUSE_MOVE,
+        MOUSE_WHEEL
     };
     };
 
 
 
 

+ 2 - 2
gameplay/src/Package.cpp

@@ -1089,7 +1089,7 @@ Mesh* Package::loadMesh(const char* id, bool loadWithMeshRBSupport, const char*
     }
     }
     mesh->setVertexData(vertexData, 0, vertexCount);
     mesh->setVertexData(vertexData, 0, vertexCount);
     if (loadWithMeshRBSupport)
     if (loadWithMeshRBSupport)
-        SceneLoader::addMeshRigidBodyData(nodeId, mesh, vertexData, vertexByteCount);
+        SceneLoader::addMeshRigidBodyData(_path, nodeId, mesh, vertexData, vertexByteCount);
     SAFE_DELETE_ARRAY(vertexData);
     SAFE_DELETE_ARRAY(vertexData);
 
 
     // Set mesh bounding volumes
     // Set mesh bounding volumes
@@ -1150,7 +1150,7 @@ Mesh* Package::loadMesh(const char* id, bool loadWithMeshRBSupport, const char*
         }
         }
         part->setIndexData(indexData, 0, indexCount);
         part->setIndexData(indexData, 0, indexCount);
         if (loadWithMeshRBSupport)
         if (loadWithMeshRBSupport)
-            SceneLoader::addMeshRigidBodyData(nodeId, indexData, iByteCount);
+            SceneLoader::addMeshRigidBodyData(_path, nodeId, indexData, iByteCount);
         SAFE_DELETE_ARRAY(indexData);
         SAFE_DELETE_ARRAY(indexData);
     }
     }
 
 

+ 1 - 1
gameplay/src/PhysicsConstraint.cpp

@@ -118,7 +118,7 @@ btTransform PhysicsConstraint::getTransformOffset(const Node* node, const Vector
     
     
     t = offsetByCenterOfMass(node, t);
     t = offsetByCenterOfMass(node, t);
 
 
-    return btTransform(btQuaternion(r.x, r.y, r.z, r.w), btVector3(t.x, t.y, t.z));
+    return btTransform(r, t);
 }
 }
 
 
 Vector3 PhysicsConstraint::getWorldCenterOfMass(const Model* model)
 Vector3 PhysicsConstraint::getWorldCenterOfMass(const Model* model)

+ 146 - 51
gameplay/src/PhysicsController.cpp

@@ -11,6 +11,10 @@
 namespace gameplay
 namespace gameplay
 {
 {
 
 
+const int PhysicsController::DIRTY         = 0x01;
+const int PhysicsController::COLLISION     = 0x02;
+const int PhysicsController::REGISTERED    = 0x04;
+
 PhysicsController::PhysicsController()
 PhysicsController::PhysicsController()
   : _collisionConfiguration(NULL), _dispatcher(NULL),
   : _collisionConfiguration(NULL), _dispatcher(NULL),
     _overlappingPairCache(NULL), _solver(NULL), _world(NULL), _debugDrawer(NULL), 
     _overlappingPairCache(NULL), _solver(NULL), _world(NULL), _debugDrawer(NULL), 
@@ -114,7 +118,7 @@ void PhysicsController::setGravity(const Vector3& gravity)
     _gravity = gravity;
     _gravity = gravity;
 
 
     if (_world)
     if (_world)
-        _world->setGravity(btVector3(_gravity.x, _gravity.y, _gravity.z));
+        _world->setGravity(_gravity);
 }
 }
 
 
 void PhysicsController::drawDebug(const Matrix& viewProjection)
 void PhysicsController::drawDebug(const Matrix& viewProjection)
@@ -124,6 +128,83 @@ void PhysicsController::drawDebug(const Matrix& viewProjection)
     _debugDrawer->end();
     _debugDrawer->end();
 }
 }
 
 
+PhysicsRigidBody* PhysicsController::rayTest(const Ray& ray)
+{
+    btCollisionWorld::ClosestRayResultCallback callback(ray.getOrigin(), ray.getDirection());
+    _world->rayTest(ray.getOrigin(), ray.getDirection(), callback);
+    if (callback.hasHit())
+        return getRigidBody(callback.m_collisionObject);
+
+    return NULL;
+}
+
+btScalar PhysicsController::addSingleResult(btManifoldPoint& cp, const btCollisionObject* a, int partIdA, int indexA, 
+    const btCollisionObject* b, int partIdB, int indexB)
+{
+    // Get pointers to the PhysicsRigidBody objects.
+    PhysicsRigidBody* rbA = Game::getInstance()->getPhysicsController()->getRigidBody(a);
+    PhysicsRigidBody* rbB = Game::getInstance()->getPhysicsController()->getRigidBody(b);
+    
+    // If the given rigid body pair has collided in the past, then
+    // we notify the listeners only if the pair was not colliding
+    // during the previous frame. Otherwise, it's a new pair, so add a
+    // new entry to the cache with the appropriate listeners and notify them.
+    PhysicsRigidBody::CollisionPair pair(rbA, rbB);
+    if (_collisionStatus.count(pair) > 0)
+    {
+        const CollisionInfo& collisionInfo = _collisionStatus[pair];
+        if ((collisionInfo._status & COLLISION) == 0)
+        {
+            std::vector<PhysicsRigidBody::Listener*>::const_iterator iter = collisionInfo._listeners.begin();
+            for (; iter != collisionInfo._listeners.end(); iter++)
+            {
+                (*iter)->collisionEvent(PhysicsRigidBody::Listener::COLLIDING, pair, Vector3(cp.getPositionWorldOnA().x(), cp.getPositionWorldOnA().y(), cp.getPositionWorldOnA().z()),
+                    Vector3(cp.getPositionWorldOnB().x(), cp.getPositionWorldOnB().y(), cp.getPositionWorldOnB().z()));
+            }
+        }
+    }
+    else
+    {
+        CollisionInfo& collisionInfo = _collisionStatus[pair];
+
+        // Add the appropriate listeners.
+        PhysicsRigidBody::CollisionPair p1(pair._rbA, NULL);
+        if (_collisionStatus.count(p1) > 0)
+        {
+            const CollisionInfo& ci = _collisionStatus[p1];
+            std::vector<PhysicsRigidBody::Listener*>::const_iterator iter = ci._listeners.begin();
+            for (; iter != ci._listeners.end(); iter++)
+            {
+                collisionInfo._listeners.push_back(*iter);
+            }
+        }
+        PhysicsRigidBody::CollisionPair p2(pair._rbB, NULL);
+        if (_collisionStatus.count(p2) > 0)
+        {
+            const CollisionInfo& ci = _collisionStatus[p2];
+            std::vector<PhysicsRigidBody::Listener*>::const_iterator iter = ci._listeners.begin();
+            for (; iter != ci._listeners.end(); iter++)
+            {
+                collisionInfo._listeners.push_back(*iter);
+            }
+        }
+
+        std::vector<PhysicsRigidBody::Listener*>::iterator iter = collisionInfo._listeners.begin();
+        for (; iter != collisionInfo._listeners.end(); iter++)
+        {
+            (*iter)->collisionEvent(PhysicsRigidBody::Listener::COLLIDING, pair, Vector3(cp.getPositionWorldOnA().x(), cp.getPositionWorldOnA().y(), cp.getPositionWorldOnA().z()),
+                Vector3(cp.getPositionWorldOnB().x(), cp.getPositionWorldOnB().y(), cp.getPositionWorldOnB().z()));
+        }
+    }
+
+    // Update the collision status cache (we remove the dirty bit
+    // set in the controller's update so that this particular collision pair's
+    // status is not reset to 'no collision' when the controller's update completes).
+    _collisionStatus[pair]._status &= ~DIRTY;
+    _collisionStatus[pair]._status |= COLLISION;
+    return 0.0f;
+}
+
 void PhysicsController::initialize()
 void PhysicsController::initialize()
 {
 {
     _collisionConfiguration = new btDefaultCollisionConfiguration();
     _collisionConfiguration = new btDefaultCollisionConfiguration();
@@ -133,7 +214,7 @@ void PhysicsController::initialize()
 
 
     // Create the world.
     // Create the world.
     _world = new btDiscreteDynamicsWorld(_dispatcher, _overlappingPairCache, _solver, _collisionConfiguration);
     _world = new btDiscreteDynamicsWorld(_dispatcher, _overlappingPairCache, _solver, _collisionConfiguration);
-    _world->setGravity(btVector3(_gravity.x, _gravity.y, _gravity.z));
+    _world->setGravity(_gravity);
 
 
     // Set up debug drawing.
     // Set up debug drawing.
     _debugDrawer = new DebugDrawer();
     _debugDrawer = new DebugDrawer();
@@ -217,67 +298,57 @@ void PhysicsController::update(long elapsedTime)
     // set to COLLISION and the DIRTY bit is cleared. Then, after collision processing 
     // set to COLLISION and the DIRTY bit is cleared. Then, after collision processing 
     // is finished, if a given status is still dirty, the COLLISION bit is cleared.
     // is finished, if a given status is still dirty, the COLLISION bit is cleared.
 
 
-    // Dirty all the collision listeners' collision status caches.
-    for (unsigned int i = 0; i < _bodies.size(); i++)
+    // Dirty the collision status cache entries.
+    std::map<PhysicsRigidBody::CollisionPair, CollisionInfo>::iterator iter = _collisionStatus.begin();
+    for (; iter != _collisionStatus.end(); iter++)
     {
     {
-        if (_bodies[i]->_listeners)
-        {
-            for (unsigned int k = 0; k < _bodies[i]->_listeners->size(); k++)
-            {
-                std::map<PhysicsRigidBody::CollisionPair, int>::iterator iter = (*_bodies[i]->_listeners)[k]->_collisionStatus.begin();
-                for (; iter != (*_bodies[i]->_listeners)[k]->_collisionStatus.end(); iter++)
-                {
-                    iter->second |= PhysicsRigidBody::Listener::DIRTY;
-                }
-            }
-        }
+        iter->second._status |= DIRTY;
     }
     }
 
 
-    // Go through the physics rigid bodies and update the collision listeners.
-    for (unsigned int i = 0; i < _bodies.size(); i++)
+    // Go through the collision status cache and perform all registered collision tests.
+    iter = _collisionStatus.begin();
+    for (; iter != _collisionStatus.end(); iter++)
     {
     {
-        if (_bodies[i]->_listeners)
+        // If this collision pair was one that was registered for listening, then perform the collision test.
+        // (In the case where we register for all collisions with a rigid body, there will be a lot
+        // of collision pairs in the status cache that we did not explicitly register for.)
+        if ((iter->second._status & REGISTERED) != 0)
         {
         {
-            for (unsigned int k = 0; k < _bodies[i]->_listeners->size(); k++)
-            {
-                std::map<PhysicsRigidBody::CollisionPair, int>::iterator iter = (*_bodies[i]->_listeners)[k]->_collisionStatus.begin();
-                for (; iter != (*_bodies[i]->_listeners)[k]->_collisionStatus.end(); iter++)
-                {
-                    // If this collision pair was one that was registered for listening, then perform the collision test.
-                    // (In the case where we register for all collisions with a rigid body, there will be a lot
-                    // of collision pairs in the status cache that we did not explicitly register for.)
-                    if ((iter->second & PhysicsRigidBody::Listener::REGISTERED) != 0)
-                    {
-                        if (iter->first._rbB)
-                            Game::getInstance()->getPhysicsController()->_world->contactPairTest(iter->first._rbA->_body, iter->first._rbB->_body, *(*_bodies[i]->_listeners)[k]);
-                        else
-                            Game::getInstance()->getPhysicsController()->_world->contactTest(iter->first._rbA->_body, *(*_bodies[i]->_listeners)[k]);
-                    }
-                }   
-            }
+            if (iter->first._rbB)
+                _world->contactPairTest(iter->first._rbA->_body, iter->first._rbB->_body, *this);
+            else
+                _world->contactTest(iter->first._rbA->_body, *this);
         }
         }
     }
     }
 
 
-    // Go through all the collision listeners and update their collision status caches.
-    for (unsigned int i = 0; i < _bodies.size(); i++)
+    // Update all the collision status cache entries.
+    iter = _collisionStatus.begin();
+    for (; iter != _collisionStatus.end(); iter++)
     {
     {
-        if (_bodies[i]->_listeners)
+        if ((iter->second._status & DIRTY) != 0)
         {
         {
-            for (unsigned int k = 0; k < _bodies[i]->_listeners->size(); k++)
+            if ((iter->second._status & COLLISION) != 0 && iter->first._rbB)
             {
             {
-                std::map<PhysicsRigidBody::CollisionPair, int>::iterator iter = (*_bodies[i]->_listeners)[k]->_collisionStatus.begin();
-                for (; iter != (*_bodies[i]->_listeners)[k]->_collisionStatus.end(); iter++)
+                unsigned int size = iter->second._listeners.size();
+                for (unsigned int i = 0; i < size; i++)
                 {
                 {
-                    if ((iter->second & PhysicsRigidBody::Listener::DIRTY) != 0)
-                    {
-                        iter->second &= ~PhysicsRigidBody::Listener::COLLISION;
-                    }
+                    iter->second._listeners[i]->collisionEvent(PhysicsRigidBody::Listener::NOT_COLLIDING, iter->first);
                 }
                 }
             }
             }
+
+            iter->second._status &= ~COLLISION;
         }
         }
     }
     }
 }
 }
-    
+
+void PhysicsController::addCollisionListener(PhysicsRigidBody::Listener* listener, PhysicsRigidBody* rbA, PhysicsRigidBody* rbB)
+{
+    // Add the listener and ensure the status includes that this collision pair is registered.
+    PhysicsRigidBody::CollisionPair pair(rbA, rbB);
+    _collisionStatus[pair]._listeners.push_back(listener);
+    if ((_collisionStatus[pair]._status & PhysicsController::REGISTERED) == 0)
+        _collisionStatus[pair]._status |= PhysicsController::REGISTERED;
+}
 
 
 void PhysicsController::addRigidBody(PhysicsRigidBody* body)
 void PhysicsController::addRigidBody(PhysicsRigidBody* body)
 {
 {
@@ -311,8 +382,32 @@ void PhysicsController::removeRigidBody(PhysicsRigidBody* rigidBody)
             else
             else
                 _shapes[i]->release();
                 _shapes[i]->release();
 
 
-            return;
+            break;
+        }
+    }
+
+    // Remove the rigid body from the controller's list.
+    for (unsigned int i = 0; i < _bodies.size(); i++)
+    {
+        if (_bodies[i] == rigidBody)
+        {
+            _bodies.erase(_bodies.begin() + i);
+            break;
+        }
+    }
+
+    // Find all references to the rigid body in the collision status cache and remove them.
+    std::map<PhysicsRigidBody::CollisionPair, CollisionInfo>::iterator iter = _collisionStatus.begin();
+    for (; iter != _collisionStatus.end();)
+    {
+        if (iter->first._rbA == rigidBody || iter->first._rbB == rigidBody)
+        {
+            std::map<PhysicsRigidBody::CollisionPair, CollisionInfo>::iterator eraseIter = iter;
+            iter++;
+            _collisionStatus.erase(eraseIter);
         }
         }
+        else
+            iter++;
     }
     }
 }
 }
 
 
@@ -407,14 +502,14 @@ btCollisionShape* PhysicsController::createSphere(float radius, const btVector3&
     return sphere;
     return sphere;
 }
 }
 
 
-btCollisionShape* PhysicsController::createMesh(PhysicsRigidBody* body)
+btCollisionShape* PhysicsController::createMesh(PhysicsRigidBody* body, const Vector3& scale)
 {
 {
     // Retrieve the mesh rigid body data from the loaded scene.
     // Retrieve the mesh rigid body data from the loaded scene.
     const SceneLoader::MeshRigidBodyData* data = SceneLoader::getMeshRigidBodyData(body->_node->getId());
     const SceneLoader::MeshRigidBodyData* data = SceneLoader::getMeshRigidBodyData(body->_node->getId());
 
 
     // Copy the scaled vertex position data to the rigid body's local buffer.
     // Copy the scaled vertex position data to the rigid body's local buffer.
     Matrix m;
     Matrix m;
-    Matrix::createScale(body->_node->getScaleX(), body->_node->getScaleY(), body->_node->getScaleZ(), &m);
+    Matrix::createScale(scale, &m);
     unsigned int vertexCount = data->mesh->getVertexCount();
     unsigned int vertexCount = data->mesh->getVertexCount();
     body->_vertexData = new float[vertexCount * 3];
     body->_vertexData = new float[vertexCount * 3];
     Vector3 v;
     Vector3 v;
@@ -467,7 +562,7 @@ btCollisionShape* PhysicsController::createMesh(PhysicsRigidBody* body)
             indexedMesh.m_numTriangles = meshPart->getIndexCount() / 3;
             indexedMesh.m_numTriangles = meshPart->getIndexCount() / 3;
             indexedMesh.m_numVertices = meshPart->getIndexCount();
             indexedMesh.m_numVertices = meshPart->getIndexCount();
             indexedMesh.m_triangleIndexBase = (const unsigned char*)body->_indexData[i];
             indexedMesh.m_triangleIndexBase = (const unsigned char*)body->_indexData[i];
-            indexedMesh.m_triangleIndexStride = indexStride;
+            indexedMesh.m_triangleIndexStride = indexStride*3;
             indexedMesh.m_vertexBase = (const unsigned char*)body->_vertexData;
             indexedMesh.m_vertexBase = (const unsigned char*)body->_vertexData;
             indexedMesh.m_vertexStride = sizeof(float)*3;
             indexedMesh.m_vertexStride = sizeof(float)*3;
             indexedMesh.m_vertexType = PHY_FLOAT;
             indexedMesh.m_vertexType = PHY_FLOAT;
@@ -664,4 +759,4 @@ int	PhysicsController::DebugDrawer::getDebugMode() const
     return _mode;
     return _mode;
 }
 }
 
 
-}
+}

+ 35 - 3
gameplay/src/PhysicsController.h

@@ -15,7 +15,7 @@ namespace gameplay
 /**
 /**
  * Defines a class for controlling game physics.
  * Defines a class for controlling game physics.
  */
  */
-class PhysicsController
+class PhysicsController : public btCollisionWorld::ContactResultCallback
 {
 {
     friend class Game;
     friend class Game;
     friend class PhysicsConstraint;
     friend class PhysicsConstraint;
@@ -189,8 +189,36 @@ public:
      */
      */
     void drawDebug(const Matrix& viewProjection);
     void drawDebug(const Matrix& viewProjection);
 
 
+    /**
+     * Gets the first rigid body that the given ray intersects.
+     * 
+     * @param ray The ray to test intersection with.
+     * @return The first rigid body that the ray intersects.
+     */
+    PhysicsRigidBody* rayTest(const Ray& ray);
+
+protected:
+
+    /**
+     * Internal function used for Bullet integration (do not use or override).
+     */
+    btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* a, int partIdA, int indexA, const btCollisionObject* b, int partIdB, int indexB);    
+
 private:
 private:
 
 
+    // Internal constants for the collision status cache.
+    static const int DIRTY;
+    static const int COLLISION;
+    static const int REGISTERED;
+
+    // Represents the collision listeners and status for a given collision pair (used by the collision status cache).
+    struct CollisionInfo
+    {
+        std::vector<PhysicsRigidBody::Listener*> _listeners;
+        int _status;
+    };
+
+    // Wraps Bullet collision shapes (used for implementing shape caching).
     struct PhysicsCollisionShape : public Ref
     struct PhysicsCollisionShape : public Ref
     {
     {
         PhysicsCollisionShape(btCollisionShape* shape) : _shape(shape) {}
         PhysicsCollisionShape(btCollisionShape* shape) : _shape(shape) {}
@@ -234,6 +262,9 @@ private:
      */
      */
     void update(long elapsedTime);
     void update(long elapsedTime);
 
 
+    // Adds the given collision listener for the two given rigid bodies.
+    void addCollisionListener(PhysicsRigidBody::Listener* listener, PhysicsRigidBody* rbA, PhysicsRigidBody* rbB);
+
     // Adds the given rigid body to the world.
     // Adds the given rigid body to the world.
     void addRigidBody(PhysicsRigidBody* body);
     void addRigidBody(PhysicsRigidBody* body);
     
     
@@ -253,7 +284,7 @@ private:
     btCollisionShape* createSphere(float radius, const btVector3& scale);
     btCollisionShape* createSphere(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* createMesh(PhysicsRigidBody* body);
+    btCollisionShape* createMesh(PhysicsRigidBody* body, const Vector3& scale);
 
 
     // Sets up the given constraint for the given two rigid bodies.
     // Sets up the given constraint for the given two rigid bodies.
     void addConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b, PhysicsConstraint* constraint);
     void addConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b, PhysicsConstraint* constraint);
@@ -308,8 +339,9 @@ private:
     std::vector<Listener*>* _listeners;
     std::vector<Listener*>* _listeners;
     std::vector<PhysicsRigidBody*> _bodies;
     std::vector<PhysicsRigidBody*> _bodies;
     Vector3 _gravity;
     Vector3 _gravity;
+    std::map<PhysicsRigidBody::CollisionPair, CollisionInfo> _collisionStatus;  
 };
 };
 
 
 }
 }
 
 
-#endif
+#endif

+ 3 - 3
gameplay/src/PhysicsGenericConstraint.cpp

@@ -45,13 +45,13 @@ PhysicsGenericConstraint::PhysicsGenericConstraint(PhysicsRigidBody* a, const Qu
         b->getNode()->getWorldMatrix().getScale(&sB);
         b->getNode()->getWorldMatrix().getScale(&sB);
         Vector3 tB(translationOffsetB.x * sB.x, translationOffsetB.y * sB.y, translationOffsetB.z * sB.z);
         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));
+        btTransform frameInA(rotationOffsetA, tA);
+        btTransform frameInB(rotationOffsetB, tB);
         _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(tA.x, tA.y, tA.z));
+        btTransform frameInA(rotationOffsetA, tA);
         _constraint = new btGeneric6DofConstraint(*a->_body, frameInA, true);
         _constraint = new btGeneric6DofConstraint(*a->_body, frameInA, true);
     }
     }
 }
 }

+ 8 - 8
gameplay/src/PhysicsGenericConstraint.inl

@@ -45,42 +45,42 @@ inline const Vector3& PhysicsGenericConstraint::getTranslationOffsetB() const
 
 
 inline void PhysicsGenericConstraint::setAngularLowerLimit(const Vector3& limits)
 inline void PhysicsGenericConstraint::setAngularLowerLimit(const Vector3& limits)
 {
 {
-    ((btGeneric6DofConstraint*)_constraint)->setAngularLowerLimit(btVector3(limits.x, limits.y, limits.z));
+    ((btGeneric6DofConstraint*)_constraint)->setAngularLowerLimit(limits);
 }
 }
 
 
 inline void PhysicsGenericConstraint::setAngularUpperLimit(const Vector3& limits)
 inline void PhysicsGenericConstraint::setAngularUpperLimit(const Vector3& limits)
 {
 {
-    ((btGeneric6DofConstraint*)_constraint)->setAngularUpperLimit(btVector3(limits.x, limits.y, limits.z));
+    ((btGeneric6DofConstraint*)_constraint)->setAngularUpperLimit(limits);
 }
 }
 
 
 inline void PhysicsGenericConstraint::setLinearLowerLimit(const Vector3& limits)
 inline void PhysicsGenericConstraint::setLinearLowerLimit(const Vector3& limits)
 {
 {
-    ((btGeneric6DofConstraint*)_constraint)->setLinearLowerLimit(btVector3(limits.x, limits.y, limits.z));
+    ((btGeneric6DofConstraint*)_constraint)->setLinearLowerLimit(limits);
 }
 }
     
     
 inline void PhysicsGenericConstraint::setLinearUpperLimit(const Vector3& limits)
 inline void PhysicsGenericConstraint::setLinearUpperLimit(const Vector3& limits)
 {
 {
-    ((btGeneric6DofConstraint*)_constraint)->setLinearUpperLimit(btVector3(limits.x, limits.y, limits.z));
+    ((btGeneric6DofConstraint*)_constraint)->setLinearUpperLimit(limits);
 }
 }
 
 
 inline void PhysicsGenericConstraint::setRotationOffsetA(const Quaternion& rotationOffset)
 inline void PhysicsGenericConstraint::setRotationOffsetA(const Quaternion& rotationOffset)
 {
 {
-    static_cast<btGeneric6DofConstraint*>(_constraint)->getFrameOffsetA().setRotation(btQuaternion(rotationOffset.x, rotationOffset.y, rotationOffset.z, rotationOffset.w));
+    static_cast<btGeneric6DofConstraint*>(_constraint)->getFrameOffsetA().setRotation(rotationOffset);
 }
 }
 
 
 inline void PhysicsGenericConstraint::setRotationOffsetB(const Quaternion& rotationOffset)
 inline void PhysicsGenericConstraint::setRotationOffsetB(const Quaternion& rotationOffset)
 {
 {
-    static_cast<btGeneric6DofConstraint*>(_constraint)->getFrameOffsetB().setRotation(btQuaternion(rotationOffset.x, rotationOffset.y, rotationOffset.z, rotationOffset.w));
+    static_cast<btGeneric6DofConstraint*>(_constraint)->getFrameOffsetB().setRotation(rotationOffset);
 }
 }
 
 
 inline void PhysicsGenericConstraint::setTranslationOffsetA(const Vector3& translationOffset)
 inline void PhysicsGenericConstraint::setTranslationOffsetA(const Vector3& translationOffset)
 {
 {
-    static_cast<btGeneric6DofConstraint*>(_constraint)->getFrameOffsetA().setOrigin(btVector3(translationOffset.x, translationOffset.y, translationOffset.z));
+    static_cast<btGeneric6DofConstraint*>(_constraint)->getFrameOffsetA().setOrigin(translationOffset);
 }
 }
 
 
 inline void PhysicsGenericConstraint::setTranslationOffsetB(const Vector3& translationOffset)
 inline void PhysicsGenericConstraint::setTranslationOffsetB(const Vector3& translationOffset)
 {
 {
-    static_cast<btGeneric6DofConstraint*>(_constraint)->getFrameOffsetB().setOrigin(btVector3(translationOffset.x, translationOffset.y, translationOffset.z));
+    static_cast<btGeneric6DofConstraint*>(_constraint)->getFrameOffsetB().setOrigin(translationOffset);
 }
 }
 
 
 }
 }

+ 3 - 3
gameplay/src/PhysicsHingeConstraint.cpp

@@ -27,13 +27,13 @@ PhysicsHingeConstraint::PhysicsHingeConstraint(PhysicsRigidBody* a, const Quater
         b->getNode()->getWorldMatrix().getScale(&sB);
         b->getNode()->getWorldMatrix().getScale(&sB);
         Vector3 tB(translationOffsetB.x * sB.x, translationOffsetB.y * sB.y, translationOffsetB.z * sB.z);
         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));
+        btTransform frameInA(rotationOffsetA, tA);
+        btTransform frameInB(rotationOffsetB, tB);
         _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(tA.x, tA.y, tA.z));
+        btTransform frameInA(rotationOffsetA, tA);
         _constraint = new btHingeConstraint(*a->_body, frameInA);
         _constraint = new btHingeConstraint(*a->_body, frameInA);
     }
     }
 }
 }

+ 4 - 5
gameplay/src/PhysicsMotionState.cpp

@@ -9,7 +9,7 @@ PhysicsMotionState::PhysicsMotionState(Node* node, const Vector3* centerOfMassOf
     if (centerOfMassOffset)
     if (centerOfMassOffset)
     {
     {
         // Store the center of mass offset.
         // Store the center of mass offset.
-        _centerOfMassOffset.setOrigin(btVector3(centerOfMassOffset->x, centerOfMassOffset->y, centerOfMassOffset->z));
+        _centerOfMassOffset.setOrigin(*centerOfMassOffset);
     }
     }
 
 
     updateTransformFromNode();
     updateTransformFromNode();
@@ -49,17 +49,16 @@ void PhysicsMotionState::updateTransformFromNode() const
     {
     {
         // When there is a center of mass offset, we modify the initial world transformation
         // When there is a center of mass offset, we modify the initial world transformation
         // so that when physics is initially applied, the object is in the correct location.
         // so that when physics is initially applied, the object is in the correct location.
-        btQuaternion orientation(rotation.x, rotation.y, rotation.z, rotation.w);
-        btTransform offset = btTransform(orientation, btVector3(0.0f, 0.0f, 0.0f)) * _centerOfMassOffset.inverse();
+        btTransform offset = btTransform(rotation, btVector3(0.0f, 0.0f, 0.0f)) * _centerOfMassOffset.inverse();
 
 
         btVector3 origin(m.m[12] + _centerOfMassOffset.getOrigin().getX() + offset.getOrigin().getX(), 
         btVector3 origin(m.m[12] + _centerOfMassOffset.getOrigin().getX() + offset.getOrigin().getX(), 
                          m.m[13] + _centerOfMassOffset.getOrigin().getY() + offset.getOrigin().getY(), 
                          m.m[13] + _centerOfMassOffset.getOrigin().getY() + offset.getOrigin().getY(), 
                          m.m[14] + _centerOfMassOffset.getOrigin().getZ() + offset.getOrigin().getZ());
                          m.m[14] + _centerOfMassOffset.getOrigin().getZ() + offset.getOrigin().getZ());
-        _worldTransform = btTransform(orientation, origin);
+        _worldTransform = btTransform(rotation, origin);
     }
     }
     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(rotation, btVector3(m.m[12], m.m[13], m.m[14]));
     }
     }
 }
 }
 
 

+ 26 - 52
gameplay/src/PhysicsRigidBody.cpp

@@ -10,10 +10,6 @@
 namespace gameplay
 namespace gameplay
 {
 {
 
 
-const int PhysicsRigidBody::Listener::DIRTY         = 0x01;
-const int PhysicsRigidBody::Listener::COLLISION     = 0x02;
-const int PhysicsRigidBody::Listener::REGISTERED    = 0x04;
-
 // Internal values used for creating mesh, heightfield, and capsule rigid bodies.
 // Internal values used for creating mesh, heightfield, and capsule rigid bodies.
 #define SHAPE_MESH ((PhysicsRigidBody::Type)(PhysicsRigidBody::SHAPE_NONE + 1))
 #define SHAPE_MESH ((PhysicsRigidBody::Type)(PhysicsRigidBody::SHAPE_NONE + 1))
 #define SHAPE_HEIGHTFIELD ((PhysicsRigidBody::Type)(PhysicsRigidBody::SHAPE_NONE + 2))
 #define SHAPE_HEIGHTFIELD ((PhysicsRigidBody::Type)(PhysicsRigidBody::SHAPE_NONE + 2))
@@ -28,33 +24,40 @@ PhysicsRigidBody::PhysicsRigidBody(Node* node, PhysicsRigidBody::Type type, floa
         _anisotropicFriction(NULL), _gravity(NULL), _linearVelocity(NULL), _vertexData(NULL),
         _anisotropicFriction(NULL), _gravity(NULL), _linearVelocity(NULL), _vertexData(NULL),
         _indexData(NULL), _heightfieldData(NULL), _inverse(NULL), _inverseIsDirty(true)
         _indexData(NULL), _heightfieldData(NULL), _inverse(NULL), _inverseIsDirty(true)
 {
 {
+    // Get the node's world scale (we need to apply this during creation since rigid bodies don't scale dynamically).
+    Vector3 scale;
+    node->getWorldMatrix().getScale(&scale);
+
     switch (type)
     switch (type)
     {
     {
         case SHAPE_BOX:
         case SHAPE_BOX:
         {
         {
             const BoundingBox& box = node->getModel()->getMesh()->getBoundingBox();
             const BoundingBox& box = node->getModel()->getMesh()->getBoundingBox();
-            _shape = Game::getInstance()->getPhysicsController()->createBox(box.min, box.max, btVector3(node->getScaleX(), node->getScaleY(), node->getScaleZ()));
+            _shape = Game::getInstance()->getPhysicsController()->createBox(box.min, box.max, scale);
             break;
             break;
         }
         }
         case SHAPE_SPHERE:
         case SHAPE_SPHERE:
         {
         {
             const BoundingSphere& sphere = node->getModel()->getMesh()->getBoundingSphere();
             const BoundingSphere& sphere = node->getModel()->getMesh()->getBoundingSphere();
-            _shape = Game::getInstance()->getPhysicsController()->createSphere(sphere.radius, btVector3(node->getScaleX(), node->getScaleY(), node->getScaleZ()));
+            _shape = Game::getInstance()->getPhysicsController()->createSphere(sphere.radius, scale);
             break;
             break;
         }
         }
         case SHAPE_MESH:
         case SHAPE_MESH:
         {
         {
-            _shape = Game::getInstance()->getPhysicsController()->createMesh(this);
+            _shape = Game::getInstance()->getPhysicsController()->createMesh(this, scale);
             break;
             break;
         }
         }
     }
     }
 
 
     // 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(node->getModel()->getMesh()->getBoundingSphere().center);
     Vector3 c(node->getModel()->getMesh()->getBoundingSphere().center);
+    c.x *= scale.x;
+    c.y *= scale.y;
+    c.z *= scale.z;
     c.negate();
     c.negate();
 
 
-    // Create the Bullet rigid body.
-    if (c.lengthSquared() > MATH_EPSILON)
+    // Create the Bullet rigid body (we don't apply center of mass offsets on mesh rigid bodies).
+    if (c.lengthSquared() > MATH_EPSILON && type != SHAPE_MESH)
         _body = createRigidBodyInternal(_shape, mass, node, friction, restitution, linearDamping, angularDamping, &c);
         _body = createRigidBodyInternal(_shape, mass, node, friction, restitution, linearDamping, angularDamping, &c);
     else
     else
         _body = createRigidBodyInternal(_shape, mass, node, friction, restitution, linearDamping, angularDamping);
         _body = createRigidBodyInternal(_shape, mass, node, friction, restitution, linearDamping, angularDamping);
@@ -151,11 +154,18 @@ PhysicsRigidBody::PhysicsRigidBody(Node* node, float radius, float height, float
         _anisotropicFriction(NULL), _gravity(NULL), _linearVelocity(NULL), _vertexData(NULL),
         _anisotropicFriction(NULL), _gravity(NULL), _linearVelocity(NULL), _vertexData(NULL),
         _indexData(NULL), _heightfieldData(NULL), _inverse(NULL), _inverseIsDirty(true)
         _indexData(NULL), _heightfieldData(NULL), _inverse(NULL), _inverseIsDirty(true)
 {
 {
+    // Get the node's world scale (we need to apply this during creation since rigid bodies don't scale dynamically).
+    Vector3 scale;
+    node->getWorldMatrix().getScale(&scale);
+
     // Create the capsule collision shape.
     // Create the capsule collision shape.
     _shape = Game::getInstance()->getPhysicsController()->createCapsule(radius, height);
     _shape = Game::getInstance()->getPhysicsController()->createCapsule(radius, height);
 
 
     // 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(node->getModel()->getMesh()->getBoundingSphere().center);
     Vector3 c(node->getModel()->getMesh()->getBoundingSphere().center);
+    c.x *= scale.x;
+    c.y *= scale.y;
+    c.z *= scale.z;
     c.negate();
     c.negate();
 
 
     // Create the Bullet rigid body.
     // Create the Bullet rigid body.
@@ -205,13 +215,7 @@ PhysicsRigidBody::~PhysicsRigidBody()
 
 
 void PhysicsRigidBody::addCollisionListener(Listener* listener, PhysicsRigidBody* body)
 void PhysicsRigidBody::addCollisionListener(Listener* listener, PhysicsRigidBody* body)
 {
 {
-    if (!_listeners)
-        _listeners = new std::vector<Listener*>();
-
-    CollisionPair pair(this, body);
-    listener->_collisionStatus[pair] = PhysicsRigidBody::Listener::REGISTERED;
-
-    _listeners->push_back(listener);
+    Game::getInstance()->getPhysicsController()->addCollisionListener(listener, this, body);
 }
 }
 
 
 void PhysicsRigidBody::applyForce(const Vector3& force, const Vector3* relativePosition)
 void PhysicsRigidBody::applyForce(const Vector3& force, const Vector3* relativePosition)
@@ -222,9 +226,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));
+            _body->applyForce(force, *relativePosition);
         else
         else
-            _body->applyCentralForce(btVector3(force.x, force.y, force.z));
+            _body->applyCentralForce(force);
     }
     }
 }
 }
 
 
@@ -238,10 +242,10 @@ void PhysicsRigidBody::applyImpulse(const Vector3& impulse, const Vector3* relat
 
 
         if (relativePosition)
         if (relativePosition)
         {
         {
-            _body->applyImpulse(btVector3(impulse.x, impulse.y, impulse.z), btVector3(relativePosition->x, relativePosition->y, relativePosition->z));
+            _body->applyImpulse(impulse, *relativePosition);
         }
         }
         else
         else
-            _body->applyCentralImpulse(btVector3(impulse.x, impulse.y, impulse.z));
+            _body->applyCentralImpulse(impulse);
     }
     }
 }
 }
 
 
@@ -252,7 +256,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(torque);
     }
     }
 }
 }
 
 
@@ -263,7 +267,7 @@ void PhysicsRigidBody::applyTorqueImpulse(const Vector3& torque)
     if (torque.lengthSquared() > MATH_EPSILON)
     if (torque.lengthSquared() > MATH_EPSILON)
     {
     {
         _body->activate();
         _body->activate();
-        _body->applyTorqueImpulse(btVector3(torque.x, torque.y, torque.z));
+        _body->applyTorqueImpulse(torque);
     }
     }
 }
 }
 
 
@@ -568,36 +572,6 @@ PhysicsRigidBody::Listener::~Listener()
     // Unused
     // Unused
 }
 }
 
 
-btScalar PhysicsRigidBody::Listener::addSingleResult(btManifoldPoint& cp, 
-                                                     const btCollisionObject* a, int partIdA, int indexA, 
-                                                     const btCollisionObject* b, int partIdB, int indexB)
-{
-    // Get pointers to the PhysicsRigidBody objects.
-    PhysicsRigidBody* rbA = Game::getInstance()->getPhysicsController()->getRigidBody(a);
-    PhysicsRigidBody* rbB = Game::getInstance()->getPhysicsController()->getRigidBody(b);
-    
-    // If the given rigid body pair has collided in the past, then
-    // we notify the listener only if the pair was not colliding
-    // during the previous frame. Otherwise, it's a new pair, so notify the listener.
-    CollisionPair pair(rbA, rbB);
-    if (_collisionStatus.count(pair) > 0)
-    {
-        if ((_collisionStatus[pair] & COLLISION) == 0)
-            collisionEvent(pair, Vector3(cp.getPositionWorldOnA().x(), cp.getPositionWorldOnA().y(), cp.getPositionWorldOnA().z()));
-    }
-    else
-    {
-        collisionEvent(pair, Vector3(cp.getPositionWorldOnA().x(), cp.getPositionWorldOnA().y(), cp.getPositionWorldOnA().z()));
-    }
-
-    // Update the collision status cache (we remove the dirty bit
-    // set in the controller's update so that this particular collision pair's
-    // status is not reset to 'no collision' when the controller's update completes).
-    _collisionStatus[pair] &= ~DIRTY;
-    _collisionStatus[pair] |= COLLISION;
-    return 0.0f;
-}
-
 btScalar PhysicsRigidBody::CollidesWithCallback::addSingleResult(btManifoldPoint& cp, 
 btScalar PhysicsRigidBody::CollidesWithCallback::addSingleResult(btManifoldPoint& cp, 
                                                                  const btCollisionObject* a, int partIdA, int indexA, 
                                                                  const btCollisionObject* a, int partIdA, int indexA, 
                                                                  const btCollisionObject* b, int partIdB, int indexB)
                                                                  const btCollisionObject* b, int partIdB, int indexB)

+ 22 - 24
gameplay/src/PhysicsRigidBody.h

@@ -69,44 +69,42 @@ public:
     /**
     /**
      * Collision listener interface.
      * Collision listener interface.
      */
      */
-    class Listener : public btCollisionWorld::ContactResultCallback
+    class Listener
     {
     {
         friend class PhysicsRigidBody;
         friend class PhysicsRigidBody;
         friend class PhysicsController;
         friend class PhysicsController;
 
 
     public:
     public:
+        /**
+         * The type of collision event.
+         */
+        enum EventType
+        {
+            /**
+             * Event fired when the two rigid bodies start colliding.
+             */
+            COLLIDING,
+
+            /**
+             * Event fired when the two rigid bodies no longer collide.
+             */
+            NOT_COLLIDING
+        };
+
         /**
         /**
          * Destructor.
          * Destructor.
          */
          */
         virtual ~Listener();
         virtual ~Listener();
 
 
         /**
         /**
-         * Handles when a collision occurs for the rigid body where this listener is registered.
+         * Handles when a collision starts or stops occurring for the rigid body where this listener is registered.
          * 
          * 
+         * @param type The type of collision event.
          * @param collisionPair The two rigid bodies involved in the collision.
          * @param collisionPair The two rigid bodies involved in the collision.
-         * @param contactPoint The point (in world space) where the collision occurred.
-         */
-        virtual void collisionEvent(const CollisionPair& collisionPair, const Vector3& contactPoint) = 0;
-        
-    protected:
-        
-        /**
-         * Internal function used for Bullet integration (do not use or override).
+         * @param contactPointA The contact point with the first rigid body (in world space).
+         * @param contactPointB The contact point with the second rigid body (in world space).
          */
          */
-        btScalar addSingleResult(btManifoldPoint& cp, 
-                                 const btCollisionObject* a, int partIdA, int indexA, 
-                                 const btCollisionObject* b, int partIdB, int indexB);
-
-        std::map<CollisionPair, int> _collisionStatus;  // Holds the collision status for each pair of rigid bodies. 
-        
-    private:
-
-        // Internal constant.
-        static const int DIRTY;
-        // Internal constant.
-        static const int COLLISION;
-        // Internal constant.
-        static const int REGISTERED;
+        virtual void collisionEvent(EventType type, const CollisionPair& collisionPair, const Vector3& contactPointA = Vector3(), const Vector3& contactPointB = Vector3()) = 0;
     };
     };
 
 
     /**
     /**

+ 4 - 4
gameplay/src/PhysicsRigidBody.inl

@@ -75,12 +75,12 @@ inline bool PhysicsRigidBody::isKinematic() 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(velocity);
 }
 }
 
 
 inline void PhysicsRigidBody::setAnisotropicFriction(const Vector3& friction)
 inline void PhysicsRigidBody::setAnisotropicFriction(const Vector3& friction)
 {
 {
-    _body->setAnisotropicFriction(btVector3(friction.x, friction.y, friction.z));
+    _body->setAnisotropicFriction(friction);
 }
 }
 
 
 inline void PhysicsRigidBody::setDamping(float linearDamping, float angularDamping)
 inline void PhysicsRigidBody::setDamping(float linearDamping, float angularDamping)
@@ -95,7 +95,7 @@ inline void PhysicsRigidBody::setFriction(float friction)
 
 
 inline void PhysicsRigidBody::setGravity(const Vector3& gravity)
 inline void PhysicsRigidBody::setGravity(const Vector3& gravity)
 {
 {
-    _body->setGravity(btVector3(gravity.x, gravity.y, gravity.z));
+    _body->setGravity(gravity);
 }
 }
 
 
 inline void PhysicsRigidBody::setKinematic(bool kinematic)
 inline void PhysicsRigidBody::setKinematic(bool kinematic)
@@ -114,7 +114,7 @@ inline void PhysicsRigidBody::setKinematic(bool kinematic)
 
 
 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(velocity);
 }
 }
 
 
 inline void PhysicsRigidBody::setRestitution(float restitution)
 inline void PhysicsRigidBody::setRestitution(float restitution)

+ 2 - 2
gameplay/src/PhysicsSocketConstraint.cpp

@@ -38,11 +38,11 @@ PhysicsSocketConstraint::PhysicsSocketConstraint(PhysicsRigidBody* a, const Vect
         b->getNode()->getWorldMatrix().getScale(&sB);
         b->getNode()->getWorldMatrix().getScale(&sB);
         Vector3 tB(translationOffsetB.x * sB.x, translationOffsetB.y * sB.y, translationOffsetB.z * sB.z);
         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));
+        _constraint = new btPoint2PointConstraint(*a->_body, *b->_body, tA, tB);
     }
     }
     else
     else
     {
     {
-        _constraint = new btPoint2PointConstraint(*a->_body, btVector3(tA.x, tA.y, tA.z));
+        _constraint = new btPoint2PointConstraint(*a->_body, tA);
     }
     }
 }
 }
 
 

+ 2 - 2
gameplay/src/PhysicsSpringConstraint.cpp

@@ -32,8 +32,8 @@ PhysicsSpringConstraint::PhysicsSpringConstraint(PhysicsRigidBody* a, const Quat
     b->getNode()->getWorldMatrix().getScale(&sB);
     b->getNode()->getWorldMatrix().getScale(&sB);
     Vector3 tB(translationOffsetB.x * sB.x, translationOffsetB.y * sB.y, translationOffsetB.z * sB.z);
     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));
+    btTransform frameInA(rotationOffsetA, tA);
+    btTransform frameInB(rotationOffsetB, tB);
     _constraint = new btGeneric6DofSpringConstraint(*a->_body, *b->_body, frameInA, frameInB, true);
     _constraint = new btGeneric6DofSpringConstraint(*a->_body, *b->_body, frameInA, frameInB, true);
 }
 }
 
 

+ 1 - 1
gameplay/src/Plane.h

@@ -220,7 +220,7 @@ private:
  * @param plane The plane to transform.
  * @param plane The plane to transform.
  * @return The resulting transformed plane.
  * @return The resulting transformed plane.
  */
  */
-inline Plane operator*(const Matrix& matrix, const Plane& plane);
+inline const Plane operator*(const Matrix& matrix, const Plane& plane);
 
 
 }
 }
 
 

+ 1 - 1
gameplay/src/Plane.inl

@@ -9,7 +9,7 @@ inline Plane& Plane::operator*=(const Matrix& matrix)
     return *this;
     return *this;
 }
 }
 
 
-inline Plane operator*(const Matrix& matrix, const Plane& plane)
+inline const Plane operator*(const Matrix& matrix, const Plane& plane)
 {
 {
     Plane p(plane);
     Plane p(plane);
     p.transform(matrix);
     p.transform(matrix);

+ 14 - 0
gameplay/src/Platform.h

@@ -36,6 +36,20 @@ public:
      * @return The platform message pump return code.
      * @return The platform message pump return code.
      */
      */
     int enterMessagePump();
     int enterMessagePump();
+    
+    /**
+     * Gets the display width.
+     * 
+     * @return The display width.
+     */
+    static unsigned int getDisplayWidth();
+    
+    /**
+     * Gets the display height.
+     * 
+     * @return The display height.
+     */
+    static unsigned int getDisplayHeight();
 
 
     /**
     /**
      * Gets the absolute platform time starting from when the message pump was started.
      * Gets the absolute platform time starting from when the message pump was started.

+ 11 - 1
gameplay/src/PlatformAndroid.cpp

@@ -766,7 +766,17 @@ int Platform::enterMessagePump()
         gameplay::displayKeyboard(__state, __displayKeyboard);
         gameplay::displayKeyboard(__state, __displayKeyboard);
     }
     }
 }
 }
-
+   
+unsigned int Platform::getDisplayWidth()
+{
+    return __width;
+}
+    
+unsigned int Platform::getDisplayHeight()
+{
+    return __height;
+}
+    
 long Platform::getAbsoluteTime()
 long Platform::getAbsoluteTime()
 {
 {
     clock_gettime(CLOCK_REALTIME, &__timespec);
     clock_gettime(CLOCK_REALTIME, &__timespec);

+ 91 - 10
gameplay/src/PlatformMacOS.mm

@@ -13,6 +13,10 @@
 using namespace std;
 using namespace std;
 using namespace gameplay;
 using namespace gameplay;
 
 
+// Default to 720p
+#define WINDOW_WIDTH    1280
+#define WINDOW_HEIGHT   720
+
 static const float ACCELEROMETER_X_FACTOR = 90.0f / WINDOW_WIDTH;
 static const float ACCELEROMETER_X_FACTOR = 90.0f / WINDOW_WIDTH;
 static const float ACCELEROMETER_Y_FACTOR = 90.0f / WINDOW_HEIGHT;
 static const float ACCELEROMETER_Y_FACTOR = 90.0f / WINDOW_HEIGHT;
 
 
@@ -26,6 +30,7 @@ static int __ly;
 static bool __hasMouse = false;
 static bool __hasMouse = false;
 static bool __leftMouseDown = false;
 static bool __leftMouseDown = false;
 static bool __rightMouseDown = false;
 static bool __rightMouseDown = false;
+static bool __otherMouseDown = false;
 static bool __shiftDown = false;
 static bool __shiftDown = false;
 
 
 long getMachTimeInMilliseconds()
 long getMachTimeInMilliseconds()
@@ -102,9 +107,7 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
 
 
 - (id) initWithFrame: (NSRect) frame
 - (id) initWithFrame: (NSRect) frame
 {    
 {    
-    lock = [[NSRecursiveLock alloc] init];
-    _game = Game::getInstance();
-    __timeStart = getMachTimeInMilliseconds();
+
     NSOpenGLPixelFormatAttribute attrs[] = 
     NSOpenGLPixelFormatAttribute attrs[] = 
     {
     {
         NSOpenGLPFAAccelerated,
         NSOpenGLPFAAccelerated,
@@ -120,7 +123,12 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     if (!pf)
     if (!pf)
         NSLog(@"OpenGL pixel format not supported.");
         NSLog(@"OpenGL pixel format not supported.");
     
     
-    self = [super initWithFrame:frame pixelFormat:[pf autorelease]];  
+    if((self = [super initWithFrame:frame pixelFormat:[pf autorelease]])) 
+    {
+        lock = [[NSRecursiveLock alloc] init];
+        _game = Game::getInstance();
+        __timeStart = getMachTimeInMilliseconds();
+    }
     
     
     return self;
     return self;
 }
 }
@@ -173,18 +181,47 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     [super dealloc];
     [super dealloc];
 }
 }
 
 
+
+- (void) mouse: (Mouse::MouseEvent) mouseEvent orTouchEvent: (Touch::TouchEvent) touchEvent atX: (int) x y: (int) y s: (int) s 
+{
+    if (!Game::getInstance()->mouseEvent(mouseEvent, x, y, s))
+    {
+        Game::getInstance()->touchEvent(touchEvent, x, y, 0);
+    }
+        
+}
+
 - (void) mouseDown: (NSEvent*) event
 - (void) mouseDown: (NSEvent*) event
 {
 {
     NSPoint point = [event locationInWindow];
     NSPoint point = [event locationInWindow];
     __leftMouseDown = true;
     __leftMouseDown = true;
-    _game->touchEvent(Touch::TOUCH_PRESS, point.x, WINDOW_HEIGHT - point.y, 0);
+    [self mouse: Mouse::MOUSE_PRESS_LEFT_BUTTON orTouchEvent: Touch::TOUCH_PRESS atX: WINDOW_HEIGHT - point.x y: point.y s: 0];
+
+    
+    //_game->mouseEvent(Mouse::MOUSE_PRESS_LEFT_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
+   /* 
+    MOUSE_PRESS_LEFT_BUTTON,
+    MOUSE_RELEASE_LEFT_BUTTON,
+    MOUSE_PRESS_MIDDLE_BUTTON,
+    MOUSE_RELEASE_MIDDLE_BUTTON,
+    MOUSE_PRESS_RIGHT_BUTTON,
+    MOUSE_RELEASE_RIGHT_BUTTON,
+    MOUSE_MOVE,
+    MOUSE_WHEEL
+*/
 }
 }
 
 
 - (void) mouseUp: (NSEvent*) event
 - (void) mouseUp: (NSEvent*) event
 {
 {
     NSPoint point = [event locationInWindow];
     NSPoint point = [event locationInWindow];
     __leftMouseDown = false;
     __leftMouseDown = false;
-    _game->touchEvent(Touch::TOUCH_RELEASE, point.x, WINDOW_HEIGHT - point.y, 0);
+    [self mouse: Mouse::MOUSE_RELEASE_LEFT_BUTTON orTouchEvent: Touch::TOUCH_RELEASE atX: point.x y: WINDOW_HEIGHT - point.y s: 0];
+}
+
+- (void)mouseMoved:(NSEvent *) event 
+{
+    NSPoint point = [event locationInWindow];
+    Game::getInstance()->mouseEvent(Mouse::MOUSE_MOVE, point.x, WINDOW_HEIGHT - point.y, 0);
 }
 }
 
 
 - (void) mouseDragged: (NSEvent*) event
 - (void) mouseDragged: (NSEvent*) event
@@ -192,7 +229,7 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     NSPoint point = [event locationInWindow];
     NSPoint point = [event locationInWindow];
     if (__leftMouseDown)
     if (__leftMouseDown)
     {
     {
-        _game->touchEvent(Touch::TOUCH_MOVE, point.x, WINDOW_HEIGHT - point.y, 0);
+        [self mouse: Mouse::MOUSE_MOVE orTouchEvent: Touch::TOUCH_MOVE atX: point.x y: WINDOW_HEIGHT - point.y s: 0];
     }
     }
 }
 }
 
 
@@ -201,12 +238,15 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     __rightMouseDown = true;
     __rightMouseDown = true;
      NSPoint point = [event locationInWindow];
      NSPoint point = [event locationInWindow];
     __lx = point.x;
     __lx = point.x;
-    __ly = WINDOW_HEIGHT - point.y;
+    __ly = WINDOW_HEIGHT - point.y;    
+    _game->mouseEvent(Mouse::MOUSE_PRESS_RIGHT_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
 }
 }
 
 
 - (void) rightMouseUp: (NSEvent*) event
 - (void) rightMouseUp: (NSEvent*) event
 {
 {
    __rightMouseDown = false;
    __rightMouseDown = false;
+    NSPoint point = [event locationInWindow];
+    _game->mouseEvent(Mouse::MOUSE_RELEASE_RIGHT_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
 }
 }
 
 
 - (void) rightMouseDragged: (NSEvent*) event
 - (void) rightMouseDragged: (NSEvent*) event
@@ -226,6 +266,30 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
         __lx = point.x;
         __lx = point.x;
         __ly = (WINDOW_HEIGHT - point.y);
         __ly = (WINDOW_HEIGHT - point.y);
     }
     }
+    
+    // In right-mouse case, whether __rightMouseDown is true or false
+    // this should not matter, mouse move is still occuring
+    _game->mouseEvent(Mouse::MOUSE_MOVE, point.x, WINDOW_HEIGHT - point.y, 0);
+}
+
+- (void)otherMouseDown: (NSEvent *) event 
+{
+    __otherMouseDown = true;
+    NSPoint point = [event locationInWindow];
+    _game->mouseEvent(Mouse::MOUSE_PRESS_MIDDLE_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
+}
+
+- (void)otherMouseUp: (NSEvent *) event 
+{
+    __otherMouseDown = false;
+    NSPoint point = [event locationInWindow];
+    _game->mouseEvent(Mouse::MOUSE_RELEASE_MIDDLE_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
+}
+
+- (void)otherMouseDragged: (NSEvent *) event 
+{
+    NSPoint point = [event locationInWindow];
+    _game->mouseEvent(Mouse::MOUSE_MOVE, point.x, WINDOW_HEIGHT - point.y, 0);
 }
 }
 
 
 - (void) mouseEntered: (NSEvent*)event
 - (void) mouseEntered: (NSEvent*)event
@@ -233,10 +297,17 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     __hasMouse = true;
     __hasMouse = true;
 }
 }
 
 
+- (void)scrollWheel: (NSEvent *) event 
+{
+    NSPoint point = [event locationInWindow];
+    Game::getInstance()->mouseEvent(Mouse::MOUSE_WHEEL, point.x, WINDOW_HEIGHT - point.y, (int)([event deltaY] * 10.0f));
+}
+
 - (void) mouseExited: (NSEvent*)event
 - (void) mouseExited: (NSEvent*)event
 {
 {
     __leftMouseDown = false;
     __leftMouseDown = false;
     __rightMouseDown = false;
     __rightMouseDown = false;
+    __otherMouseDown = false;
     __hasMouse = false;
     __hasMouse = false;
 }
 }
 
 
@@ -503,7 +574,6 @@ extern void printError(const char* format, ...)
     va_end(argptr);
     va_end(argptr);
 }
 }
     
     
-    
 Platform::Platform(Game* game)
 Platform::Platform(Game* game)
 : _game(game)
 : _game(game)
 {
 {
@@ -545,6 +615,7 @@ int Platform::enterMessagePump()
                         backing:NSBackingStoreBuffered
                         backing:NSBackingStoreBuffered
                         defer:NO];
                         defer:NO];
     
     
+    [window setAcceptsMouseMovedEvents:YES];
     [window setContentView:__view];
     [window setContentView:__view];
     [window setDelegate:__view];
     [window setDelegate:__view];
     [__view release];
     [__view release];
@@ -554,7 +625,17 @@ int Platform::enterMessagePump()
     [pool release];
     [pool release];
     return EXIT_SUCCESS;
     return EXIT_SUCCESS;
 }
 }
-    
+
+unsigned int Platform::getDisplayWidth()
+{
+    return WINDOW_WIDTH;
+}
+
+unsigned int Platform::getDisplayHeight()
+{
+    return WINDOW_HEIGHT;
+}
+
 long Platform::getAbsoluteTime()
 long Platform::getAbsoluteTime()
 {
 {
     __timeAbsolute = getMachTimeInMilliseconds();
     __timeAbsolute = getMachTimeInMilliseconds();

+ 19 - 9
gameplay/src/PlatformQNX.cpp

@@ -712,7 +712,7 @@ long timespec2millis(struct timespec *a)
  */
  */
 void mouseOrTouchEvent(Mouse::MouseEvent mouseEvent, Touch::TouchEvent touchEvent, int x, int y)
 void mouseOrTouchEvent(Mouse::MouseEvent mouseEvent, Touch::TouchEvent touchEvent, int x, int y)
 {
 {
-    if (!Game::getInstance()->mouseEvent(mouseEvent, x, y))
+    if (!Game::getInstance()->mouseEvent(mouseEvent, x, y, 0))
     {
     {
         Game::getInstance()->touchEvent(touchEvent, x, y, 0);
         Game::getInstance()->touchEvent(touchEvent, x, y, 0);
     }
     }
@@ -827,14 +827,14 @@ int Platform::enterMessagePump()
                             {
                             {
                                 move = false;
                                 move = false;
                                 mouse_pressed |= SCREEN_LEFT_MOUSE_BUTTON;
                                 mouse_pressed |= SCREEN_LEFT_MOUSE_BUTTON;
-                                mouseOrTouchEvent(Mouse::MOUSE_LEFT_BUTTON_PRESS, Touch::TOUCH_PRESS, position[0], position[1]);
+                                mouseOrTouchEvent(Mouse::MOUSE_PRESS_LEFT_BUTTON, Touch::TOUCH_PRESS, position[0], position[1]);
                             }
                             }
                         }
                         }
                         else if (mouse_pressed & SCREEN_LEFT_MOUSE_BUTTON)
                         else if (mouse_pressed & SCREEN_LEFT_MOUSE_BUTTON)
                         {
                         {
                             move = false;
                             move = false;
                             mouse_pressed &= ~SCREEN_LEFT_MOUSE_BUTTON;
                             mouse_pressed &= ~SCREEN_LEFT_MOUSE_BUTTON;
-                            mouseOrTouchEvent(Mouse::MOUSE_LEFT_BUTTON_RELEASE, Touch::TOUCH_RELEASE, position[0], position[1]);
+                            mouseOrTouchEvent(Mouse::MOUSE_RELEASE_LEFT_BUTTON, Touch::TOUCH_RELEASE, position[0], position[1]);
                         }
                         }
 
 
                         // Handle right mouse
                         // Handle right mouse
@@ -844,14 +844,14 @@ int Platform::enterMessagePump()
                             {
                             {
                                 move = false;
                                 move = false;
                                 mouse_pressed |= SCREEN_RIGHT_MOUSE_BUTTON;
                                 mouse_pressed |= SCREEN_RIGHT_MOUSE_BUTTON;
-                                Game::getInstance()->mouseEvent(Mouse::MOUSE_RIGHT_BUTTON_PRESS, position[0], position[1]);
+                                Game::getInstance()->mouseEvent(Mouse::MOUSE_PRESS_RIGHT_BUTTON, position[0], position[1], 0);
                             }
                             }
                         }
                         }
                         else if (mouse_pressed & SCREEN_RIGHT_MOUSE_BUTTON)
                         else if (mouse_pressed & SCREEN_RIGHT_MOUSE_BUTTON)
                         {
                         {
                             move = false;
                             move = false;
                             mouse_pressed &= ~SCREEN_RIGHT_MOUSE_BUTTON;
                             mouse_pressed &= ~SCREEN_RIGHT_MOUSE_BUTTON;
-                            Game::getInstance()->mouseEvent(Mouse::MOUSE_RIGHT_BUTTON_RELEASE, position[0], position[1]);
+                            Game::getInstance()->mouseEvent(Mouse::MOUSE_RELEASE_RIGHT_BUTTON, position[0], position[1], 0);
                         }
                         }
 
 
                         // Handle middle mouse
                         // Handle middle mouse
@@ -861,14 +861,14 @@ int Platform::enterMessagePump()
                             {
                             {
                                 move = false;
                                 move = false;
                                 mouse_pressed |= SCREEN_MIDDLE_MOUSE_BUTTON;
                                 mouse_pressed |= SCREEN_MIDDLE_MOUSE_BUTTON;
-                                Game::getInstance()->mouseEvent(Mouse::MOUSE_MIDDLE_BUTTON_PRESS, position[0], position[1]);
+                                Game::getInstance()->mouseEvent(Mouse::MOUSE_PRESS_MIDDLE_BUTTON, position[0], position[1], 0);
                             }
                             }
                         }
                         }
                         else if (mouse_pressed & SCREEN_MIDDLE_MOUSE_BUTTON)
                         else if (mouse_pressed & SCREEN_MIDDLE_MOUSE_BUTTON)
                         {
                         {
                             move = false;
                             move = false;
                             mouse_pressed &= ~SCREEN_MIDDLE_MOUSE_BUTTON;
                             mouse_pressed &= ~SCREEN_MIDDLE_MOUSE_BUTTON;
-                            Game::getInstance()->mouseEvent(Mouse::MOUSE_MIDDLE_BUTTON_RELEASE, position[0], position[1]);
+                            Game::getInstance()->mouseEvent(Mouse::MOUSE_RELEASE_MIDDLE_BUTTON, position[0], position[1], 0);
                         }
                         }
 
 
                         // Fire a move event if none of the buttons changed.
                         // Fire a move event if none of the buttons changed.
@@ -878,13 +878,13 @@ int Platform::enterMessagePump()
                         }
                         }
                         else if (move)
                         else if (move)
                         {
                         {
-                            Game::getInstance()->mouseEvent(Mouse::MOUSE_MOVE, position[0], position[1]);
+                            Game::getInstance()->mouseEvent(Mouse::MOUSE_MOVE, position[0], position[1], 0);
                         }
                         }
 
 
                         // Handle mouse wheel events
                         // Handle mouse wheel events
                         if (wheel)
                         if (wheel)
                         {
                         {
-                            Game::getInstance()->mouseWheelEvent(position[0], position[1], -wheel);
+                            Game::getInstance()->mouseEvent(Mouse::MOUSE_WHEEL, position[0], position[1], -wheel);
                         }
                         }
                         break;
                         break;
                     }
                     }
@@ -962,6 +962,16 @@ int Platform::enterMessagePump()
 
 
     return 0;
     return 0;
 }
 }
+    
+unsigned int Platform::getDisplayWidth()
+{
+    return __screenWindowSize[0];
+}
+
+unsigned int Platform::getDisplayHeight()
+{
+    return __screenWindowSize[1];
+}
 
 
 long Platform::getAbsoluteTime()
 long Platform::getAbsoluteTime()
 {
 {

+ 27 - 8
gameplay/src/PlatformWin32.cpp

@@ -6,6 +6,10 @@
 #include "Game.h"
 #include "Game.h"
 #include <GL/wglew.h>
 #include <GL/wglew.h>
 
 
+// Default to 720p
+#define WINDOW_WIDTH    1280
+#define WINDOW_HEIGHT   720
+
 static long __timeTicksPerMillis;
 static long __timeTicksPerMillis;
 static long __timeStart;
 static long __timeStart;
 static long __timeAbsolute;
 static long __timeAbsolute;
@@ -264,7 +268,7 @@ LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
         return 0;
         return 0;
 
 
     case WM_LBUTTONDOWN:
     case WM_LBUTTONDOWN:
-        if (!gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_LEFT_BUTTON_PRESS, LOWORD(lParam), HIWORD(lParam)))
+        if (!gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_PRESS_LEFT_BUTTON, LOWORD(lParam), HIWORD(lParam), 0))
         {
         {
             gameplay::Game::getInstance()->touchEvent(gameplay::Touch::TOUCH_PRESS, LOWORD(lParam), HIWORD(lParam), 0);
             gameplay::Game::getInstance()->touchEvent(gameplay::Touch::TOUCH_PRESS, LOWORD(lParam), HIWORD(lParam), 0);
         }
         }
@@ -273,30 +277,30 @@ LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 
 
     case WM_LBUTTONUP:
     case WM_LBUTTONUP:
         lMouseDown = false;
         lMouseDown = false;
-        if (!gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_LEFT_BUTTON_RELEASE, LOWORD(lParam), HIWORD(lParam)))
+        if (!gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_RELEASE_LEFT_BUTTON, LOWORD(lParam), HIWORD(lParam), 0))
         {
         {
             gameplay::Game::getInstance()->touchEvent(gameplay::Touch::TOUCH_RELEASE, LOWORD(lParam), HIWORD(lParam), 0);
             gameplay::Game::getInstance()->touchEvent(gameplay::Touch::TOUCH_RELEASE, LOWORD(lParam), HIWORD(lParam), 0);
         }
         }
         return 0;
         return 0;
 
 
     case WM_RBUTTONDOWN:
     case WM_RBUTTONDOWN:
-        gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_RIGHT_BUTTON_PRESS, LOWORD(lParam), HIWORD(lParam));
+        gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_PRESS_RIGHT_BUTTON, LOWORD(lParam), HIWORD(lParam), 0);
         rMouseDown = true;
         rMouseDown = true;
         lx = LOWORD(lParam);
         lx = LOWORD(lParam);
         ly = HIWORD(lParam);
         ly = HIWORD(lParam);
         break;
         break;
 
 
     case WM_RBUTTONUP:
     case WM_RBUTTONUP:
-        gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_RIGHT_BUTTON_RELEASE, LOWORD(lParam), HIWORD(lParam));
+        gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_RELEASE_RIGHT_BUTTON, LOWORD(lParam), HIWORD(lParam), 0);
         rMouseDown = false;
         rMouseDown = false;
         break;
         break;
 
 
     case WM_MBUTTONDOWN:
     case WM_MBUTTONDOWN:
-        gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_MIDDLE_BUTTON_PRESS, LOWORD(lParam), HIWORD(lParam));
+        gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_PRESS_MIDDLE_BUTTON, LOWORD(lParam), HIWORD(lParam), 0);
         break;
         break;
 
 
     case WM_MBUTTONUP:
     case WM_MBUTTONUP:
-        gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_MIDDLE_BUTTON_RELEASE, LOWORD(lParam), HIWORD(lParam));
+        gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_RELEASE_MIDDLE_BUTTON, LOWORD(lParam), HIWORD(lParam), 0);
         break;
         break;
 
 
     case WM_MOUSEMOVE:
     case WM_MOUSEMOVE:
@@ -313,7 +317,7 @@ LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
             TrackMouseEvent(&tme);
             TrackMouseEvent(&tme);
         }
         }
 
 
-        bool consumed = gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_MOVE, LOWORD(lParam), HIWORD(lParam));
+        bool consumed = gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_MOVE, LOWORD(lParam), HIWORD(lParam), 0);
         if (lMouseDown && !consumed)
         if (lMouseDown && !consumed)
         {
         {
             // Mouse move events should be interpreted as touch move only if left mouse is held and the game did not consume the mouse event.
             // Mouse move events should be interpreted as touch move only if left mouse is held and the game did not consume the mouse event.
@@ -344,7 +348,7 @@ LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
         break;
         break;
 
 
     case WM_MOUSEWHEEL:
     case WM_MOUSEWHEEL:
-        gameplay::Game::getInstance()->mouseWheelEvent(LOWORD(lParam), HIWORD(lParam), GET_WHEEL_DELTA_WPARAM(wParam) / 120);
+        gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_WHEEL, LOWORD(lParam), HIWORD(lParam), GET_WHEEL_DELTA_WPARAM(wParam) / 120);
         break;
         break;
 
 
     case WM_KEYDOWN:
     case WM_KEYDOWN:
@@ -471,6 +475,11 @@ Platform* Platform::create(Game* game)
     // Get the drawing context.
     // Get the drawing context.
     __hdc = GetDC(__hwnd);
     __hdc = GetDC(__hwnd);
 
 
+    // Center the window
+    const int screenX = (GetSystemMetrics(SM_CXSCREEN) - WINDOW_WIDTH) / 2;
+    const int screenY = (GetSystemMetrics(SM_CYSCREEN) - WINDOW_HEIGHT) / 2;
+    ::SetWindowPos(__hwnd, __hwnd, screenX, screenY, -1, -1, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+
     // Choose pixel format. 32-bit. RGBA.
     // Choose pixel format. 32-bit. RGBA.
     PIXELFORMATDESCRIPTOR pfd;
     PIXELFORMATDESCRIPTOR pfd;
     memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
     memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
@@ -570,6 +579,16 @@ int Platform::enterMessagePump()
     return msg.wParam;
     return msg.wParam;
 }
 }
 
 
+unsigned int Platform::getDisplayWidth()
+{
+    return WINDOW_WIDTH;
+}
+
+unsigned int Platform::getDisplayHeight()
+{
+    return WINDOW_HEIGHT;
+}
+    
 long Platform::getAbsoluteTime()
 long Platform::getAbsoluteTime()
 {
 {
        LARGE_INTEGER queryTime;
        LARGE_INTEGER queryTime;

+ 141 - 99
gameplay/src/PlatformiOS.mm

@@ -18,6 +18,11 @@
 using namespace std;
 using namespace std;
 using namespace gameplay;
 using namespace gameplay;
 
 
+// UIScreen bounds are provided as if device was in portrait mode
+// Gameplay defaults to landscape
+extern const int WINDOW_WIDTH  = [[UIScreen mainScreen] bounds].size.height;
+extern const int WINDOW_HEIGHT = [[UIScreen mainScreen] bounds].size.width;
+
 static const float ACCELEROMETER_X_FACTOR = 90.0f / WINDOW_WIDTH;
 static const float ACCELEROMETER_X_FACTOR = 90.0f / WINDOW_WIDTH;
 static const float ACCELEROMETER_Y_FACTOR = 90.0f / WINDOW_HEIGHT;
 static const float ACCELEROMETER_Y_FACTOR = 90.0f / WINDOW_HEIGHT;
 
 
@@ -34,7 +39,8 @@ static float __pitch;
 static float __roll;
 static float __roll;
 
 
 
 
-long getMachTimeInMilliseconds(); 
+long getMachTimeInMilliseconds();
+
 int getKey(unichar keyCode);
 int getKey(unichar keyCode);
 
 
 @interface View : UIView <UIKeyInput>
 @interface View : UIView <UIKeyInput>
@@ -59,7 +65,7 @@ int getKey(unichar keyCode);
 - (void)update:(id)sender;
 - (void)update:(id)sender;
 - (void)setSwapInterval:(NSInteger)interval;
 - (void)setSwapInterval:(NSInteger)interval;
 - (int)swapInterval;
 - (int)swapInterval;
-
+- (void)swapBuffers;
 - (BOOL)showKeyboard;
 - (BOOL)showKeyboard;
 - (BOOL)dismissKeyboard;
 - (BOOL)dismissKeyboard;
 @end
 @end
@@ -113,6 +119,12 @@ int getKey(unichar keyCode);
 			[self release];
 			[self release];
 			return nil;
 			return nil;
 		}
 		}
+
+            if (!defaultFramebuffer)
+                [self createFramebuffer];
+            
+        glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);
+        glViewport(0, 0, framebufferWidth, framebufferHeight);
         
         
         // Initialize Internal Defaults
         // Initialize Internal Defaults
         displayLink = nil;
         displayLink = nil;
@@ -132,10 +144,11 @@ int getKey(unichar keyCode);
         
         
         _game = Game::getInstance();
         _game = Game::getInstance();
         __timeStart = getMachTimeInMilliseconds();
         __timeStart = getMachTimeInMilliseconds();
-        _game->run(WINDOW_WIDTH, WINDOW_HEIGHT);    // TODO: Handle based on current orientation            
+        _game->run(WINDOW_WIDTH, WINDOW_HEIGHT);          
     }
     }
     return self;
     return self;
 }
 }
+
 - (void) dealloc
 - (void) dealloc
 {
 {
     _game->exit();
     _game->exit();
@@ -163,7 +176,6 @@ int getKey(unichar keyCode);
 {
 {
     // iOS Requires all content go to a rendering buffer then it is swapped into the windows rendering surface
     // iOS Requires all content go to a rendering buffer then it is swapped into the windows rendering surface
     assert(defaultFramebuffer == 0);
     assert(defaultFramebuffer == 0);
-    //NSLog(@"EAGLView: creating Framebuffer");
     
     
     // Create the default frame buffer, and render buffer
     // Create the default frame buffer, and render buffer
     glGenFramebuffers(1, &defaultFramebuffer);
     glGenFramebuffers(1, &defaultFramebuffer);
@@ -229,6 +241,15 @@ int getKey(unichar keyCode);
     return swapInterval;
     return swapInterval;
 }
 }
 
 
+- (void)swapBuffers
+{
+    if (context != nil)
+    {
+        glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
+        [context presentRenderbuffer:GL_RENDERBUFFER];
+    }
+}
+
 - (void)startUpdating
 - (void)startUpdating
 {
 {
 	if (!updating)
 	if (!updating)
@@ -271,17 +292,20 @@ int getKey(unichar keyCode);
     }
     }
 }
 }
 
 
-- (BOOL)showKeyboard {
+- (BOOL)showKeyboard 
+{
     return [self becomeFirstResponder];
     return [self becomeFirstResponder];
 }
 }
-- (BOOL)dismissKeyboard {
+
+- (BOOL)dismissKeyboard 
+{
     return [self resignFirstResponder];
     return [self resignFirstResponder];
 }
 }
 
 
 /*
 /*
  * Virtual Keyboard Support
  * Virtual Keyboard Support
  */
  */
-- (void)insertText:(NSString *)text 
+- (void)insertText:(NSString*)text 
 {
 {
     if([text length] == 0) return;
     if([text length] == 0) return;
     assert([text length] == 1);
     assert([text length] == 1);
@@ -290,11 +314,13 @@ int getKey(unichar keyCode);
     Game::getInstance()->keyEvent(Keyboard::KEY_PRESS, gpk);    
     Game::getInstance()->keyEvent(Keyboard::KEY_PRESS, gpk);    
     Game::getInstance()->keyEvent(Keyboard::KEY_RELEASE, gpk);    
     Game::getInstance()->keyEvent(Keyboard::KEY_RELEASE, gpk);    
 }
 }
+
 - (void)deleteBackward 
 - (void)deleteBackward 
 {
 {
     Game::getInstance()->keyEvent(Keyboard::KEY_PRESS, Keyboard::KEY_BACKSPACE);    
     Game::getInstance()->keyEvent(Keyboard::KEY_PRESS, Keyboard::KEY_BACKSPACE);    
     Game::getInstance()->keyEvent(Keyboard::KEY_RELEASE, Keyboard::KEY_BACKSPACE);    
     Game::getInstance()->keyEvent(Keyboard::KEY_RELEASE, Keyboard::KEY_BACKSPACE);    
 }
 }
+
 - (BOOL)hasText 
 - (BOOL)hasText 
 {
 {
     return YES;
     return YES;
@@ -311,7 +337,7 @@ int getKey(unichar keyCode);
         CGPoint touchLoc = [t locationInView:self];
         CGPoint touchLoc = [t locationInView:self];
         if(self.multipleTouchEnabled == YES) 
         if(self.multipleTouchEnabled == YES) 
             uniqueTouch = [t hash];
             uniqueTouch = [t hash];
-        Game::getInstance()->touchEvent(Touch::TOUCH_PRESS, touchLoc.x,  touchLoc.y, uniqueTouch);
+        Game::getInstance()->touchEvent(Touch::TOUCH_PRESS, touchLoc.x, touchLoc.y, uniqueTouch);
     }
     }
 }
 }
 
 
@@ -341,7 +367,7 @@ int getKey(unichar keyCode);
         CGPoint touchLoc = [t locationInView:self];
         CGPoint touchLoc = [t locationInView:self];
         if(self.multipleTouchEnabled == YES) 
         if(self.multipleTouchEnabled == YES) 
             uniqueTouch = [t hash];
             uniqueTouch = [t hash];
-        Game::getInstance()->touchEvent(Touch::TOUCH_MOVE, touchLoc.x,  touchLoc.y, uniqueTouch);
+        Game::getInstance()->touchEvent(Touch::TOUCH_MOVE, touchLoc.x, touchLoc.y, uniqueTouch);
     }
     }
 }
 }
 
 
@@ -451,8 +477,10 @@ int getKey(unichar keyCode);
         r = atan(tx / sqrt(ty * ty + tz * tz)) * 180.0f * M_1_PI;     
         r = atan(tx / sqrt(ty * ty + tz * tz)) * 180.0f * M_1_PI;     
     }
     }
     
     
-    if(pitch != NULL) *pitch = p;
-    if(roll != NULL) *roll = r;
+    if(pitch != NULL) 
+        *pitch = p;
+    if(roll != NULL) 
+        *roll = r;
 }
 }
 
 
 - (void)applicationWillResignActive:(UIApplication*)application
 - (void)applicationWillResignActive:(UIApplication*)application
@@ -505,7 +533,8 @@ long getMachTimeInMilliseconds()
 
 
 int getKey(unichar keyCode) 
 int getKey(unichar keyCode) 
 {
 {
-    switch(keyCode) {
+    switch(keyCode) 
+    {
         case 0x30:
         case 0x30:
             return Keyboard::KEY_ZERO;
             return Keyboard::KEY_ZERO;
         case 0x31:
         case 0x31:
@@ -720,97 +749,110 @@ int getKey(unichar keyCode)
 
 
 namespace gameplay
 namespace gameplay
 {
 {
-    extern void printError(const char* format, ...)
-    {
-        va_list argptr;
-        va_start(argptr, format);
-        vfprintf(stderr, format, argptr);
-        fprintf(stderr, "\n");
-        va_end(argptr);
-    }
-    
-    Platform::Platform(Game* game)
-        : _game(game)
-    {
-    }
-    
-    Platform::Platform(const Platform& copy)
-    {
-        // hidden
-    }
     
     
-    Platform::~Platform()
-    {
-    }
-    
-    Platform* Platform::create(Game* game)
-    {
-        Platform* platform = new Platform(game);
-        return platform;
-    }
-    
-    int Platform::enterMessagePump()
-    {
-        NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
-        [AppDelegate load];
-        UIApplicationMain(0, nil, NSStringFromClass([AppDelegate class]), NSStringFromClass([AppDelegate class]));
-        [pool release];
-        return EXIT_SUCCESS;
-    }
-    
-    long Platform::getAbsoluteTime()
-    {
-        __timeAbsolute = getMachTimeInMilliseconds();
-        return __timeAbsolute;
-    }
-    
-    void Platform::setAbsoluteTime(long time)
-    {
-        __timeAbsolute = time;
-    }
-    
-    bool Platform::isVsync()
-    {
-        return __vsync;
-    }
-    
-    void Platform::setVsync(bool enable)
-    {
-        __vsync = enable;
-    }
-    
-    int Platform::getOrientationAngle()
-    {
-        return 0;
-    }
-    
-    void Platform::getAccelerometerValues(float* pitch, float* roll)
-    {
-        [__appDelegate getAccelerometerPitch:pitch roll:roll];
-    }
-    
-    void Platform::setMultiTouch(bool enabled) 
-    {
-        __view.multipleTouchEnabled = enabled;
-    }
-    
-    bool Platform::isMultiTouch() 
-    {
-        return __view.multipleTouchEnabled;
-    }
+extern void printError(const char* format, ...)
+{
+    va_list argptr;
+    va_start(argptr, format);
+    vfprintf(stderr, format, argptr);
+    fprintf(stderr, "\n");
+    va_end(argptr);
+}
+
+Platform::Platform(Game* game)
+    : _game(game)
+{
+}
+
+Platform::Platform(const Platform& copy)
+{
+    // hidden
+}
+
+Platform::~Platform()
+{
+}
+
+Platform* Platform::create(Game* game)
+{
+    Platform* platform = new Platform(game);
+    return platform;
+}
+
+int Platform::enterMessagePump()
+{
+    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+    [AppDelegate load];
+    UIApplicationMain(0, nil, NSStringFromClass([AppDelegate class]), NSStringFromClass([AppDelegate class]));
+    [pool release];
+    return EXIT_SUCCESS;
+}
     
     
-    void Platform::swapBuffers()
+unsigned int Platform::getDisplayWidth()
+{
+    return WINDOW_WIDTH;
+}
+
+unsigned int Platform::getDisplayHeight()
+{
+    return WINDOW_HEIGHT;
+}
+
+long Platform::getAbsoluteTime()
+{
+    __timeAbsolute = getMachTimeInMilliseconds();
+    return __timeAbsolute;
+}
+
+void Platform::setAbsoluteTime(long time)
+{
+    __timeAbsolute = time;
+}
+
+bool Platform::isVsync()
+{
+    return __vsync;
+}
+
+void Platform::setVsync(bool enable)
+{
+    __vsync = enable;
+}
+
+int Platform::getOrientationAngle()
+{
+    return 0;
+}
+
+void Platform::getAccelerometerValues(float* pitch, float* roll)
+{
+    [__appDelegate getAccelerometerPitch:pitch roll:roll];
+}
+
+void Platform::setMultiTouch(bool enabled) 
+{
+    __view.multipleTouchEnabled = enabled;
+}
+
+bool Platform::isMultiTouch() 
+{
+    return __view.multipleTouchEnabled;
+}
+
+void Platform::swapBuffers()
+{
+    if (__view)
+        [__view swapBuffers];
+}
+
+void displayKeyboard(bool display) 
+{
+    if(__view) 
     {
     {
-        if (__view)
-            [[__view getContext] presentRenderbuffer:GL_RENDERBUFFER];
-    }
-    
-    void displayKeyboard(bool display) {
-        if(__view) {
-            if(display) [__view showKeyboard];
-            else [__view dismissKeyboard];
-        }
+        if(display) [__view showKeyboard];
+        else [__view dismissKeyboard];
     }
     }
+}
     
     
 }
 }
 
 

+ 12 - 11
gameplay/src/Properties.cpp

@@ -477,34 +477,35 @@ bool Properties::exists(const char* name) const
     return _properties.find(name) != _properties.end();
     return _properties.find(name) != _properties.end();
 }
 }
 
 
-bool isStringNumeric(const char* str)
+const bool isStringNumeric(const char* str)
 {
 {
-    char* ptr = const_cast<char*>(str);
+    // The first character may be '-'
+    if (*str == '-')
+        str++;
 
 
-    // First character must be a digit
-    if (!isdigit(*ptr))
+    // The first character after the sign must be a digit
+    if (!isdigit(*str))
         return false;
         return false;
-    ptr++;
+    str++;
 
 
     // All remaining characters must be digits, with a single decimal (.) permitted
     // All remaining characters must be digits, with a single decimal (.) permitted
     unsigned int decimalCount = 0;
     unsigned int decimalCount = 0;
-    while (*ptr)
+    while (*str)
     {
     {
-        if (!isdigit(*ptr))
+        if (!isdigit(*str))
         {
         {
-            if (*ptr == '.' && decimalCount == 0)
+            if (*str == '.' && decimalCount == 0)
             {
             {
                 // Max of 1 decimal allowed
                 // Max of 1 decimal allowed
                 decimalCount++;
                 decimalCount++;
             }
             }
             else
             else
             {
             {
-                // Not a number
+                return false;
             }
             }
         }
         }
-        ptr++;
+        str++;
     }
     }
-    
     return true;
     return true;
 }
 }
 
 

+ 6 - 1
gameplay/src/Quaternion.h

@@ -340,7 +340,7 @@ public:
      * @param q The quaternion to multiply.
      * @param q The quaternion to multiply.
      * @return The quaternion product.
      * @return The quaternion product.
      */
      */
-    inline Quaternion operator*(const Quaternion& q) const;
+    inline const Quaternion operator*(const Quaternion& q) const;
 
 
     /**
     /**
      * Multiplies this quaternion with the given quaternion.
      * Multiplies this quaternion with the given quaternion.
@@ -350,6 +350,11 @@ public:
      */
      */
     inline Quaternion& operator*=(const Quaternion& q);
     inline Quaternion& operator*=(const Quaternion& q);
 
 
+    /**
+     * Defines implicit conversion operator to the Bullet btQuaternion type.
+     */
+    inline operator btQuaternion() const;
+
 private:
 private:
 
 
     /**
     /**

+ 7 - 1
gameplay/src/Quaternion.inl

@@ -1,9 +1,10 @@
 #include "Quaternion.h"
 #include "Quaternion.h"
+#include "Base.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
 
 
-inline Quaternion Quaternion::operator*(const Quaternion& q) const
+inline const Quaternion Quaternion::operator*(const Quaternion& q) const
 {
 {
     Quaternion result(*this);
     Quaternion result(*this);
     result.multiply(q);
     result.multiply(q);
@@ -16,4 +17,9 @@ inline Quaternion& Quaternion::operator*=(const Quaternion& q)
     return *this;
     return *this;
 }
 }
 
 
+inline Quaternion::operator btQuaternion() const
+{
+    return btQuaternion(x, y, z, w);
+}
+
 }
 }

+ 1 - 1
gameplay/src/Ray.h

@@ -167,7 +167,7 @@ private:
  * @param ray The ray to transform.
  * @param ray The ray to transform.
  * @return The resulting transformed ray.
  * @return The resulting transformed ray.
  */
  */
-inline Ray operator*(const Matrix& matrix, const Ray& ray);
+inline const Ray operator*(const Matrix& matrix, const Ray& ray);
 
 
 }
 }
 
 

+ 1 - 1
gameplay/src/Ray.inl

@@ -9,7 +9,7 @@ inline Ray& Ray::operator*=(const Matrix& matrix)
     return *this;
     return *this;
 }
 }
 
 
-inline Ray operator*(const Matrix& matrix, const Ray& ray)
+inline const Ray operator*(const Matrix& matrix, const Ray& ray)
 {
 {
     Ray r(ray);
     Ray r(ray);
     r.transform(matrix);
     r.transform(matrix);

+ 52 - 8
gameplay/src/SceneLoader.cpp

@@ -12,6 +12,7 @@ std::vector<SceneLoader::SceneAnimation> SceneLoader::_animations;
 std::vector<SceneLoader::SceneNodeProperty> SceneLoader::_nodeProperties;
 std::vector<SceneLoader::SceneNodeProperty> SceneLoader::_nodeProperties;
 std::vector<std::string> SceneLoader::_nodesWithMeshRB;
 std::vector<std::string> SceneLoader::_nodesWithMeshRB;
 std::map<std::string, SceneLoader::MeshRigidBodyData>* SceneLoader::_meshRigidBodyData = NULL;
 std::map<std::string, SceneLoader::MeshRigidBodyData>* SceneLoader::_meshRigidBodyData = NULL;
+std::string SceneLoader::_path;
 
 
 Scene* SceneLoader::load(const char* filePath)
 Scene* SceneLoader::load(const char* filePath)
 {
 {
@@ -35,8 +36,10 @@ Scene* SceneLoader::load(const char* filePath)
         SAFE_DELETE(properties);
         SAFE_DELETE(properties);
         return NULL;
         return NULL;
     }
     }
-    
 
 
+    // Get the path to the main GPB.
+    _path = sceneProperties->getString("path");
+    
     // Build the node URL/property and animation reference tables and load the referenced files.
     // Build the node URL/property and animation reference tables and load the referenced files.
     buildReferenceTables(sceneProperties);
     buildReferenceTables(sceneProperties);
     loadReferencedFiles();
     loadReferencedFiles();
@@ -124,7 +127,7 @@ Scene* SceneLoader::load(const char* filePath)
     return scene;
     return scene;
 }
 }
 
 
-void SceneLoader::addMeshRigidBodyData(std::string id, Mesh* mesh, unsigned char* vertexData, unsigned int vertexByteCount)
+void SceneLoader::addMeshRigidBodyData(std::string package, std::string id, Mesh* mesh, unsigned char* vertexData, unsigned int vertexByteCount)
 {
 {
     if (!_meshRigidBodyData)
     if (!_meshRigidBodyData)
     {
     {
@@ -132,12 +135,27 @@ void SceneLoader::addMeshRigidBodyData(std::string id, Mesh* mesh, unsigned char
         return;
         return;
     }
     }
 
 
+    // If the node with the mesh rigid body is renamed, we need to find the new id.
+    for (unsigned int i = 0; i < _nodeProperties.size(); i++)
+    {
+        if (_nodeProperties[i]._type == SceneNodeProperty::URL &&
+            _nodeProperties[i]._id == id)
+        {
+            if ((package == _path && _nodeProperties[i]._file.size() == 0) ||
+                (package == _nodeProperties[i]._file))
+            {
+                id = _nodeProperties[i]._nodeID;
+                break;
+            }
+        }
+    }
+
     (*_meshRigidBodyData)[id].mesh = mesh;
     (*_meshRigidBodyData)[id].mesh = mesh;
     (*_meshRigidBodyData)[id].vertexData = new unsigned char[vertexByteCount];
     (*_meshRigidBodyData)[id].vertexData = new unsigned char[vertexByteCount];
     memcpy((*_meshRigidBodyData)[id].vertexData, vertexData, vertexByteCount);
     memcpy((*_meshRigidBodyData)[id].vertexData, vertexData, vertexByteCount);
 }
 }
 
 
-void SceneLoader::addMeshRigidBodyData(std::string id, unsigned char* indexData, unsigned int indexByteCount)
+void SceneLoader::addMeshRigidBodyData(std::string package, std::string id, unsigned char* indexData, unsigned int indexByteCount)
 {
 {
     if (!_meshRigidBodyData)
     if (!_meshRigidBodyData)
     {
     {
@@ -145,6 +163,21 @@ void SceneLoader::addMeshRigidBodyData(std::string id, unsigned char* indexData,
         return;
         return;
     }
     }
 
 
+    // If the node with the mesh rigid body is renamed, we need to find the new id.
+    for (unsigned int i = 0; i < _nodeProperties.size(); i++)
+    {
+        if (_nodeProperties[i]._type == SceneNodeProperty::URL &&
+            _nodeProperties[i]._id == id)
+        {
+            if ((package == _path && _nodeProperties[i]._file.size() == 0) ||
+                (package == _nodeProperties[i]._file))
+            {
+                id = _nodeProperties[i]._nodeID;
+                break;
+            }
+        }
+    }
+
     unsigned char* indexDataCopy = new unsigned char[indexByteCount];
     unsigned char* indexDataCopy = new unsigned char[indexByteCount];
     memcpy(indexDataCopy, indexData, indexByteCount);
     memcpy(indexDataCopy, indexData, indexByteCount);
     (*_meshRigidBodyData)[id].indexData.push_back(indexDataCopy);
     (*_meshRigidBodyData)[id].indexData.push_back(indexDataCopy);
@@ -568,7 +601,19 @@ void SceneLoader::calculateNodesWithMeshRigidBodies(const Properties* scenePrope
                     if (p && (name = p->getString("rigidbodymodel")))
                     if (p && (name = p->getString("rigidbodymodel")))
                         _nodesWithMeshRB.push_back(name);
                         _nodesWithMeshRB.push_back(name);
                     else
                     else
-                        _nodesWithMeshRB.push_back(_nodeProperties[i]._nodeID);
+                    {
+                        const char* id = _nodeProperties[i]._nodeID;
+                        for (unsigned int j = 0; j < _nodeProperties.size(); j++)
+                        {
+                            if (_nodeProperties[j]._type == SceneNodeProperty::URL &&
+                                _nodeProperties[j]._nodeID == _nodeProperties[i]._nodeID)
+                            {
+                                id = _nodeProperties[j]._id.c_str();
+                                break;
+                            }
+                        }
+                        _nodesWithMeshRB.push_back(id);
+                    }
                 }
                 }
             }
             }
         }
         }
@@ -704,18 +749,17 @@ PhysicsConstraint* SceneLoader::loadHingeConstraint(const Properties* constraint
 Scene* SceneLoader::loadMainSceneData(const Properties* sceneProperties)
 Scene* SceneLoader::loadMainSceneData(const Properties* sceneProperties)
 {
 {
     // Load the main scene from the specified path.
     // Load the main scene from the specified path.
-    const char* path = sceneProperties->getString("path");
-    Package* package = Package::create(path);
+    Package* package = Package::create(_path.c_str());
     if (!package)
     if (!package)
     {
     {
-        WARN_VARG("Failed to load scene GPB file '%s'.", path);
+        WARN_VARG("Failed to load scene GPB file '%s'.", _path.c_str());
         return NULL;
         return NULL;
     }
     }
     
     
     Scene* scene = package->loadScene(NULL, &_nodesWithMeshRB);
     Scene* scene = package->loadScene(NULL, &_nodesWithMeshRB);
     if (!scene)
     if (!scene)
     {
     {
-        WARN_VARG("Failed to load scene from '%s'.", path);
+        WARN_VARG("Failed to load scene from '%s'.", _path.c_str());
         SAFE_RELEASE(package);
         SAFE_RELEASE(package);
         return NULL;
         return NULL;
     }
     }

+ 5 - 2
gameplay/src/SceneLoader.h

@@ -58,8 +58,8 @@ private:
         std::string _id;
         std::string _id;
     };
     };
 
 
-    static void addMeshRigidBodyData(std::string id, Mesh* mesh, unsigned char* vertexData, unsigned int vertexByteCount);
-    static void addMeshRigidBodyData(std::string id, unsigned char* indexData, unsigned int indexByteCount);
+    static void addMeshRigidBodyData(std::string package, std::string id, Mesh* mesh, unsigned char* vertexData, unsigned int vertexByteCount);
+    static void addMeshRigidBodyData(std::string package, std::string id, unsigned char* indexData, unsigned int indexByteCount);
     static void addSceneAnimation(const char* animationID, const char* targetID, const char* url);
     static void addSceneAnimation(const char* animationID, const char* targetID, const char* url);
     static void addSceneNodeProperty(SceneNodeProperty::Type type, const char* nodeID, const char* url = NULL);
     static void addSceneNodeProperty(SceneNodeProperty::Type type, const char* nodeID, const char* url = NULL);
     static void applyNodeProperties(const Scene* scene, const Properties* sceneProperties);
     static void applyNodeProperties(const Scene* scene, const Properties* sceneProperties);
@@ -93,6 +93,9 @@ private:
 
 
     // Stores the mesh data needed for triangle mesh rigid body support.
     // Stores the mesh data needed for triangle mesh rigid body support.
     static std::map<std::string, MeshRigidBodyData>* _meshRigidBodyData;
     static std::map<std::string, MeshRigidBodyData>* _meshRigidBodyData;
+
+    // The path of the main GPB for the scene being loaded.
+    static std::string _path;
 };
 };
 
 
 }
 }

+ 2 - 1
gameplay/src/Texture.cpp

@@ -68,7 +68,8 @@ Texture* Texture::create(const char* path, bool generateMipmaps)
             if (tolower(ext[1]) == 'p' && tolower(ext[2]) == 'n' && tolower(ext[3]) == 'g')
             if (tolower(ext[1]) == 'p' && tolower(ext[2]) == 'n' && tolower(ext[3]) == 'g')
             {
             {
                 Image* image = Image::create(path);
                 Image* image = Image::create(path);
-                texture = create(image, generateMipmaps);
+                if (image)
+                    texture = create(image, generateMipmaps);
                 SAFE_RELEASE(image);
                 SAFE_RELEASE(image);
             }
             }
             break;
             break;

+ 14 - 5
gameplay/src/Vector2.h

@@ -323,7 +323,7 @@ public:
      * @param v The vector to add.
      * @param v The vector to add.
      * @return The vector sum.
      * @return The vector sum.
      */
      */
-    inline Vector2 operator+(const Vector2& v) const;
+    inline const Vector2 operator+(const Vector2& v) const;
 
 
     /**
     /**
      * Adds the given vector to this vector.
      * Adds the given vector to this vector.
@@ -341,7 +341,7 @@ public:
      * @param v The vector to add.
      * @param v The vector to add.
      * @return The vector sum.
      * @return The vector sum.
      */
      */
-    inline Vector2 operator-(const Vector2& v) const;
+    inline const Vector2 operator-(const Vector2& v) const;
 
 
     /**
     /**
      * Subtracts the given vector from this vector.
      * Subtracts the given vector from this vector.
@@ -358,7 +358,7 @@ public:
      * 
      * 
      * @return The negation of this vector.
      * @return The negation of this vector.
      */
      */
-    inline Vector2 operator-() const;
+    inline const Vector2 operator-() const;
 
 
     /**
     /**
      * Calculates the scalar product of this vector with the given value.
      * Calculates the scalar product of this vector with the given value.
@@ -368,7 +368,7 @@ public:
      * @param x The value to scale by.
      * @param x The value to scale by.
      * @return The scaled vector.
      * @return The scaled vector.
      */
      */
-    inline Vector2 operator*(float x) const;
+    inline const Vector2 operator*(float x) const;
 
 
     /**
     /**
      * Scales this vector by the given value.
      * Scales this vector by the given value.
@@ -395,6 +395,15 @@ public:
      * @return True if this vector is equal to the given vector, false otherwise.
      * @return True if this vector is equal to the given vector, false otherwise.
      */
      */
     inline bool operator==(const Vector2& v) const;
     inline bool operator==(const Vector2& v) const;
+
+    /**
+     * Determines if this vector is not equal to the given vector.
+     * 
+     * @param v The vector to compare against.
+     * 
+     * @return True if this vector is not equal to the given vector, false otherwise.
+     */
+    inline bool operator!=(const Vector2& v) const;
 };
 };
 
 
 /**
 /**
@@ -404,7 +413,7 @@ public:
  * @param v The vector to scale.
  * @param v The vector to scale.
  * @return The scaled vector.
  * @return The scaled vector.
  */
  */
-inline Vector2 operator*(float x, const Vector2& v);
+inline const Vector2 operator*(float x, const Vector2& v);
 
 
 }
 }
 
 

+ 10 - 5
gameplay/src/Vector2.inl

@@ -3,7 +3,7 @@
 namespace gameplay
 namespace gameplay
 {
 {
 
 
-inline Vector2 Vector2::operator+(const Vector2& v) const
+inline const Vector2 Vector2::operator+(const Vector2& v) const
 {
 {
     Vector2 result(*this);
     Vector2 result(*this);
     result.add(v);
     result.add(v);
@@ -16,7 +16,7 @@ inline Vector2& Vector2::operator+=(const Vector2& v)
     return *this;
     return *this;
 }
 }
 
 
-inline Vector2 Vector2::operator-(const Vector2& v) const
+inline const Vector2 Vector2::operator-(const Vector2& v) const
 {
 {
     Vector2 result(*this);
     Vector2 result(*this);
     result.subtract(v);
     result.subtract(v);
@@ -29,14 +29,14 @@ inline Vector2& Vector2::operator-=(const Vector2& v)
     return *this;
     return *this;
 }
 }
 
 
-inline Vector2 Vector2::operator-() const
+inline const Vector2 Vector2::operator-() const
 {
 {
     Vector2 result(*this);
     Vector2 result(*this);
     result.negate();
     result.negate();
     return result;
     return result;
 }
 }
 
 
-inline Vector2 Vector2::operator*(float x) const
+inline const Vector2 Vector2::operator*(float x) const
 {
 {
     Vector2 result(*this);
     Vector2 result(*this);
     result.scale(x);
     result.scale(x);
@@ -63,7 +63,12 @@ inline bool Vector2::operator==(const Vector2& v) const
     return x==v.x && y==v.y;
     return x==v.x && y==v.y;
 }
 }
 
 
-inline Vector2 operator*(float x, const Vector2& v)
+inline bool Vector2::operator!=(const Vector2& v) const
+{
+    return x!=v.x || y!=v.y;
+}
+
+inline const Vector2 operator*(float x, const Vector2& v)
 {
 {
     Vector2 result(v);
     Vector2 result(v);
     result.scale(x);
     result.scale(x);

+ 12 - 5
gameplay/src/Vector3.h

@@ -1,6 +1,8 @@
 #ifndef VECTOR3_H_
 #ifndef VECTOR3_H_
 #define VECTOR3_H_
 #define VECTOR3_H_
 
 
+class btVector3;
+
 namespace gameplay
 namespace gameplay
 {
 {
 
 
@@ -353,7 +355,7 @@ public:
      * @param v The vector to add.
      * @param v The vector to add.
      * @return The vector sum.
      * @return The vector sum.
      */
      */
-    inline Vector3 operator+(const Vector3& v) const;
+    inline const Vector3 operator+(const Vector3& v) const;
 
 
     /**
     /**
      * Adds the given vector to this vector.
      * Adds the given vector to this vector.
@@ -371,7 +373,7 @@ public:
      * @param v The vector to add.
      * @param v The vector to add.
      * @return The vector sum.
      * @return The vector sum.
      */
      */
-    inline Vector3 operator-(const Vector3& v) const;
+    inline const Vector3 operator-(const Vector3& v) const;
 
 
     /**
     /**
      * Subtracts the given vector from this vector.
      * Subtracts the given vector from this vector.
@@ -388,7 +390,7 @@ public:
      * 
      * 
      * @return The negation of this vector.
      * @return The negation of this vector.
      */
      */
-    inline Vector3 operator-() const;
+    inline const Vector3 operator-() const;
 
 
     /**
     /**
      * Calculates the scalar product of this vector with the given value.
      * Calculates the scalar product of this vector with the given value.
@@ -398,7 +400,7 @@ public:
      * @param x The value to scale by.
      * @param x The value to scale by.
      * @return The scaled vector.
      * @return The scaled vector.
      */
      */
-    inline Vector3 operator*(float x) const;
+    inline const Vector3 operator*(float x) const;
 
 
     /**
     /**
      * Scales this vector by the given value.
      * Scales this vector by the given value.
@@ -425,6 +427,11 @@ public:
      * @return True if this vector is equal to the given vector, false otherwise.
      * @return True if this vector is equal to the given vector, false otherwise.
      */
      */
     inline bool operator==(const Vector3& v) const;
     inline bool operator==(const Vector3& v) const;
+
+    /**
+     * Defines implicit conversion operator to the Bullet btVector3 type.
+     */
+    inline operator btVector3() const;
 };
 };
 
 
 /**
 /**
@@ -434,7 +441,7 @@ public:
  * @param v The vector to scale.
  * @param v The vector to scale.
  * @return The scaled vector.
  * @return The scaled vector.
  */
  */
-inline Vector3 operator*(float x, const Vector3& v);
+inline const Vector3 operator*(float x, const Vector3& v);
 
 
 }
 }
 
 

+ 11 - 5
gameplay/src/Vector3.inl

@@ -1,10 +1,11 @@
 #include "Vector3.h"
 #include "Vector3.h"
 #include "Matrix.h"
 #include "Matrix.h"
+#include "Base.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
 
 
-inline Vector3 Vector3::operator+(const Vector3& v) const
+inline const Vector3 Vector3::operator+(const Vector3& v) const
 {
 {
     Vector3 result(*this);
     Vector3 result(*this);
     result.add(v);
     result.add(v);
@@ -17,7 +18,7 @@ inline Vector3& Vector3::operator+=(const Vector3& v)
     return *this;
     return *this;
 }
 }
 
 
-inline Vector3 Vector3::operator-(const Vector3& v) const
+inline const Vector3 Vector3::operator-(const Vector3& v) const
 {
 {
     Vector3 result(*this);
     Vector3 result(*this);
     result.subtract(v);
     result.subtract(v);
@@ -30,14 +31,14 @@ inline Vector3& Vector3::operator-=(const Vector3& v)
     return *this;
     return *this;
 }
 }
 
 
-inline Vector3 Vector3::operator-() const
+inline const Vector3 Vector3::operator-() const
 {
 {
     Vector3 result(*this);
     Vector3 result(*this);
     result.negate();
     result.negate();
     return result;
     return result;
 }
 }
 
 
-inline Vector3 Vector3::operator*(float x) const
+inline const Vector3 Vector3::operator*(float x) const
 {
 {
     Vector3 result(*this);
     Vector3 result(*this);
     result.scale(x);
     result.scale(x);
@@ -68,7 +69,12 @@ inline bool Vector3::operator==(const Vector3& v) const
     return x==v.x && y==v.y && z==v.z;
     return x==v.x && y==v.y && z==v.z;
 }
 }
 
 
-inline Vector3 operator*(float x, const Vector3& v)
+inline Vector3::operator btVector3() const
+{
+    return btVector3(x, y, z);
+}
+
+inline const Vector3 operator*(float x, const Vector3& v)
 {
 {
     Vector3 result(v);
     Vector3 result(v);
     result.scale(x);
     result.scale(x);

+ 14 - 5
gameplay/src/Vector4.h

@@ -348,7 +348,7 @@ public:
      * @param v The vector to add.
      * @param v The vector to add.
      * @return The vector sum.
      * @return The vector sum.
      */
      */
-    inline Vector4 operator+(const Vector4& v) const;
+    inline const Vector4 operator+(const Vector4& v) const;
 
 
     /**
     /**
      * Adds the given vector to this vector.
      * Adds the given vector to this vector.
@@ -366,7 +366,7 @@ public:
      * @param v The vector to add.
      * @param v The vector to add.
      * @return The vector sum.
      * @return The vector sum.
      */
      */
-    inline Vector4 operator-(const Vector4& v) const;
+    inline const Vector4 operator-(const Vector4& v) const;
 
 
     /**
     /**
      * Subtracts the given vector from this vector.
      * Subtracts the given vector from this vector.
@@ -383,7 +383,7 @@ public:
      * 
      * 
      * @return The negation of this vector.
      * @return The negation of this vector.
      */
      */
-    inline Vector4 operator-() const;
+    inline const Vector4 operator-() const;
 
 
     /**
     /**
      * Calculates the scalar product of this vector with the given value.
      * Calculates the scalar product of this vector with the given value.
@@ -393,7 +393,7 @@ public:
      * @param x The value to scale by.
      * @param x The value to scale by.
      * @return The scaled vector.
      * @return The scaled vector.
      */
      */
-    inline Vector4 operator*(float x) const;
+    inline const Vector4 operator*(float x) const;
 
 
     /**
     /**
      * Scales this vector by the given value.
      * Scales this vector by the given value.
@@ -420,6 +420,15 @@ public:
      * @return True if this vector is equal to the given vector, false otherwise.
      * @return True if this vector is equal to the given vector, false otherwise.
      */
      */
     inline bool operator==(const Vector4& v) const;
     inline bool operator==(const Vector4& v) const;
+
+    /**
+     * Determines if this vector is not equal to the given vector.
+     * 
+     * @param v The vector to compare against.
+     * 
+     * @return True if this vector is not equal to the given vector, false otherwise.
+     */
+    inline bool operator!=(const Vector4& v) const;
 };
 };
 
 
 /**
 /**
@@ -429,7 +438,7 @@ public:
  * @param v The vector to scale.
  * @param v The vector to scale.
  * @return The scaled vector.
  * @return The scaled vector.
  */
  */
-inline Vector4 operator*(float x, const Vector4& v);
+inline const Vector4 operator*(float x, const Vector4& v);
 
 
 }
 }
 
 

+ 10 - 5
gameplay/src/Vector4.inl

@@ -4,7 +4,7 @@
 namespace gameplay
 namespace gameplay
 {
 {
 
 
-inline Vector4 Vector4::operator+(const Vector4& v) const
+inline const Vector4 Vector4::operator+(const Vector4& v) const
 {
 {
     Vector4 result(*this);
     Vector4 result(*this);
     result.add(v);
     result.add(v);
@@ -17,7 +17,7 @@ inline Vector4& Vector4::operator+=(const Vector4& v)
     return *this;
     return *this;
 }
 }
 
 
-inline Vector4 Vector4::operator-(const Vector4& v) const
+inline const Vector4 Vector4::operator-(const Vector4& v) const
 {
 {
     Vector4 result(*this);
     Vector4 result(*this);
     result.subtract(v);
     result.subtract(v);
@@ -30,14 +30,14 @@ inline Vector4& Vector4::operator-=(const Vector4& v)
     return *this;
     return *this;
 }
 }
 
 
-inline Vector4 Vector4::operator-() const
+inline const Vector4 Vector4::operator-() const
 {
 {
     Vector4 result(*this);
     Vector4 result(*this);
     result.negate();
     result.negate();
     return result;
     return result;
 }
 }
 
 
-inline Vector4 Vector4::operator*(float x) const
+inline const Vector4 Vector4::operator*(float x) const
 {
 {
     Vector4 result(*this);
     Vector4 result(*this);
     result.scale(x);
     result.scale(x);
@@ -75,7 +75,12 @@ inline bool Vector4::operator==(const Vector4& v) const
     return x==v.x && y==v.y && z==v.z && w==v.w;
     return x==v.x && y==v.y && z==v.z && w==v.w;
 }
 }
 
 
-inline Vector4 operator*(float x, const Vector4& v)
+inline bool Vector4::operator!=(const Vector4& v) const
+{
+    return x!=v.x || y!=v.y || z!=v.z || w!=v.w;
+}
+
+inline const Vector4 operator*(float x, const Vector4& v)
 {
 {
     Vector4 result(v);
     Vector4 result(v);
     result.scale(x);
     result.scale(x);

+ 2 - 1
gameplay/src/gameplay-main-ios.mm

@@ -4,11 +4,12 @@
 
 
 using namespace gameplay;
 using namespace gameplay;
 
 
+
 /**
 /**
  * Main entry point.
  * Main entry point.
  */
  */
 int main(int argc, char** argv)
 int main(int argc, char** argv)
-{
+{    
     Game* game = Game::getInstance();
     Game* game = Game::getInstance();
     assert(game != NULL);
     assert(game != NULL);
     Platform* platform = Platform::create(game);
     Platform* platform = Platform::create(game);