Selaa lähdekoodia

- Updated character sample.
- Added PhysicsCharacter class for supporting character movement and animation with basic physics simulation.

Steve Grenier 14 vuotta sitten
vanhempi
sitoutus
406c3651d0
48 muutettua tiedostoa jossa 1084 lisäystä ja 426 poistoa
  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. 71 38
      gameplay-encoder/src/DAESceneEncoder.cpp
  8. 88 39
      gameplay-encoder/src/FBXSceneEncoder.cpp
  9. 119 0
      gameplay-encoder/src/GPBFile.cpp
  10. 11 0
      gameplay-encoder/src/GPBFile.h
  11. 2 2
      gameplay-encoder/src/Node.cpp
  12. 1 1
      gameplay-encoder/src/Node.h
  13. 89 0
      gameplay-encoder/src/Transform.cpp
  14. 11 0
      gameplay-encoder/src/Transform.h
  15. 18 12
      gameplay-encoder/src/Vertex.cpp
  16. 21 7
      gameplay-encoder/src/Vertex.h
  17. 1 3
      gameplay/.cproject
  18. 0 12
      gameplay/.project
  19. 2 0
      gameplay/gameplay.vcxproj
  20. 6 0
      gameplay/gameplay.vcxproj.filters
  21. 121 71
      gameplay/src/AnimationClip.cpp
  22. 22 13
      gameplay/src/AnimationClip.h
  23. 6 18
      gameplay/src/AnimationController.cpp
  24. 1 8
      gameplay/src/Base.h
  25. 10 7
      gameplay/src/Game.cpp
  26. 4 12
      gameplay/src/Game.h
  27. 8 7
      gameplay/src/Mouse.h
  28. 1 1
      gameplay/src/PhysicsConstraint.cpp
  29. 34 13
      gameplay/src/PhysicsController.cpp
  30. 3 1
      gameplay/src/PhysicsController.h
  31. 1 0
      gameplay/src/PhysicsFixedConstraint.cpp
  32. 1 1
      gameplay/src/PhysicsGenericConstraint.cpp
  33. 1 1
      gameplay/src/PhysicsHingeConstraint.cpp
  34. 1 0
      gameplay/src/PhysicsMotionState.cpp
  35. 1 0
      gameplay/src/PhysicsMotionState.h
  36. 5 4
      gameplay/src/PhysicsRigidBody.cpp
  37. 37 6
      gameplay/src/PhysicsRigidBody.h
  38. 11 1
      gameplay/src/PhysicsRigidBody.inl
  39. 1 1
      gameplay/src/PhysicsSocketConstraint.cpp
  40. 1 1
      gameplay/src/PhysicsSpringConstraint.cpp
  41. 14 0
      gameplay/src/Platform.h
  42. 11 1
      gameplay/src/PlatformAndroid.cpp
  43. 91 10
      gameplay/src/PlatformMacOS.mm
  44. 19 9
      gameplay/src/PlatformQNX.cpp
  45. 27 8
      gameplay/src/PlatformWin32.cpp
  46. 141 99
      gameplay/src/PlatformiOS.mm
  47. 2 1
      gameplay/src/gameplay-main-ios.mm
  48. 2 1
      gameplay/src/gameplay.h

+ 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)
   * Example: fbxsdk-2012.2-mdd.lib;wininet.lib
 - 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
 
 ### 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);
 }
 
+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
 {
     return _channels.size();
@@ -58,6 +67,7 @@ unsigned int Animation::getAnimationChannelCount() const
 
 AnimationChannel* Animation::getAnimationChannel(unsigned int index) const
 {
+    assert(index < _channels.size());
     return _channels[index];
 }
 

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

@@ -26,8 +26,20 @@ public:
     virtual void writeBinary(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);
 
+    /**
+     * 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.
      * 
@@ -36,7 +48,11 @@ public:
     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;
 

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

@@ -43,7 +43,7 @@ void AnimationChannel::writeText(FILE* file)
 {
     fprintElementStart(file);
     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 ", "values", _keyValues);
     fprintfElement(file, "%f ", "tangentsIn", _tangentsIn);
@@ -130,27 +130,29 @@ void AnimationChannel::setInterpolations(const std::vector<unsigned int>& values
 
 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;
 
         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;
         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)
                 {
-                    deleteRange(prevIndex+1, i);
+                    deleteRange(prevIndex+1, i, propSize);
                     i = prevIndex;
-                    prevStart = _keyValues.begin() + i * 10;
-                    prevEnd = _keyValues.begin() + (i * 10 + 9);
+                    prevStart = _keyValues.begin() + i * propSize;
+                    prevEnd = prevStart + propSize - 1;
                 }
                 else
                 {
@@ -162,7 +164,7 @@ void AnimationChannel::removeDuplicates()
         }
         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;
 }
 
-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
     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);
 
     a = _keytimes.begin() + begin;
@@ -286,9 +289,11 @@ void AnimationChannel::deleteRange(size_t begin, size_t end)
     if (_interpolations.size() > 1)
     {
         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);
     }
+
+    // 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<unsigned int>& getInterpolationTypes() const;
 
+    /**
+     * Removes duplicate key frames from the animation channel.
+     */
     void removeDuplicates();
 
     void convertToQuaternion();
@@ -77,7 +80,15 @@ public:
 
 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:
 
     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)
 
+// Object deletion macro
+#define SAFE_DELETE(x) \
+    if (x) \
+    { \
+        delete x; \
+        x = NULL; \
+    }
+
 #ifdef NDEBUG
 #define DEBUGPRINT(x)
 #define DEBUGPRINT_VARG(x, ...)

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

@@ -1240,9 +1240,9 @@ void DAESceneEncoder::loadSkeleton(domInstance_controller::domSkeleton* skeleton
     for (std::vector<std::string>::const_iterator i = jointNames.begin(); i != jointNames.end(); 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);
         }
     }
@@ -1673,10 +1673,9 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
             {
                 maxOffset = offset;
             }
-            int type = polygonInputs[k]->type;
-
             unsigned int polyIndex = (unsigned int) polyInts.get(poly + offset);
-            switch (type)
+
+            switch (polygonInputs[k]->type)
             {
             case POSITION:
                 vertex = Vertex(); // TODO
@@ -1707,16 +1706,52 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
                 vertex.normal.z = (float)source.get(polyIndex * 3 + 2);
                 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:
                 vertex.hasTangent = true;
@@ -1786,7 +1821,7 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
     }
     
     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 hasBinormals = mesh->vertices[0].hasBinormal;
     bool hasTexCoords = mesh->vertices[0].hasTexCoord;
@@ -1796,38 +1831,38 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
     // It should be the same order as how the Vertex data is written.
 
     // Position
-    mesh->addVetexAttribute(POSITION, 3);
+    mesh->addVetexAttribute(POSITION, Vertex::POSITION_COUNT);
     
     // Normals
     if (hasNormals)
     {
-        mesh->addVetexAttribute(NORMAL, 3);
+        mesh->addVetexAttribute(NORMAL, Vertex::NORMAL_COUNT);
     }
     // Tangents
     if (hasTangents)
     {
-        mesh->addVetexAttribute(TANGENT, 3);
+        mesh->addVetexAttribute(TANGENT, Vertex::TANGENT_COUNT);
     }
     // Binormals
     if (hasBinormals)
     {
-        mesh->addVetexAttribute(BINORMAL, 3);
+        mesh->addVetexAttribute(BINORMAL, Vertex::BINORMAL_COUNT);
     }
     // Texture Coordinates
     if (hasTexCoords)
     {
-        mesh->addVetexAttribute(TEXCOORD0, 2);
+        mesh->addVetexAttribute(TEXCOORD0, Vertex::TEXCOORD_COUNT);
     }
     // Diffuse Color
-    if (hasColors)
+    if (hasDiffuses)
     {
-        mesh->addVetexAttribute(COLOR, 3);
+        mesh->addVetexAttribute(COLOR, Vertex::DIFFUSE_COUNT);
     }
     // 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);
@@ -1846,7 +1881,6 @@ void DAESceneEncoder::warning(const char* message)
 
 int DAESceneEncoder::getVertexUsageType(const std::string& semantic)
 {
-    int type = -1;
     if (semantic.length() > 0)
     {
         switch (semantic[0])
@@ -1854,48 +1888,47 @@ int DAESceneEncoder::getVertexUsageType(const std::string& semantic)
         case 'P':
             if (equals(semantic, "POSITION"))
             {
-                type = POSITION;
+                return POSITION;
             }
-            break;
         case 'N':
             if (equals(semantic, "NORMAL"))
             {
-                type = NORMAL;
+                return NORMAL;
             }
         case 'C':
             if (equals(semantic, "COLOR"))
             {
-                type = COLOR;
+                return COLOR;
             }
         case 'T':
             if (equals(semantic, "TANGENT"))
             {
-                type = TANGENT;
+                return TANGENT;
             }
             else if (equals(semantic, "TEXCOORD"))
             {
-                type = TEXCOORD0;
+                return TEXCOORD0;
             }
             else if (equals(semantic, "TEXTANGENT"))
             {
                 // Treat TEXTANGENT as TANGENT
-                type = TANGENT;
+                return TANGENT;
             }
             else if (equals(semantic, "TEXBINORMAL"))
             {
                 // Treat TEXBINORMAL as BINORMAL
-                type = BINORMAL;
+                return BINORMAL;
             }
         case 'B':
             if (equals(semantic, "BINORMAL"))
             {
-                type = BINORMAL;
+                return BINORMAL;
             }
         default:
-            break;
+            return -1;
         }
     }
-    return type;
+    return -1;
 }
 
 DAESceneEncoder::DAEPolygonInput::DAEPolygonInput(void) :

+ 88 - 39
gameplay-encoder/src/FBXSceneEncoder.cpp

@@ -63,6 +63,15 @@ void loadTangent(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
  */
 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.
+ */
+void loadVertexColor(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
+
 /**
  * Loads the blend weight and blend indices data into the vertex.
  * 
@@ -778,7 +787,7 @@ Mesh* FBXSceneEncoder::loadMesh(KFbxMesh* fbxMesh)
             loadNormal(fbxMesh, vertexIndex, &vertex);
             loadTangent(fbxMesh, vertexIndex, &vertex);
             loadBinormal(fbxMesh, vertexIndex, &vertex);
-            // TODO: loadDiffuseColors
+            loadVertexColor(fbxMesh, vertexIndex, &vertex);
 
             if (hasSkin)
             {
@@ -819,39 +828,39 @@ Mesh* FBXSceneEncoder::loadMesh(KFbxMesh* fbxMesh)
     // It should be the same order as how the Vertex data is written.
 
     // Position
-    mesh->addVetexAttribute(POSITION, 3);
+    mesh->addVetexAttribute(POSITION, Vertex::POSITION_COUNT);
 
     const Vertex& vertex = mesh->vertices[0];
     // Normals
     if (vertex.hasNormal)
     {
-        mesh->addVetexAttribute(NORMAL, 3);
+        mesh->addVetexAttribute(NORMAL, Vertex::NORMAL_COUNT);
     }
     // Tangents
     if (vertex.hasTangent)
     {
-        mesh->addVetexAttribute(TANGENT, 3);
+        mesh->addVetexAttribute(TANGENT, Vertex::TANGENT_COUNT);
     }
     // Binormals
     if (vertex.hasBinormal)
     {
-        mesh->addVetexAttribute(BINORMAL, 3);
+        mesh->addVetexAttribute(BINORMAL, Vertex::BINORMAL_COUNT);
     }
     // Texture Coordinates
     if (vertex.hasTexCoord)
     {
-        mesh->addVetexAttribute(TEXCOORD0, 2);
+        mesh->addVetexAttribute(TEXCOORD0, Vertex::TEXCOORD_COUNT);
     }
     // Diffuse Color
-    if (vertex.hasColor)
+    if (vertex.hasDiffuse)
     {
-        mesh->addVetexAttribute(COLOR, 3);
+        mesh->addVetexAttribute(COLOR, Vertex::DIFFUSE_COUNT);
     }
     // Skinning BlendWeights BlendIndices
     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);
@@ -974,23 +983,23 @@ void loadTextureCoords(KFbxMesh* fbxMesh, int polyIndex, int posInPoly, Vertex*
     if (fbxMesh->GetElementUVCount() > 0)
     {
         // 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:
-            switch (leUV->GetReferenceMode())
+            switch (uv->GetReferenceMode())
             {
             case KFbxGeometryElement::eDIRECT:
                 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;
             case KFbxGeometryElement::eINDEX_TO_DIRECT:
                 {
-                    int id = leUV->GetIndexArray().GetAt(polyIndex);
+                    int id = uv->GetIndexArray().GetAt(polyIndex);
                     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;
             default:
@@ -1000,13 +1009,13 @@ void loadTextureCoords(KFbxMesh* fbxMesh, int polyIndex, int posInPoly, Vertex*
         case KFbxGeometryElement::eBY_POLYGON_VERTEX:
             {
                 int lTextureUVIndex = fbxMesh->GetTextureUVIndex(polyIndex, posInPoly);
-                switch (leUV->GetReferenceMode())
+                switch (uv->GetReferenceMode())
                 {
                 case KFbxGeometryElement::eDIRECT:
                 case KFbxGeometryElement::eINDEX_TO_DIRECT:
                     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;
                 default:
                     break;
@@ -1024,14 +1033,14 @@ void loadNormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
     if (fbxMesh->GetElementNormalCount() > 0)
     {
         // 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:
                 {
-                    KFbxVector4 vec4 = leNormal->GetDirectArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = normal->GetDirectArray().GetAt(vertexIndex);
                     vertex->hasNormal = true;
                     vertex->normal.x = (float)vec4[0];
                     vertex->normal.y = (float)vec4[1];
@@ -1040,8 +1049,8 @@ void loadNormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
                 break;
             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->normal.x = (float)vec4[0];
                     vertex->normal.y = (float)vec4[1];
@@ -1060,14 +1069,14 @@ void loadTangent(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
     if (fbxMesh->GetElementTangentCount() > 0)
     {
         // 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:
                 {
-                    KFbxVector4 vec4 = leTangent->GetDirectArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = tangent->GetDirectArray().GetAt(vertexIndex);
                     vertex->hasTangent = true;
                     vertex->tangent.x = (float)vec4[0];
                     vertex->tangent.y = (float)vec4[1];
@@ -1076,8 +1085,8 @@ void loadTangent(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
                 break;
             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->tangent.x = (float)vec4[0];
                     vertex->tangent.y = (float)vec4[1];
@@ -1096,14 +1105,14 @@ void loadBinormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
     if (fbxMesh->GetElementBinormalCount() > 0)
     {
         // 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:
                 {
-                    KFbxVector4 vec4 = leBinormal->GetDirectArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = binormal->GetDirectArray().GetAt(vertexIndex);
                     vertex->hasBinormal = true;
                     vertex->binormal.x = (float)vec4[0];
                     vertex->binormal.y = (float)vec4[1];
@@ -1112,8 +1121,8 @@ void loadBinormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
                 break;
             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->binormal.x = (float)vec4[0];
                     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)
 {
     size_t size = vertexWeights.size();

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

@@ -1,11 +1,19 @@
 #include "Base.h"
 #include "GPBFile.h"
+#include "Transform.h"
+
+#define EPSILON 1.2e-7f;
 
 namespace gameplay
 {
 
 static GPBFile* __instance = NULL;
 
+/**
+ * Returns true if the given value is close to one.
+ */
+static bool isAlmostOne(float value);
+
 GPBFile::GPBFile(void)
     : _file(NULL), _animationsAdded(false)
 {
@@ -245,6 +253,9 @@ void GPBFile::adjust()
         }
     }
 
+    // try to convert joint transform animations into rotation animations
+    //optimizeTransformAnimations(); // TODO: Fix bounding sphere before re-enabling this
+
     // TODO:
     // remove ambient _lights
     // for each node
@@ -259,4 +270,112 @@ void GPBFile::adjust()
     //   This can be merged into one animation. Same for scale animations.
 }
 
+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;
+}
+
 }

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

@@ -98,6 +98,17 @@ public:
      */
     void adjust();
 
+private:
+    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:
 
     FILE* _file;

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

@@ -296,7 +296,7 @@ void Node::setIsJoint(bool value)
     _joint = value;
 }
 
-bool Node::isJoint()
+bool Node::isJoint() const
 {
     return _joint;
 }
@@ -324,7 +324,7 @@ Node* Node::getFirstCameraNode() const
 {
     if (hasCamera())
     {
-        return (Node*)this;
+        return const_cast<Node*>(this);
     }
     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.
      */
-    bool isJoint();
+    bool isJoint() const;
 
     Node* getFirstCameraNode() const;
 

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

@@ -1,2 +1,91 @@
 #include "Base.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_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)
-    : 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 count = 3;
+    unsigned int count = POSITION_COUNT;
     if (hasNormal)
-        count += 3;
+        count += NORMAL_COUNT;
     if (hasTangent)
-        count += 3;
+        count += TANGENT_COUNT;
     if (hasBinormal)
-        count += 3;
+        count += BINORMAL_COUNT;
     if (hasTexCoord)
-        count += 2;
+        count += TEXCOORD_COUNT;
     if (hasWeights)
-        count += 8;
+        count += BLEND_WEIGHTS_COUNT + BLEND_INDICES_COUNT;
+    if (hasDiffuse)
+        count += DIFFUSE_COUNT;
     return count * sizeof(float);
 }
 
@@ -48,11 +50,10 @@ void Vertex::writeBinary(FILE* file) const
     {
         writeVectorBinary(texCoord, file);
     }
-    // TODO add vertex color?
-    //if (hasColor)
-    //{
-    //    writeVectorBinary(color, file);
-    //}
+    if (hasDiffuse)
+    {
+        writeVectorBinary(diffuse, file);
+    }
     if (hasWeights)
     {
         writeVectorBinary(blendWeights, file);
@@ -84,6 +85,11 @@ void Vertex::writeText(FILE* file) const
         write("// texCoord\n", file);
         writeVectorText(texCoord, file);
     }
+    if (hasDiffuse)
+    {
+        write("// diffuse\n", file);
+        writeVectorText(diffuse, file);
+    }
     if (hasWeights)
     {
         write("// blendWeights\n", file);

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

@@ -13,6 +13,15 @@ class Vertex
 {
 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.
      */
@@ -28,11 +37,12 @@ public:
     Vector3 tangent;
     Vector3 binormal;
     Vector2 texCoord;
+    Vector4 diffuse;
 
     Vector4 blendWeights;
     Vector4 blendIndices;
 
-    bool hasNormal, hasTangent, hasBinormal, hasTexCoord, hasColor, hasWeights;
+    bool hasNormal, hasTangent, hasBinormal, hasTexCoord, hasDiffuse, hasWeights;
 
     inline bool operator<(const Vertex& v) const
     {
@@ -46,15 +56,19 @@ public:
                     {
                         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;
                     }
@@ -70,7 +84,7 @@ public:
     inline bool operator==(const Vertex& v) const
     {
         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;
     }
 
     /**

+ 1 - 3
gameplay/.cproject

@@ -9,8 +9,6 @@
 				<extensions>
 					<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.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
-					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
 				</extensions>
 			</storageModule>
 			<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">
 							<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"/>
-							<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">
 								<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"/>

+ 0 - 12
gameplay/.project

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

+ 2 - 0
gameplay/gameplay.vcxproj

@@ -54,6 +54,7 @@
     <ClCompile Include="src\Node.cpp" />
     <ClCompile Include="src\Package.cpp" />
     <ClCompile Include="src\ParticleEmitter.cpp" />
+    <ClCompile Include="src\PhysicsCharacter.cpp" />
     <ClCompile Include="src\PhysicsConstraint.cpp" />
     <ClCompile Include="src\PhysicsController.cpp" />
     <ClCompile Include="src\PhysicsFixedConstraint.cpp" />
@@ -128,6 +129,7 @@
     <ClInclude Include="src\Node.h" />
     <ClInclude Include="src\Package.h" />
     <ClInclude Include="src\ParticleEmitter.h" />
+    <ClInclude Include="src\PhysicsCharacter.h" />
     <ClInclude Include="src\PhysicsConstraint.h" />
     <ClInclude Include="src\PhysicsController.h" />
     <ClInclude Include="src\PhysicsFixedConstraint.h" />

+ 6 - 0
gameplay/gameplay.vcxproj.filters

@@ -228,6 +228,9 @@
     <ClCompile Include="src\PlatformAndroid.cpp">
       <Filter>src</Filter>
     </ClCompile>
+    <ClCompile Include="src\PhysicsCharacter.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\Animation.h">
@@ -443,6 +446,9 @@
     <ClInclude Include="src\Mouse.h">
       <Filter>src</Filter>
     </ClInclude>
+    <ClInclude Include="src\PhysicsCharacter.h">
+      <Filter>src</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="res\shaders\bumped-specular.vsh">

+ 121 - 71
gameplay/src/AnimationClip.cpp

@@ -9,10 +9,10 @@ namespace gameplay
 {
 
 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);
     
@@ -37,6 +37,7 @@ AnimationClip::~AnimationClip()
     SAFE_DELETE(_beginListeners);
     SAFE_DELETE(_endListeners);
     SAFE_DELETE(_listeners);
+    SAFE_DELETE(_listenerItr);
 }
 
 const char* AnimationClip::getID() const
@@ -129,22 +130,29 @@ float AnimationClip::getBlendWeight() const
 
 bool AnimationClip::isPlaying() const
 {
-    return _isPlaying;
+    return isClipStateBitSet(CLIP_IS_PLAYING_BIT);
 }
 
 void AnimationClip::play()
 {
+    if (isClipStateBitSet(CLIP_IS_PLAYING_BIT))
+    {
+        onEnd();
+        _animation->_controller->unschedule(this);
+    }
+    
+    setClipStateBit(CLIP_IS_PLAYING_BIT);
+    
     _animation->_controller->schedule(this);
     _timeStarted = Game::getGameTime();
 }
 
 void AnimationClip::stop()
 {
-    _animation->_controller->unschedule(this);
-    if (_isPlaying)
+    if (isClipStateBitSet(CLIP_IS_PLAYING_BIT))
     {
-        _isPlaying = false;
         onEnd();
+        _animation->_controller->unschedule(this);
     }
 }
 
@@ -152,27 +160,37 @@ void AnimationClip::crossFade(AnimationClip* clip, unsigned long duration)
 {
     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.
     // 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)
+    {
         SAFE_RELEASE(_crossFadeToClip);
-        
+    }
+
+    // Set and initialize the crossfade clip
     _crossFadeToClip = clip;
     _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;
     
-    // 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;
-    _isFadingOutStarted = true;
     
     // If this clip is currently not playing, we should start playing it.
-    if (!_isPlaying)
+    if (!isClipStateBitSet(CLIP_IS_PLAYING_BIT))
         play();
 
     // Start playing the cross fade clip.
@@ -188,29 +206,30 @@ void AnimationClip::addListener(AnimationClip::Listener* listener, unsigned long
 
     if (!_listeners)
     {
-        _listeners = new ListenerList;
-        _listeners->_list.push_front(listener);
-        if (_isPlaying)
-            _listeners->_listItr = _listeners->_list.begin();
+        _listeners = new std::list<Listener*>;
+        _listeners->push_front(listener);
+
+        _listenerItr = new std::list<Listener*>::iterator;
+        if (isClipStateBitSet(CLIP_IS_PLAYING_BIT))
+            *_listenerItr = _listeners->begin();
     }
     else
     {
-        for (std::list<Listener*>::iterator itr = _listeners->_list.begin(); itr != _listeners->_list.begin(); itr++)
+        for (std::list<Listener*>::iterator itr = _listeners->begin(); itr != _listeners->begin(); itr++)
         {
             if (eventTime < (*itr)->_listenerTime)
             {
-                itr = _listeners->_list.insert(itr, listener);
+                itr = _listeners->insert(itr, listener);
 
                 // If playing, update the iterator if we need to.
                 // 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;
-                    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)->_listenerTime)) || 
+                        (_speed <= 0 && currentTime > eventTime && (*_listenerItr == _listeners->begin() || eventTime > (**_listenerItr)->_listenerTime)))
+                        *_listenerItr = itr;
                 }
-
                 return;
             }
         }
@@ -235,21 +254,34 @@ void AnimationClip::addEndListener(AnimationClip::Listener* listener)
 
 bool AnimationClip::update(unsigned long elapsedTime, std::list<AnimationTarget*>* activeTargets)
 {
-    if (!_isPlaying)
+    if (!isClipStateBitSet(CLIP_IS_STARTED_BIT))
         onBegin();
-    else 
+    else
+    {
         _elapsedTime += elapsedTime * _speed;
 
+        if (_repeatCount == REPEAT_INDEFINITE && _elapsedTime <= 0)
+            _elapsedTime = _activeDuration + _elapsedTime;
+    }
+
     unsigned long currentTime = 0L;
     // Check to see if clip is complete.
     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)
         {
-            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
         {
@@ -258,31 +290,43 @@ bool AnimationClip::update(unsigned long elapsedTime, std::list<AnimationTarget*
     }
     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.
     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() && currentTime >= (**_listenerItr)->_listenerTime)
+            {
+                (**_listenerItr)->animationEvent(this, Listener::DEFAULT);
+                ++*_listenerItr;
+            }
+        }
+        else
+        {
+            while (*_listenerItr != _listeners->begin() && currentTime <= (**_listenerItr)->_listenerTime)
+            {
+                (**_listenerItr)->animationEvent(this, Listener::DEFAULT);
+                --*_listenerItr;
+            }
         }
     }
 
     // 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;
     
-    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
         {
@@ -296,7 +340,7 @@ bool AnimationClip::update(unsigned long elapsedTime, std::list<AnimationTarget*
             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 (_isFadingIn)
+            if (isClipStateBitSet(CLIP_IS_FADING_IN_BIT))
             {
                 _crossFadeToClip->_blendWeight = (1.0f - tempBlendWeight) * _blendWeight;
                 _blendWeight -= _crossFadeToClip->_blendWeight;
@@ -310,21 +354,12 @@ bool AnimationClip::update(unsigned long elapsedTime, std::list<AnimationTarget*
         }
         else
         {   // Fade is done.
-            // Set the crossFadeToClip's blend weight to 1
             _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);
-            _blendWeight = 0.0f; 
-            _isFadingOut = false;
-            _isPlaying = false;
         }
     }
     
@@ -352,7 +387,7 @@ 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.
-    if (!_isPlaying)
+    if (!isClipStateBitSet(CLIP_IS_STARTED_BIT))
     {
         onEnd();
         // Notify end listeners if any.
@@ -365,33 +400,32 @@ bool AnimationClip::update(unsigned long elapsedTime, std::list<AnimationTarget*
                 listener++;
             }
         }
+
+        return true;
     }
 
-    return !_isPlaying;
+    return false;
 }
 
 void AnimationClip::onBegin()
 {
     // Initialize animation to play.
-    _isPlaying = true;
-
+    setClipStateBit(CLIP_IS_STARTED_BIT);
     if (_speed >= 0)
     {
-        _elapsedTime = 0;
+        _elapsedTime = (Game::getGameTime() - _timeStarted) * _speed;
 
         if (_listeners)
-            _listeners->_listItr = _listeners->_list.begin();
+            *_listenerItr = _listeners->begin(); 
     }
     else
     {
-        _elapsedTime = _activeDuration;
+        _elapsedTime = _activeDuration + (Game::getGameTime() - _timeStarted) * _speed;
 
         if (_listeners)
-            _listeners->_listItr = _listeners->_list.end();
+            *_listenerItr = _listeners->end();
     }
-
-    _elapsedTime += (Game::getGameTime() - _timeStarted) * _speed;
-
+    
     // Notify begin listeners.. if any.
     if (_beginListeners)
     {
@@ -408,6 +442,22 @@ void AnimationClip::onEnd()
 {
     _blendWeight = 1.0f;
     _timeStarted = 0;
+    resetClipStateBit(CLIP_ALL_BITS);
+}
+
+bool AnimationClip::isClipStateBitSet(char bit) const
+{
+    return (_stateBits & bit) == bit;
+}
+
+void AnimationClip::setClipStateBit(char bit)
+{
+    _stateBits |= bit;
+}
+
+void AnimationClip::resetClipStateBit(char bit)
+{
+    _stateBits &= ~bit;
 }
 
 }

+ 22 - 13
gameplay/src/AnimationClip.h

@@ -32,7 +32,7 @@ public:
      */
     class Listener
     {
-        friend AnimationClip;
+        friend class AnimationClip;
 
     public:
 
@@ -217,6 +217,12 @@ public:
     void addListener(AnimationClip::Listener* listener, unsigned long eventTime);
 
 private:
+    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_ALL_BITS = 0x1F;                   // Bit mask for all the state bits.
 
     /**
      * Constructor.
@@ -254,38 +260,41 @@ private:
     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;
+
+    /**
+     * 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.
-    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.
+    std::list<Listener*>* _listeners;               // Ordered collection of listeners on the clip.
+    std::list<Listener*>::iterator* _listenerItr;   // Iterator that points to the next listener event to be triggered.
 };
 
 }
-
 #endif

+ 6 - 18
gameplay/src/AnimationController.cpp

@@ -111,10 +111,8 @@ void AnimationController::stopAllAnimations()
     while (clipIter != _runningClips.end())
     {
         AnimationClip* clip = *clipIter;
-        clip->_isPlaying = false;
-        clip->onEnd();
-        SAFE_RELEASE(clip);
         clipIter++;
+        clip->stop();
     }
     _runningClips.clear();
 
@@ -147,7 +145,7 @@ Animation* AnimationController::createAnimation(const char* id, AnimationTarget*
     
     char delimeter = ' ';
     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];
     for (unsigned int i = 0; i < keyCount; i++)
@@ -165,7 +163,7 @@ Animation* AnimationController::createAnimation(const char* id, AnimationTarget*
     }
 
     startOffset = 0;
-    endOffset = std::string::npos;
+    endOffset = (unsigned int)std::string::npos;
     
     int componentCount = target->getAnimationPropertyComponentCount(propertyId);
     assert(componentCount > 0);
@@ -193,7 +191,7 @@ Animation* AnimationController::createAnimation(const char* id, AnimationTarget*
     {
         keyIn = new float[components];
         startOffset = 0;
-        endOffset = std::string::npos;
+        endOffset = (unsigned int)std::string::npos;
         for (unsigned int i = 0; i < components; i++)
         {
             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];
         startOffset = 0;
-        endOffset = std::string::npos;
+        endOffset = (unsigned int)std::string::npos;
         for (unsigned int i = 0; i < components; i++)
         {
             endOffset = static_cast<std::string>(keyOutStr).find_first_of(delimeter, startOffset);
@@ -294,18 +292,8 @@ void AnimationController::schedule(AnimationClip* clip)
     {
         _state = RUNNING;
     }
-    
-    if (clip->_isPlaying)
-    {
-        _runningClips.remove(clip);
-        clip->_isPlaying = false;
-        clip->onEnd();
-    }
-    else
-    {
-        clip->addRef();
-    }
 
+    clip->addRef();
     _runningClips.push_back(clip);
 }
 

+ 1 - 8
gameplay/src/Base.h

@@ -102,6 +102,7 @@ extern void printError(const char* format, ...);
 
 // Bullet Physics
 #include <btBulletDynamicsCommon.h>
+#include <BulletCollision/CollisionDispatch/btGhostObject.h>
 
 // Debug new for memory leak detection
 #include "DebugNew.h"
@@ -191,13 +192,9 @@ extern void printError(const char* format, ...);
     extern PFNGLISVERTEXARRAYOESPROC glIsVertexArray;
     #define glClearDepth glClearDepthf
     #define OPENGL_ES
-    #define WINDOW_WIDTH    1024
-    #define WINDOW_HEIGHT   600
 #elif WIN32
     #define WIN32_LEAN_AND_MEAN
     #include <GL/glew.h>
-    #define WINDOW_WIDTH    1024
-    #define WINDOW_HEIGHT   600
 #elif __APPLE__
     #include "TargetConditionals.h"
     #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
@@ -209,8 +206,6 @@ extern void printError(const char* format, ...);
         #define glIsVertexArray glIsVertexArrayOES
         #define glClearDepth glClearDepthf
         #define OPENGL_ES
-        #define WINDOW_WIDTH    480
-        #define WINDOW_HEIGHT   360
     #elif TARGET_OS_MAC
         #include <OpenGL/gl.h>
         #include <OpenGL/glext.h>
@@ -218,8 +213,6 @@ extern void printError(const char* format, ...);
         #define glDeleteVertexArrays glDeleteVertexArraysAPPLE
         #define glGenVertexArrays glGenVertexArraysAPPLE
         #define glIsVertexArray glIsVertexArrayAPPLE
-        #define WINDOW_WIDTH    960
-        #define WINDOW_HEIGHT   640
     #else
         #error "Unsupported Apple Device"
     #endif

+ 10 - 7
gameplay/src/Game.cpp

@@ -68,8 +68,15 @@ int Game::run(int width, int height)
     if (_state != UNINITIALIZED)
         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.
     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;
 }
 
-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.
      *
-     * @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.
      */
@@ -224,21 +224,13 @@ public:
      * @param evt The mouse event that occurred.
      * @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 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.
      *
      * @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.

+ 8 - 7
gameplay/src/Mouse.h

@@ -16,13 +16,14 @@ public:
      */
     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
     };
 
 

+ 1 - 1
gameplay/src/PhysicsConstraint.cpp

@@ -1,5 +1,5 @@
+#include "Base.h"
 #include "PhysicsConstraint.h"
-
 #include "Game.h"
 #include "Node.h"
 #include "PhysicsMotionState.h"

+ 34 - 13
gameplay/src/PhysicsController.cpp

@@ -13,8 +13,8 @@ namespace gameplay
 
 PhysicsController::PhysicsController()
   : _collisionConfiguration(NULL), _dispatcher(NULL),
-    _overlappingPairCache(NULL), _solver(NULL), _world(NULL), _debugDrawer(NULL), 
-    _status(PhysicsController::Listener::DEACTIVATED), _listeners(NULL),
+    _overlappingPairCache(NULL), _solver(NULL), _world(NULL), _ghostPairCallback(NULL),
+    _debugDrawer(NULL), _status(PhysicsController::Listener::DEACTIVATED), _listeners(NULL),
     _gravity(btScalar(0.0), btScalar(-9.8), btScalar(0.0))
 {
     // Default gravity is 9.8 along the negative Y axis.
@@ -22,6 +22,7 @@ PhysicsController::PhysicsController()
 
 PhysicsController::~PhysicsController()
 {
+    SAFE_DELETE(_ghostPairCallback);
     SAFE_DELETE(_debugDrawer);
     SAFE_DELETE(_listeners);
 }
@@ -135,6 +136,10 @@ void PhysicsController::initialize()
     _world = new btDiscreteDynamicsWorld(_dispatcher, _overlappingPairCache, _solver, _collisionConfiguration);
     _world->setGravity(btVector3(_gravity.x, _gravity.y, _gravity.z));
 
+    // Register ghost pair callback so bullet detects collisions with ghost objects (used for character collisions).
+    _ghostPairCallback = bullet_new<btGhostPairCallback>();
+    _world->getPairCache()->setInternalGhostPairCallback(_ghostPairCallback);
+
     // Set up debug drawing.
     _debugDrawer = new DebugDrawer();
     _world->setDebugDrawer(_debugDrawer);
@@ -144,6 +149,7 @@ void PhysicsController::finalize()
 {
     // Clean up the world and its various components.
     SAFE_DELETE(_world);
+    SAFE_DELETE(_ghostPairCallback);
     SAFE_DELETE(_solver);
     SAFE_DELETE(_overlappingPairCache);
     SAFE_DELETE(_dispatcher);
@@ -234,14 +240,22 @@ void PhysicsController::update(long elapsedTime)
     }
 
     // Go through the physics rigid bodies and update the collision listeners.
-    for (unsigned int i = 0; i < _bodies.size(); i++)
+    unsigned int size = _bodies.size();
+    unsigned int listenerCount = 0;
+    PhysicsRigidBody* body = NULL;
+    PhysicsRigidBody::Listener* listener = NULL;
+    PhysicsController* physicsController = Game::getInstance()->getPhysicsController();
+    for (unsigned int i = 0; i < size; i++)
     {
-        if (_bodies[i]->_listeners)
+        body = _bodies[i];
+        if (body->_listeners)
         {
-            for (unsigned int k = 0; k < _bodies[i]->_listeners->size(); k++)
+            listenerCount = body->_listeners->size();
+            for (unsigned int k = 0; k < listenerCount; k++)
             {
-                std::map<PhysicsRigidBody::CollisionPair, int>::iterator iter = (*_bodies[i]->_listeners)[k]->_collisionStatus.begin();
-                for (; iter != (*_bodies[i]->_listeners)[k]->_collisionStatus.end(); iter++)
+                listener = (*body->_listeners)[k];
+                std::map<PhysicsRigidBody::CollisionPair, int>::iterator iter = listener->_collisionStatus.begin();
+                for (; iter != listener->_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
@@ -249,9 +263,9 @@ void PhysicsController::update(long elapsedTime)
                     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]);
+                            physicsController->_world->contactPairTest(iter->first._rbA->_body, iter->first._rbB->_body, *listener);
                         else
-                            Game::getInstance()->getPhysicsController()->_world->contactTest(iter->first._rbA->_body, *(*_bodies[i]->_listeners)[k]);
+                            physicsController->_world->contactTest(iter->first._rbA->_body, *listener);
                     }
                 }   
             }
@@ -270,6 +284,11 @@ void PhysicsController::update(long elapsedTime)
                 {
                     if ((iter->second & PhysicsRigidBody::Listener::DIRTY) != 0)
                     {
+                        if ((iter->second & PhysicsRigidBody::Listener::COLLISION) != 0 && iter->first._rbB)
+                        {
+                            (*_bodies[i]->_listeners)[k]->collisionEvent(PhysicsRigidBody::Listener::NOT_COLLIDING, iter->first, Vector3::zero());
+                        }
+
                         iter->second &= ~PhysicsRigidBody::Listener::COLLISION;
                     }
                 }
@@ -407,7 +426,7 @@ btCollisionShape* PhysicsController::createSphere(float radius, const btVector3&
     return sphere;
 }
 
-btCollisionShape* PhysicsController::createMesh(PhysicsRigidBody* body)
+btCollisionShape* PhysicsController::createMesh(PhysicsRigidBody* body, const Vector3& scale)
 {
     assert(body);
 
@@ -443,8 +462,9 @@ btCollisionShape* PhysicsController::createMesh(PhysicsRigidBody* body)
 
     // Copy the scaled vertex position data to the rigid body's local buffer.
     Matrix m;
-    Matrix::createScale(body->_node->getScaleX(), body->_node->getScaleY(), body->_node->getScaleZ(), &m);
-    body->_vertexData = new float[data->vertexCount * 3];
+    Matrix::createScale(scale, &m);
+    unsigned int vertexCount = data->vertexCount;
+    body->_vertexData = new float[vertexCount * 3];
     Vector3 v;
     int vertexStride = data->vertexFormat.getVertexSize();
     for (unsigned int i = 0; i < data->vertexCount; i++)
@@ -495,7 +515,7 @@ btCollisionShape* PhysicsController::createMesh(PhysicsRigidBody* body)
             indexedMesh.m_numTriangles = meshPart->indexCount / 3; // assume TRIANGLES primitive type
             indexedMesh.m_numVertices = meshPart->indexCount;
             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_vertexStride = sizeof(float)*3;
             indexedMesh.m_vertexType = PHY_FLOAT;
@@ -611,6 +631,7 @@ PhysicsController::DebugDrawer::DebugDrawer()
         
     Effect* effect = Effect::createFromSource(vs_str, fs_str);
     Material* material = Material::create(effect);
+    material->getStateBlock()->setDepthTest(true);
 
     VertexFormat::Element elements[] =
     {

+ 3 - 1
gameplay/src/PhysicsController.h

@@ -20,6 +20,7 @@ class PhysicsController
     friend class Game;
     friend class PhysicsConstraint;
     friend class PhysicsRigidBody;
+    friend class PhysicsCharacter;
 
 public:
 
@@ -253,7 +254,7 @@ private:
     btCollisionShape* createSphere(float radius, const btVector3& scale);
 
     // 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.
     void addConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b, PhysicsConstraint* constraint);
@@ -302,6 +303,7 @@ private:
     btBroadphaseInterface* _overlappingPairCache;
     btSequentialImpulseConstraintSolver* _solver;
     btDynamicsWorld* _world;
+    btGhostPairCallback* _ghostPairCallback;
     std::vector<PhysicsCollisionShape*> _shapes;
     DebugDrawer* _debugDrawer;
     Listener::EventType _status;

+ 1 - 0
gameplay/src/PhysicsFixedConstraint.cpp

@@ -1,3 +1,4 @@
+#include "Base.h"
 #include "PhysicsFixedConstraint.h"
 
 namespace gameplay

+ 1 - 1
gameplay/src/PhysicsGenericConstraint.cpp

@@ -1,5 +1,5 @@
+#include "Base.h"
 #include "PhysicsGenericConstraint.h"
-
 #include "Node.h"
 #include "PhysicsMotionState.h"
 #include "PhysicsRigidBody.h"

+ 1 - 1
gameplay/src/PhysicsHingeConstraint.cpp

@@ -1,5 +1,5 @@
+#include "Base.h"
 #include "PhysicsHingeConstraint.h"
-
 #include "Node.h"
 
 namespace gameplay

+ 1 - 0
gameplay/src/PhysicsMotionState.cpp

@@ -1,3 +1,4 @@
+#include "Base.h"
 #include "PhysicsMotionState.h"
 
 namespace gameplay

+ 1 - 0
gameplay/src/PhysicsMotionState.h

@@ -15,6 +15,7 @@ namespace gameplay
 class PhysicsMotionState : public btMotionState
 {
     friend class PhysicsRigidBody;
+    friend class PhysicsCharacter;
     friend class PhysicsConstraint;
 
 protected:

+ 5 - 4
gameplay/src/PhysicsRigidBody.cpp

@@ -44,7 +44,7 @@ PhysicsRigidBody::PhysicsRigidBody(Node* node, PhysicsRigidBody::Type type, floa
         }
         case SHAPE_MESH:
         {
-            _shape = Game::getInstance()->getPhysicsController()->createMesh(this);
+            _shape = Game::getInstance()->getPhysicsController()->createMesh(this, node->getScale());
             break;
         }
     }
@@ -473,7 +473,6 @@ PhysicsRigidBody* PhysicsRigidBody::create(Node* node, Properties* properties)
     return body;
 }
 
-
 float PhysicsRigidBody::getHeight(float x, float y) const
 {
     // This function is only supported for heightfield rigid bodies.
@@ -583,11 +582,13 @@ btScalar PhysicsRigidBody::Listener::addSingleResult(btManifoldPoint& cp,
     if (_collisionStatus.count(pair) > 0)
     {
         if ((_collisionStatus[pair] & COLLISION) == 0)
-            collisionEvent(pair, Vector3(cp.getPositionWorldOnA().x(), cp.getPositionWorldOnA().y(), cp.getPositionWorldOnA().z()));
+            collisionEvent(COLLIDING, pair, Vector3(cp.getPositionWorldOnA().x(), cp.getPositionWorldOnA().y(), cp.getPositionWorldOnA().z()),
+                Vector3(cp.getPositionWorldOnB().x(), cp.getPositionWorldOnB().y(), cp.getPositionWorldOnB().z()));
     }
     else
     {
-        collisionEvent(pair, Vector3(cp.getPositionWorldOnA().x(), cp.getPositionWorldOnA().y(), cp.getPositionWorldOnA().z()));
+        collisionEvent(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

+ 37 - 6
gameplay/src/PhysicsRigidBody.h

@@ -18,6 +18,7 @@ class PhysicsConstraint;
 class PhysicsRigidBody : public Transform::Listener
 {
     friend class Node;
+    friend class PhysicsCharacter;
     friend class PhysicsConstraint;
     friend class PhysicsController;
     friend class PhysicsFixedConstraint;
@@ -75,21 +76,37 @@ public:
         friend class PhysicsController;
 
     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.
          */
         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 contactPoint The point (in world space) where the collision occurred.
+         * @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).
          */
-        virtual void collisionEvent(const CollisionPair& collisionPair, const Vector3& contactPoint) = 0;
-        
-    protected:
-        
+        virtual void collisionEvent(EventType type, const CollisionPair& collisionPair, const Vector3& contactPointA = Vector3(), const Vector3& contactPointB = Vector3()) = 0;
+
         /**
          * Internal function used for Bullet integration (do not use or override).
          */
@@ -235,6 +252,20 @@ public:
      */
     inline bool isKinematic() const;
 
+    /**
+     * Gets whether the rigid body is a static rigid body or not.
+     *
+     * @return Whether the rigid body is static.
+     */
+    inline bool isStatic() const;
+
+    /**
+     * Gets whether the rigid body is a dynamic rigid body or not.
+     *
+     * @return Whether the rigid body is dynamic.
+     */
+    inline bool isDynamic() const;
+
     /**
      * Sets the rigid body's angular velocity.
      * 

+ 11 - 1
gameplay/src/PhysicsRigidBody.inl

@@ -70,7 +70,17 @@ inline float PhysicsRigidBody::getRestitution() const
 
 inline bool PhysicsRigidBody::isKinematic() const
 {
-    return (_body->getCollisionFlags() & btCollisionObject::CF_KINEMATIC_OBJECT) != 0;
+    return _body->isKinematicObject();
+}
+
+inline bool PhysicsRigidBody::isStatic() const
+{
+    return _body->isStaticObject();
+}
+
+inline bool PhysicsRigidBody::isDynamic() const
+{
+    return !_body->isStaticOrKinematicObject();
 }
 
 inline void PhysicsRigidBody::setAngularVelocity(const Vector3& velocity)

+ 1 - 1
gameplay/src/PhysicsSocketConstraint.cpp

@@ -1,5 +1,5 @@
+#include "Base.h"
 #include "PhysicsSocketConstraint.h"
-
 #include "Node.h"
 
 namespace gameplay

+ 1 - 1
gameplay/src/PhysicsSpringConstraint.cpp

@@ -1,5 +1,5 @@
+#include "Base.h"
 #include "PhysicsSpringConstraint.h"
-
 #include "Node.h"
 #include "PhysicsRigidBody.h"
 

+ 14 - 0
gameplay/src/Platform.h

@@ -36,6 +36,20 @@ public:
      * @return The platform message pump return code.
      */
     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.

+ 11 - 1
gameplay/src/PlatformAndroid.cpp

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

+ 91 - 10
gameplay/src/PlatformMacOS.mm

@@ -13,6 +13,10 @@
 using namespace std;
 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_Y_FACTOR = 90.0f / WINDOW_HEIGHT;
 
@@ -26,6 +30,7 @@ static int __ly;
 static bool __hasMouse = false;
 static bool __leftMouseDown = false;
 static bool __rightMouseDown = false;
+static bool __otherMouseDown = false;
 static bool __shiftDown = false;
 
 long getMachTimeInMilliseconds()
@@ -102,9 +107,7 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
 
 - (id) initWithFrame: (NSRect) frame
 {    
-    lock = [[NSRecursiveLock alloc] init];
-    _game = Game::getInstance();
-    __timeStart = getMachTimeInMilliseconds();
+
     NSOpenGLPixelFormatAttribute attrs[] = 
     {
         NSOpenGLPFAAccelerated,
@@ -120,7 +123,12 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     if (!pf)
         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;
 }
@@ -173,18 +181,47 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     [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
 {
     NSPoint point = [event locationInWindow];
     __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
 {
     NSPoint point = [event locationInWindow];
     __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
@@ -192,7 +229,7 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     NSPoint point = [event locationInWindow];
     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;
      NSPoint point = [event locationInWindow];
     __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
 {
    __rightMouseDown = false;
+    NSPoint point = [event locationInWindow];
+    _game->mouseEvent(Mouse::MOUSE_RELEASE_RIGHT_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
 }
 
 - (void) rightMouseDragged: (NSEvent*) event
@@ -226,6 +266,30 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
         __lx = point.x;
         __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
@@ -233,10 +297,17 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     __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
 {
     __leftMouseDown = false;
     __rightMouseDown = false;
+    __otherMouseDown = false;
     __hasMouse = false;
 }
 
@@ -503,7 +574,6 @@ extern void printError(const char* format, ...)
     va_end(argptr);
 }
     
-    
 Platform::Platform(Game* game)
 : _game(game)
 {
@@ -545,6 +615,7 @@ int Platform::enterMessagePump()
                         backing:NSBackingStoreBuffered
                         defer:NO];
     
+    [window setAcceptsMouseMovedEvents:YES];
     [window setContentView:__view];
     [window setDelegate:__view];
     [__view release];
@@ -554,7 +625,17 @@ int Platform::enterMessagePump()
     [pool release];
     return EXIT_SUCCESS;
 }
-    
+
+unsigned int Platform::getDisplayWidth()
+{
+    return WINDOW_WIDTH;
+}
+
+unsigned int Platform::getDisplayHeight()
+{
+    return WINDOW_HEIGHT;
+}
+
 long Platform::getAbsoluteTime()
 {
     __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)
 {
-    if (!Game::getInstance()->mouseEvent(mouseEvent, x, y))
+    if (!Game::getInstance()->mouseEvent(mouseEvent, x, y, 0))
     {
         Game::getInstance()->touchEvent(touchEvent, x, y, 0);
     }
@@ -827,14 +827,14 @@ int Platform::enterMessagePump()
                             {
                                 move = false;
                                 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)
                         {
                             move = false;
                             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
@@ -844,14 +844,14 @@ int Platform::enterMessagePump()
                             {
                                 move = false;
                                 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)
                         {
                             move = false;
                             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
@@ -861,14 +861,14 @@ int Platform::enterMessagePump()
                             {
                                 move = false;
                                 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)
                         {
                             move = false;
                             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.
@@ -878,13 +878,13 @@ int Platform::enterMessagePump()
                         }
                         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
                         if (wheel)
                         {
-                            Game::getInstance()->mouseWheelEvent(position[0], position[1], -wheel);
+                            Game::getInstance()->mouseEvent(Mouse::MOUSE_WHEEL, position[0], position[1], -wheel);
                         }
                         break;
                     }
@@ -962,6 +962,16 @@ int Platform::enterMessagePump()
 
     return 0;
 }
+    
+unsigned int Platform::getDisplayWidth()
+{
+    return __screenWindowSize[0];
+}
+
+unsigned int Platform::getDisplayHeight()
+{
+    return __screenWindowSize[1];
+}
 
 long Platform::getAbsoluteTime()
 {

+ 27 - 8
gameplay/src/PlatformWin32.cpp

@@ -6,6 +6,10 @@
 #include "Game.h"
 #include <GL/wglew.h>
 
+// Default to 720p
+#define WINDOW_WIDTH    1280
+#define WINDOW_HEIGHT   720
+
 static long __timeTicksPerMillis;
 static long __timeStart;
 static long __timeAbsolute;
@@ -264,7 +268,7 @@ LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
         return 0;
 
     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);
         }
@@ -273,30 +277,30 @@ LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 
     case WM_LBUTTONUP:
         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);
         }
         return 0;
 
     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;
         lx = LOWORD(lParam);
         ly = HIWORD(lParam);
         break;
 
     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;
         break;
 
     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;
 
     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;
 
     case WM_MOUSEMOVE:
@@ -313,7 +317,7 @@ LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
             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)
         {
             // 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;
 
     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;
 
     case WM_KEYDOWN:
@@ -471,6 +475,11 @@ Platform* Platform::create(Game* game)
     // Get the drawing context.
     __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.
     PIXELFORMATDESCRIPTOR pfd;
     memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
@@ -570,6 +579,16 @@ int Platform::enterMessagePump()
     return msg.wParam;
 }
 
+unsigned int Platform::getDisplayWidth()
+{
+    return WINDOW_WIDTH;
+}
+
+unsigned int Platform::getDisplayHeight()
+{
+    return WINDOW_HEIGHT;
+}
+    
 long Platform::getAbsoluteTime()
 {
        LARGE_INTEGER queryTime;

+ 141 - 99
gameplay/src/PlatformiOS.mm

@@ -18,6 +18,11 @@
 using namespace std;
 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_Y_FACTOR = 90.0f / WINDOW_HEIGHT;
 
@@ -34,7 +39,8 @@ static float __pitch;
 static float __roll;
 
 
-long getMachTimeInMilliseconds(); 
+long getMachTimeInMilliseconds();
+
 int getKey(unichar keyCode);
 
 @interface View : UIView <UIKeyInput>
@@ -59,7 +65,7 @@ int getKey(unichar keyCode);
 - (void)update:(id)sender;
 - (void)setSwapInterval:(NSInteger)interval;
 - (int)swapInterval;
-
+- (void)swapBuffers;
 - (BOOL)showKeyboard;
 - (BOOL)dismissKeyboard;
 @end
@@ -113,6 +119,12 @@ int getKey(unichar keyCode);
 			[self release];
 			return nil;
 		}
+
+            if (!defaultFramebuffer)
+                [self createFramebuffer];
+            
+        glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);
+        glViewport(0, 0, framebufferWidth, framebufferHeight);
         
         // Initialize Internal Defaults
         displayLink = nil;
@@ -132,10 +144,11 @@ int getKey(unichar keyCode);
         
         _game = Game::getInstance();
         __timeStart = getMachTimeInMilliseconds();
-        _game->run(WINDOW_WIDTH, WINDOW_HEIGHT);    // TODO: Handle based on current orientation            
+        _game->run(WINDOW_WIDTH, WINDOW_HEIGHT);          
     }
     return self;
 }
+
 - (void) dealloc
 {
     _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
     assert(defaultFramebuffer == 0);
-    //NSLog(@"EAGLView: creating Framebuffer");
     
     // Create the default frame buffer, and render buffer
     glGenFramebuffers(1, &defaultFramebuffer);
@@ -229,6 +241,15 @@ int getKey(unichar keyCode);
     return swapInterval;
 }
 
+- (void)swapBuffers
+{
+    if (context != nil)
+    {
+        glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
+        [context presentRenderbuffer:GL_RENDERBUFFER];
+    }
+}
+
 - (void)startUpdating
 {
 	if (!updating)
@@ -271,17 +292,20 @@ int getKey(unichar keyCode);
     }
 }
 
-- (BOOL)showKeyboard {
+- (BOOL)showKeyboard 
+{
     return [self becomeFirstResponder];
 }
-- (BOOL)dismissKeyboard {
+
+- (BOOL)dismissKeyboard 
+{
     return [self resignFirstResponder];
 }
 
 /*
  * Virtual Keyboard Support
  */
-- (void)insertText:(NSString *)text 
+- (void)insertText:(NSString*)text 
 {
     if([text length] == 0) return;
     assert([text length] == 1);
@@ -290,11 +314,13 @@ int getKey(unichar keyCode);
     Game::getInstance()->keyEvent(Keyboard::KEY_PRESS, gpk);    
     Game::getInstance()->keyEvent(Keyboard::KEY_RELEASE, gpk);    
 }
+
 - (void)deleteBackward 
 {
     Game::getInstance()->keyEvent(Keyboard::KEY_PRESS, Keyboard::KEY_BACKSPACE);    
     Game::getInstance()->keyEvent(Keyboard::KEY_RELEASE, Keyboard::KEY_BACKSPACE);    
 }
+
 - (BOOL)hasText 
 {
     return YES;
@@ -311,7 +337,7 @@ int getKey(unichar keyCode);
         CGPoint touchLoc = [t locationInView:self];
         if(self.multipleTouchEnabled == YES) 
             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];
         if(self.multipleTouchEnabled == YES) 
             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;     
     }
     
-    if(pitch != NULL) *pitch = p;
-    if(roll != NULL) *roll = r;
+    if(pitch != NULL) 
+        *pitch = p;
+    if(roll != NULL) 
+        *roll = r;
 }
 
 - (void)applicationWillResignActive:(UIApplication*)application
@@ -505,7 +533,8 @@ long getMachTimeInMilliseconds()
 
 int getKey(unichar keyCode) 
 {
-    switch(keyCode) {
+    switch(keyCode) 
+    {
         case 0x30:
             return Keyboard::KEY_ZERO;
         case 0x31:
@@ -720,97 +749,110 @@ int getKey(unichar keyCode)
 
 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];
     }
+}
     
 }
 

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

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

+ 2 - 1
gameplay/src/gameplay.h

@@ -66,4 +66,5 @@
 #include "PhysicsHingeConstraint.h"
 #include "PhysicsSocketConstraint.h"
 #include "PhysicsSpringConstraint.h"
-#include "PhysicsRigidBody.h"
+#include "PhysicsRigidBody.h"
+#include "PhysicsCharacter.h"