Browse Source

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

Kieran Cunney 13 years ago
parent
commit
d4c7dc1628
70 changed files with 3522 additions and 1694 deletions
  1. 3 2
      gameplay-encoder/gameplay-encoder.vcxproj
  2. 9 6
      gameplay-encoder/gameplay-encoder.vcxproj.filters
  3. 2 4
      gameplay-encoder/gameplay-encoder.xcodeproj/project.pbxproj
  4. 1 0
      gameplay-encoder/src/Camera.h
  5. 1346 0
      gameplay-encoder/src/Curve.cpp
  6. 484 0
      gameplay-encoder/src/Curve.h
  7. 36 0
      gameplay-encoder/src/Curve.inl
  8. 1 0
      gameplay-encoder/src/DAEChannelTarget.h
  9. 1 0
      gameplay-encoder/src/DAESceneEncoder.h
  10. 1 0
      gameplay-encoder/src/Effect.h
  11. 3 0
      gameplay-encoder/src/FileIO.h
  12. 15 13
      gameplay-encoder/src/MeshSkin.cpp
  13. 2 2
      gameplay-encoder/src/Reference.h
  14. 1 1
      gameplay/android/jni/Android.mk
  15. 1 2
      gameplay/gameplay.vcxproj
  16. 3 6
      gameplay/gameplay.vcxproj.filters
  17. 12 12
      gameplay/gameplay.xcodeproj/project.pbxproj
  18. 9 29
      gameplay/src/Animation.cpp
  19. 1 21
      gameplay/src/Animation.h
  20. 3 3
      gameplay/src/AudioController.cpp
  21. 2 2
      gameplay/src/AudioSource.cpp
  22. 3 3
      gameplay/src/BoundingBox.cpp
  23. 1 1
      gameplay/src/BoundingBox.h
  24. 11 33
      gameplay/src/Camera.cpp
  25. 7 7
      gameplay/src/Camera.h
  26. 0 2
      gameplay/src/Control.cpp
  27. 5 0
      gameplay/src/Curve.cpp
  28. 25 11
      gameplay/src/Curve.h
  29. 19 19
      gameplay/src/FileSystem.cpp
  30. 7 4
      gameplay/src/Font.h
  31. 13 13
      gameplay/src/Form.cpp
  32. 5 2
      gameplay/src/Form.h
  33. 8 0
      gameplay/src/Game.cpp
  34. 19 44
      gameplay/src/Game.h
  35. 5 14
      gameplay/src/Game.inl
  36. 93 24
      gameplay/src/Node.cpp
  37. 122 49
      gameplay/src/Node.h
  38. 1 1
      gameplay/src/ParticleEmitter.cpp
  39. 184 193
      gameplay/src/PhysicsCharacter.cpp
  40. 6 4
      gameplay/src/PhysicsCharacter.h
  41. 15 15
      gameplay/src/PhysicsCollisionObject.cpp
  42. 31 31
      gameplay/src/PhysicsCollisionObject.h
  43. 64 23
      gameplay/src/PhysicsCollisionShape.cpp
  44. 35 33
      gameplay/src/PhysicsCollisionShape.h
  45. 1 1
      gameplay/src/PhysicsConstraint.cpp
  46. 241 239
      gameplay/src/PhysicsController.cpp
  47. 11 11
      gameplay/src/PhysicsController.h
  48. 1 1
      gameplay/src/PhysicsGhostObject.cpp
  49. 1 1
      gameplay/src/PhysicsMotionState.cpp
  50. 4 4
      gameplay/src/PhysicsMotionState.h
  51. 2 2
      gameplay/src/PhysicsRigidBody.cpp
  52. 83 83
      gameplay/src/PhysicsRigidBody.h
  53. 2 2
      gameplay/src/PhysicsRigidBody.inl
  54. 98 98
      gameplay/src/PlatformMacOS.mm
  55. 57 57
      gameplay/src/PlatformQNX.cpp
  56. 3 3
      gameplay/src/PlatformWin32.cpp
  57. 4 4
      gameplay/src/Rectangle.cpp
  58. 7 7
      gameplay/src/Rectangle.h
  59. 145 155
      gameplay/src/Scene.cpp
  60. 16 31
      gameplay/src/Scene.h
  61. 21 11
      gameplay/src/SceneLoader.cpp
  62. 4 3
      gameplay/src/SceneLoader.h
  63. 69 0
      gameplay/src/ScreenDisplayer.h
  64. 127 127
      gameplay/src/Texture.cpp
  65. 4 4
      gameplay/src/Texture.h
  66. 2 2
      gameplay/src/Theme.cpp
  67. 1 1
      gameplay/src/Theme.h
  68. 0 86
      gameplay/src/Viewport.cpp
  69. 0 132
      gameplay/src/Viewport.h
  70. 3 0
      gameplay/src/gameplay.h

+ 3 - 2
gameplay-encoder/gameplay-encoder.vcxproj

@@ -11,12 +11,12 @@
     </ProjectConfiguration>
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="..\gameplay\src\Curve.cpp" />
     <ClCompile Include="src\Animation.cpp" />
     <ClCompile Include="src\AnimationChannel.cpp" />
     <ClCompile Include="src\Base.cpp" />
     <ClCompile Include="src\BoundingVolume.cpp" />
     <ClCompile Include="src\Camera.cpp" />
+    <ClCompile Include="src\Curve.cpp" />
     <ClCompile Include="src\EncoderArguments.cpp" />
     <ClCompile Include="src\DAEChannelTarget.cpp" />
     <ClCompile Include="src\DAEOptimizer.cpp" />
@@ -55,12 +55,12 @@
     <ClCompile Include="src\VertexElement.cpp" />
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="..\gameplay\src\Curve.h" />
     <ClInclude Include="src\Animation.h" />
     <ClInclude Include="src\AnimationChannel.h" />
     <ClInclude Include="src\Base.h" />
     <ClInclude Include="src\BoundingVolume.h" />
     <ClInclude Include="src\Camera.h" />
+    <ClInclude Include="src\Curve.h" />
     <ClInclude Include="src\EncoderArguments.h" />
     <ClInclude Include="src\DAEChannelTarget.h" />
     <ClInclude Include="src\DAEOptimizer.h" />
@@ -98,6 +98,7 @@
     <ClInclude Include="src\VertexElement.h" />
   </ItemGroup>
   <ItemGroup>
+    <None Include="src\Curve.inl" />
     <None Include="src\Quaternion.inl" />
     <None Include="src\Vector2.inl" />
     <None Include="src\Vector3.inl" />

+ 9 - 6
gameplay-encoder/gameplay-encoder.vcxproj.filters

@@ -19,9 +19,6 @@
     <ClCompile Include="src\Camera.cpp">
       <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="..\gameplay\src\Curve.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
     <ClCompile Include="src\DAEChannelTarget.cpp">
       <Filter>src</Filter>
     </ClCompile>
@@ -127,6 +124,9 @@
     <ClCompile Include="src\VertexElement.cpp">
       <Filter>src</Filter>
     </ClCompile>
+    <ClCompile Include="src\Curve.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\VertexElement.h">
@@ -150,9 +150,6 @@
     <ClInclude Include="src\Camera.h">
       <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="..\gameplay\src\Curve.h">
-      <Filter>src</Filter>
-    </ClInclude>
     <ClInclude Include="src\DAEChannelTarget.h">
       <Filter>src</Filter>
     </ClInclude>
@@ -252,6 +249,9 @@
     <ClInclude Include="src\Vertex.h">
       <Filter>src</Filter>
     </ClInclude>
+    <ClInclude Include="src\Curve.h">
+      <Filter>src</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="src\Vector2.inl">
@@ -266,6 +266,9 @@
     <None Include="src\Quaternion.inl">
       <Filter>src</Filter>
     </None>
+    <None Include="src\Curve.inl">
+      <Filter>src</Filter>
+    </None>
   </ItemGroup>
   <ItemGroup>
     <Filter Include="src">

+ 2 - 4
gameplay-encoder/gameplay-encoder.xcodeproj/project.pbxproj

@@ -503,7 +503,7 @@
 		42475CF1147208A100610A6A /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+				ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
 				CLANG_CXX_LANGUAGE_STANDARD = "compiler-default";
 				CLANG_CXX_LIBRARY = "compiler-default";
 				GCC_C_LANGUAGE_STANDARD = "compiler-default";
@@ -524,7 +524,6 @@
 					"\"$(SRCROOT)/../external-deps/collada-dom/lib/macos\"",
 					"\"$(SRCROOT)/../external-deps/pcre/lib/macos\"",
 					"\"$(SRCROOT)/../../../Library/Developer/Xcode/DerivedData/gameplay-exiunaubxxjndaapmcqkaoeboiob/Build/Products/Debug\"",
-					"\"$(SYSTEM_APPS_DIR)/Autodesk/FBXSDK20122/lib/gcc4/ub\"",
 					"\"$(SRCROOT)/../external-deps/libpng/lib/macos\"",
 				);
 				MACH_O_TYPE = mh_execute;
@@ -536,7 +535,7 @@
 		42475CF2147208A100610A6A /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+				ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
 				CLANG_CXX_LANGUAGE_STANDARD = "compiler-default";
 				CLANG_CXX_LIBRARY = "compiler-default";
 				GCC_C_LANGUAGE_STANDARD = "compiler-default";
@@ -557,7 +556,6 @@
 					"\"$(SRCROOT)/../external-deps/collada-dom/lib/macos\"",
 					"\"$(SRCROOT)/../external-deps/pcre/lib/macos\"",
 					"\"$(SRCROOT)/../../../Library/Developer/Xcode/DerivedData/gameplay-exiunaubxxjndaapmcqkaoeboiob/Build/Products/Debug\"",
-					"\"$(SYSTEM_APPS_DIR)/Autodesk/FBXSDK20122/lib/gcc4/ub\"",
 					"\"$(SRCROOT)/../external-deps/libpng/lib/macos\"",
 				);
 				MACH_O_TYPE = mh_execute;

+ 1 - 0
gameplay-encoder/src/Camera.h

@@ -44,6 +44,7 @@ public:
     };
 
 private:
+    
     unsigned char _cameraType;
     float _fieldOfView;
     float _aspectRatio;

+ 1346 - 0
gameplay-encoder/src/Curve.cpp

@@ -0,0 +1,1346 @@
+// Purposely not including Base.h here, or any other gameplay dependencies
+// so this class can be reused between gameplay and gameplay-encoder.
+#include "Curve.h"
+#include "Quaternion.h"
+#include <cassert>
+#include <cmath>
+#include <memory>
+
+using std::memcpy;
+using std::fabs;
+using std::sqrt;
+using std::cos;
+using std::sin;
+using std::exp;
+using std::strcmp;
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef MATH_PI
+#define MATH_PI 3.14159265358979323846f
+#endif
+
+#ifndef MATH_PIOVER2 
+#define MATH_PIOVER2 1.57079632679489661923f
+#endif
+
+#ifndef MATH_PIX2
+#define MATH_PIX2 6.28318530717958647693f
+#endif
+
+// Object deletion macro
+#ifndef SAFE_DELETE
+#define SAFE_DELETE(x) \
+    if (x) \
+    { \
+        delete x; \
+        x = NULL; \
+    }
+#endif
+
+// Array deletion macro
+#ifndef SAFE_DELETE_ARRAY
+#define SAFE_DELETE_ARRAY(x) \
+    if (x) \
+    { \
+        delete[] x; \
+        x = NULL; \
+    }
+#endif
+
+
+namespace gameplay
+{
+
+Curve::Curve(unsigned int pointCount, unsigned int componentCount)
+    : _pointCount(pointCount), _componentCount(componentCount), _componentSize(sizeof(float)*componentCount), _quaternionOffset(NULL), _points(NULL)
+{
+    _points = new Point[_pointCount];
+    for (unsigned int i = 0; i < _pointCount; i++)
+    {
+        _points[i].time = 0.0f;
+        _points[i].value = new float[_componentCount];
+        _points[i].inValue = new float[_componentCount];
+        _points[i].outValue = new float[_componentCount];
+        _points[i].type = LINEAR;
+    }
+    _points[_pointCount - 1].time = 1.0f;
+}
+
+Curve::~Curve()
+{
+    SAFE_DELETE_ARRAY(_points);
+    SAFE_DELETE_ARRAY(_quaternionOffset);
+}
+
+Curve::Point::Point()
+    : time(0.0f), value(NULL), inValue(NULL), outValue(NULL)
+{
+}
+
+Curve::Point::~Point()
+{
+    SAFE_DELETE_ARRAY(value);
+    SAFE_DELETE_ARRAY(inValue);
+    SAFE_DELETE_ARRAY(outValue);
+}
+
+unsigned int Curve::getPointCount() const
+{
+    return _pointCount;
+}
+
+unsigned int Curve::getComponentCount() const
+{
+    return _componentCount;
+}
+
+float Curve::getStartTime() const
+{
+    return _points[0].time;
+}
+
+float Curve::getEndTime() const
+{
+    return _points[_pointCount-1].time;
+}
+
+void Curve::setPoint(unsigned int index, float time, float* value, InterpolationType type)
+{
+    setPoint(index, time, value, type, NULL, NULL);
+}
+
+void Curve::setPoint(unsigned int index, float time, float* value, InterpolationType type, float* inValue, float* outValue)
+{
+    assert(index < _pointCount && time >= 0.0f && time <= 1.0f && !(index == 0 && time != 0.0f) && !(index == _pointCount - 1 && time != 1.0f));
+
+    _points[index].time = time;
+    _points[index].type = type;
+
+    if (value)
+        memcpy(_points[index].value, value, _componentSize);
+
+    if (inValue)
+        memcpy(_points[index].inValue, inValue, _componentSize);
+
+    if (outValue)
+        memcpy(_points[index].outValue, outValue, _componentSize);
+}
+
+void Curve::setTangent(unsigned int index, InterpolationType type, float* inValue, float* outValue)
+{
+    assert(index < _pointCount);
+
+    _points[index].type = type;
+
+    if (inValue)
+        memcpy(_points[index].inValue, inValue, _componentSize);
+
+    if (outValue)
+        memcpy(_points[index].outValue, outValue, _componentSize);
+}
+
+void Curve::evaluate(float time, float* dst) const
+{
+    assert(dst && time >= 0 && time <= 1.0f);
+
+    // Check if we are at or beyond the bounds of the curve.
+    if (time <= _points[0].time)
+    {
+        memcpy(dst, _points[0].value, _componentSize);
+        return;
+    }
+    else if (time >= _points[_pointCount - 1].time)
+    {
+        memcpy(dst, _points[_pointCount - 1].value, _componentSize);
+        return;
+    }
+
+    // Locate the points we are interpolating between using a binary search.
+    unsigned int index = determineIndex(time);
+    
+    Point* from = _points + index;
+    Point* to = _points + (index + 1);
+
+    // Calculate the fractional time between the two points.
+    float scale = (to->time - from->time);
+    float t = (time - from->time) / scale;
+
+    // Calculate the value of the curve discretely if appropriate.
+    switch (from->type)
+    {
+        case BEZIER:
+        {
+            interpolateBezier(t, from, to, dst);
+            return;
+        }
+        case BSPLINE:
+        {
+            Point* c0;
+            Point* c1;
+            if (index == 0)
+            {
+                c0 = from;
+            }
+            else
+            {
+                c0 = (_points + index - 1);
+            }
+            
+            if (index == _pointCount - 2)
+            {
+                c1 = to;
+            }
+            else
+            {
+                c1 = (_points + index + 2);
+            }
+            interpolateBSpline(t, c0, from, to, c1, dst);
+            return;
+        }
+        case FLAT:
+        {
+            interpolateHermiteFlat(t, from, to, dst);
+            return;
+        }
+        case HERMITE:
+        {
+            interpolateHermite(t, from, to, dst);
+            return;
+        }
+        case LINEAR:
+        {
+            // Can just break here because linear formula follows switch
+            break;
+        }
+        case SMOOTH:
+        {
+            interpolateHermiteSmooth(t, index, from, to, dst);
+            return;
+        }
+        case STEP:
+        {
+            memcpy(dst, from->value, _componentSize);
+            return;
+        }
+        case QUADRATIC_IN:
+        {
+            t *= t;
+            break;
+        }
+        case QUADRATIC_OUT:
+        {
+            t *= -(t - 2.0f);
+            break;
+        }
+        case QUADRATIC_IN_OUT:
+        {
+            float tx2 = t * 2.0f;
+
+            if (tx2 < 1.0f)
+                t = 0.5f * (tx2 * tx2);
+            else
+            {
+                float temp = tx2 - 1.0f;
+                t = 0.5f * (-( temp * (temp - 2.0f)) + 1.0f);
+            }
+            break;
+        }
+        case QUADRATIC_OUT_IN:
+        {
+            if (t < 0.5f)
+            {
+                t = 2.0f * t * (1.0f - t);
+            }
+            else
+            {
+                t = 1.0f + 2.0f * t * (t - 1.0f);
+            }
+            break;
+        }
+        case CUBIC_IN:
+        {
+            t *= t * t;
+            break;
+        }
+        case CUBIC_OUT:
+        {
+            t--;
+            t = t * t * t + 1;
+            break;
+        }
+        case CUBIC_IN_OUT:
+        {
+            if ((t *= 2.0f) < 1.0f)
+            {
+                t = t * t * t * 0.5f;
+            }
+            else
+            {
+                t -= 2.0f;
+                t = (t * t * t + 2.0f) * 0.5f;
+            }
+            break;
+        }
+        case CUBIC_OUT_IN:
+        {
+            t = (2.0f * t - 1.0f);
+            t = (t * t * t + 1) * 0.5f;
+            break;
+        }
+        case QUARTIC_IN:
+        {
+            t *= t * t * t;
+            break;
+        }
+        case QUARTIC_OUT:
+        {
+            t--;
+            t = -(t * t * t * t) + 1.0f;
+            break;
+        }
+        case QUARTIC_IN_OUT:
+        {
+            t *= 2.0f;
+            if (t < 1.0f)
+            {
+                t = 0.5f * t * t * t * t;
+            }
+            else
+            {
+                t -= 2.0f;
+                t = -0.5f * (t * t * t * t - 2.0f);
+            }
+            break;
+        }
+        case QUARTIC_OUT_IN:
+        {
+            t = 2.0f * t - 1.0f;
+            if (t < 0.0f)
+            {
+                t = 0.5f * (-(t * t) * t * t + 1.0f);
+            }
+            else
+            {
+                t = 0.5f * (t * t * t * t + 1.0f);
+            }
+            break;
+        }
+        case QUINTIC_IN:
+        {
+            t *= t * t * t * t;
+            break;
+        }
+        case QUINTIC_OUT:
+        {
+            t--;
+            t = t * t * t * t * t + 1.0f;
+            break;
+        }
+        case QUINTIC_IN_OUT:
+        {
+            t *= 2.0f;
+            if (t < 1.0f)
+            {
+                t = 0.5f * t * t * t * t * t;
+            }
+            else
+            {
+                t -= 2.0f;
+                t = 0.5f * (t * t * t * t * t + 2.0f);
+            }
+            break;
+        }
+        case QUINTIC_OUT_IN:
+        {
+            t = 2.0f * t - 1.0f;
+            t = 0.5f * (t * t * t * t * t + 1.0f);
+            break;
+        }
+        case SINE_IN:
+        {
+            t = -(cos(t * MATH_PIOVER2) - 1.0f);
+            break;
+        }
+        case SINE_OUT:
+        {
+            t = sin(t * MATH_PIOVER2);
+            break;
+        }
+        case SINE_IN_OUT:
+        {
+            t = -0.5f * (cos(MATH_PI * t) - 1.0f);
+            break;
+        }
+        case SINE_OUT_IN:
+        {
+            if (t < 0.5f)
+            {
+                t = 0.5f * sin(MATH_PI * t);
+            }
+            else
+            {
+                t = -0.5f * cos(MATH_PIOVER2 * (2.0f * t - 1.0f)) + 1.0f;
+            }
+            break;
+        }
+        case EXPONENTIAL_IN:
+        {
+            if (t != 0.0f)
+            {
+                t = exp(10.0f * (t - 1.0f));
+            }
+            break;
+        }
+        case EXPONENTIAL_OUT:
+        {
+            if (t != 1.0f)
+            {
+                t = -exp(-10.0f * t) + 1.0f;
+            }
+            break;
+        }
+        case EXPONENTIAL_IN_OUT:
+        {
+            if (t != 0.0f && t != 1.0f)
+            {
+                if (t < 0.5f)
+                {
+                    t = 0.5f * exp(10.0f * (2.0f * t - 1.0f));
+                }
+                else
+                {
+                    t = -0.5f * exp(10.0f * (-2.0f * t + 1.0f)) + 1.0f;
+                }
+            }
+            break;
+        }
+        case EXPONENTIAL_OUT_IN:
+        {
+            if (t != 0.0f && t != 1.0f)
+            {
+                if (t < 0.5f)
+                {
+                    t = -0.5f * exp(-20.0f * t) + 0.5f;
+                }
+                else
+                {
+                    t = 0.5f * exp(20.0f * (t - 1.0f)) + 0.5f;
+                }
+            }
+            break;
+        }
+        case CIRCULAR_IN:
+        {
+            t = -(sqrt(1.0f - t * t) - 1.0f);
+            break;
+        }
+        case CIRCULAR_OUT:
+        {
+            t--;
+            t = sqrt(1.0f - t * t);
+            break;
+        }
+        case CIRCULAR_IN_OUT:
+        {
+            t *= 2.0f;
+            if (t < 1.0f)
+            {
+                t = 0.5f * (-sqrt((1.0f - t * t)) + 1.0f);
+            }
+            else
+            {
+                t -= 2.0f;
+                t = 0.5f * (sqrt((1.0f - t * t)) + 1.0f);
+            }
+            break;
+        }
+        case CIRCULAR_OUT_IN:
+        {
+            t = 2.0f * t - 1.0f;
+            if (t < 0.0f)
+            {
+                t = 0.5f * sqrt(1.0f - t * t);
+            }
+            else
+            {
+                t = 0.5f * (2.0f - sqrt(1.0f - t * t));
+            }
+            break;
+        }
+        case ELASTIC_IN:
+        {
+            if (t != 0.0f && t != 1.0f)
+            {
+                t = t - 1.0f;
+                t = -1.0f * ( exp(10.0f * t) * sin( (t - 0.075f) * MATH_PIX2 / 0.3f ) );
+            }
+            break;
+        }
+        case ELASTIC_OUT:
+        {
+            if (t != 0.0f && t != 1.0f)
+            {
+                t = exp(-10.0f * t) * sin((t - 0.075f) * MATH_PIX2 / 0.3f) + 1.0f;
+            }
+            break;
+        }
+        case ELASTIC_IN_OUT:
+        {
+            if (t != 0.0f && t != 1.0f)
+            {
+                t = 2.0f * t - 1.0f;
+                if (t < 0.0f)
+                {
+                    t = -0.5f * (exp((10 * t)) * sin(((t - 0.1125f) * MATH_PIX2 / 0.45f)));
+                }
+                else
+                {
+                    t = 0.5f * exp((-10 * t)) * sin(((t - 0.1125f) * MATH_PIX2 / 0.45f)) + 1.0f;
+                }
+            }
+            break;
+        }
+        case ELASTIC_OUT_IN:
+        {
+            if (t != 0.0f && t != 1.0f)
+            {
+                t *= 2.0f;
+                if (t < 1.0f)
+                {
+                    t = 0.5f * (exp((-10 * t)) * sin(((t - 0.1125f) * (MATH_PIX2) / 0.45f))) + 0.5f;
+                }
+                else
+                {
+                    t = 0.5f * (exp((10 *(t - 2))) * sin(((t - 0.1125f) * (MATH_PIX2) / 0.45f))) + 0.5f;
+                }
+            }
+            break;
+        }
+        case OVERSHOOT_IN:
+        {
+            t = t * t * (2.70158f * t - 1.70158f);
+            break;
+        }
+        case OVERSHOOT_OUT:
+        {
+            t--;
+            t = t * t * (2.70158f * t + 1.70158f) + 1;
+            break;
+        }
+        case OVERSHOOT_IN_OUT:
+        {
+            t *= 2.0f;
+            if (t < 1.0f)
+            {
+                t = 0.5f * t * t * (3.5949095f * t - 2.5949095f);
+            }
+            else
+            {
+                t -= 2.0f;
+                t = 0.5f * (t * t * (3.5949095f * t + 2.5949095f) + 2.0f);
+            }
+            break;
+        }
+        case OVERSHOOT_OUT_IN:
+        {
+            t = 2.0f * t - 1.0f;
+            if (t < 0.0f)
+            {
+                t = 0.5f * (t * t * (3.5949095f * t + 2.5949095f) + 1.0f);
+            }
+            else
+            {
+                t = 0.5f * (t * t * (3.5949095f * t - 2.5949095f) + 1.0f);
+            }
+            break;
+        }
+        case BOUNCE_IN:
+        {
+            t = 1.0f - t;
+
+            if (t < 0.36363636363636365f)
+            {
+                t = 7.5625f * t * t;
+            }
+            else if (t < 0.7272727272727273f)
+            {
+                t -= 0.5454545454545454f;
+                t = 7.5625f * t * t + 0.75f;
+            }
+            else if (t < 0.9090909090909091f)
+            {
+                t -= 0.8181818181818182f;
+                t = 7.5625f * t * t + 0.9375f;
+            }
+            else
+            {
+                t -= 0.9545454545454546f;
+                t = 7.5625f * t * t + 0.984375f;
+            }
+
+            t = 1.0f - t;
+            break;
+        }
+        case BOUNCE_OUT:
+        {
+            if (t < 0.36363636363636365f)
+            {
+                t = 7.5625f * t * t;
+            }
+            else if (t < 0.7272727272727273f)
+            {
+                t -= 0.5454545454545454f;
+                t = 7.5625f * t * t + 0.75f;
+            }
+            else if (t < 0.9090909090909091f)
+            {
+                t -= 0.8181818181818182f;
+                t = 7.5625f * t * t + 0.9375f;
+            }
+            else
+            {
+                t -= 0.9545454545454546f;
+                t = 7.5625f * t * t + 0.984375f;
+            }
+            break;
+        }
+        case BOUNCE_IN_OUT:
+        {
+            if (t < 0.5f)
+            {
+                t = 1.0f - t * 2.0f;
+
+                if (t < 0.36363636363636365f)
+                {
+                    t = 7.5625f * t * t;
+                }
+                else if (t < 0.7272727272727273f)
+                {
+                    t -= 0.5454545454545454f;
+                    t = 7.5625f * t * t + 0.75f;
+                }
+                else if (t < 0.9090909090909091f)
+                {
+                    t -= 0.8181818181818182f;
+                    t = 7.5625f * t * t + 0.9375f;
+                }
+                else
+                {
+                    t -= 0.9545454545454546f;
+                    t = 7.5625f * t * t + 0.984375f;
+                }
+
+                t = (1.0f - t) * 0.5f;
+            }
+            else
+            {
+                t = t * 2.0f - 1.0f;
+                if (t < 0.36363636363636365f)
+                {
+                    t = 7.5625f * t * t;
+                }
+                else if (t < 0.7272727272727273f)
+                {
+                    t -= 0.5454545454545454f;
+                    t = 7.5625f * t * t + 0.75f;
+                }
+                else if (t < 0.9090909090909091f)
+                {
+                    t -= 0.8181818181818182f;
+                    t = 7.5625f * t * t + 0.9375f;
+                }
+                else
+                {
+                    t -= 0.9545454545454546f;
+                    t = 7.5625f * t * t + 0.984375f;
+                }
+
+                t = 0.5f * t + 0.5f;
+            }
+            break;
+        }
+        case BOUNCE_OUT_IN:
+        {
+            if (t < 0.1818181818f)
+            {
+                t = 15.125f * t * t;
+            }
+            else if (t < 0.3636363636f)
+            {
+                t = 1.5f + (-8.250000001f + 15.125f * t) * t;
+            }
+            else if (t < 0.4545454546f)
+            {
+                t = 3.0f + (-12.375f + 15.125f * t) * t;
+            }
+            else if (t < 0.5f)
+            {
+                t = 3.9375f + (-14.4375f + 15.125f * t) * t;
+            }
+            else if (t <= 0.5454545455f)
+            {
+                t = -3.625000004f + (15.81250001f - 15.125f * t) * t;
+            }
+            else if (t <= 0.6363636365f)
+            {
+                t = -4.75f + (17.875f - 15.125f * t) * t;
+            }
+            else if (t <= 0.8181818180f)
+            {
+                t = -7.374999995f + (21.99999999f - 15.125f * t) * t;
+            }
+            else
+            {
+                t = -14.125f + (30.25f - 15.125f * t) * t;
+            }
+            break;
+        }
+    }
+
+    interpolateLinear(t, from, to, dst);
+}
+
+float Curve::lerp(float t, float from, float to)
+{
+    return lerpInl(t, from, to);
+}
+
+void Curve::setQuaternionOffset(unsigned int offset)
+{
+    assert(offset <= (_componentCount - 4));
+
+    if (!_quaternionOffset)
+        _quaternionOffset = new unsigned int[1];
+    
+    *_quaternionOffset = offset;
+}
+
+void Curve::interpolateBezier(float s, Point* from, Point* to, float* dst) const
+{
+    float s_2 = s * s;
+    float eq0 = 1 - s;
+    float eq0_2 = eq0 * eq0;
+    float eq1 = eq0_2 * eq0;
+    float eq2 = 3 * s * eq0_2;
+    float eq3 = 3 * s_2 * eq0;
+    float eq4 = s_2 * s;
+
+    float* fromValue = from->value;
+    float* toValue = to->value;
+    float* outValue = from->outValue;
+    float* inValue = to->inValue;
+
+
+    if (!_quaternionOffset)
+    {
+        for (unsigned int i = 0; i < _componentCount; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = bezier(eq1, eq2, eq3, eq4, fromValue[i], outValue[i], toValue[i], inValue[i]);
+        }
+    }
+    else
+    {
+        // Interpolate any values up to the quaternion offset as scalars.
+        unsigned int quaternionOffset = *_quaternionOffset;
+        unsigned int i = 0;
+        for (i = 0; i < quaternionOffset; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = bezier(eq1, eq2, eq3, eq4, fromValue[i], outValue[i], toValue[i], inValue[i]);
+        }
+
+        // Handle quaternion component.
+        float interpTime = bezier(eq1, eq2, eq3, eq4, from->time, outValue[i], to->time, inValue[i]);
+        interpolateQuaternion(interpTime, (fromValue + i), (toValue + i), (dst + i));
+        
+        // Handle remaining components (if any) as scalars
+        for (i += 4; i < _componentCount; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = bezier(eq1, eq2, eq3, eq4, fromValue[i], outValue[i], toValue[i], inValue[i]);
+        }
+    }
+}
+
+void Curve::interpolateBSpline(float s, Point* c0, Point* c1, Point* c2, Point* c3, float* dst) const
+{   
+    float s_2 = s * s;
+    float s_3 = s_2 * s;
+    float eq0 = (-s_3 + 3 * s_2 - 3 * s + 1) / 6.0f;
+    float eq1 = (3 * s_3 - 6 * s_2 + 4) / 6.0f;
+    float eq2 = (-3 * s_3 + 3 * s_2 + 3 * s + 1) / 6.0f;
+    float eq3 = s_3 / 6.0f;
+
+    float* c0Value = c0->value;
+    float* c1Value = c1->value;
+    float* c2Value = c2->value;
+    float* c3Value = c3->value;
+
+    if (!_quaternionOffset)
+    {
+        for (unsigned int i = 0; i < _componentCount; i++)
+        {
+            if (c1Value[i] == c2Value[i])
+                dst[i] = c1Value[i];
+            else
+                dst[i] = bspline(eq0, eq1, eq2, eq3, c0Value[i], c1Value[i], c2Value[i], c3Value[i]);
+        }
+    }
+    else
+    {
+        // Interpolate any values up to the quaternion offset as scalars.
+        unsigned int quaternionOffset = *_quaternionOffset;
+        unsigned int i = 0;
+        for (i = 0; i < quaternionOffset; i++)
+        {
+            if (c1Value[i] == c2Value[i])
+                dst[i] = c1Value[i];
+            else
+                dst[i] = bspline(eq0, eq1, eq2, eq3, c0Value[i], c1Value[i], c2Value[i], c3Value[i]);
+        }
+
+        // Handle quaternion component.
+        float interpTime;
+        if (c0->time == c1->time)
+            interpTime = bspline(eq0, eq1, eq2, eq3, -c0->time, c1->time, c2->time, c3->time);
+        else if (c2->time == c3->time)
+            interpTime = bspline(eq0, eq1, eq2, eq3, c0->time, c1->time, c2->time, -c3->time); 
+        else
+            interpTime = bspline(eq0, eq1, eq2, eq3, c0->time, c1->time, c2->time, c3->time);
+        interpolateQuaternion(s, (c1Value + i) , (c2Value + i), (dst + i));
+            
+        // Handle remaining components (if any) as scalars
+        for (i += 4; i < _componentCount; i++)
+        {
+            if (c1Value[i] == c2Value[i])
+                dst[i] = c1Value[i];
+            else
+                dst[i] = bspline(eq0, eq1, eq2, eq3, c0Value[i], c1Value[i], c2Value[i], c3Value[i]);
+        }
+    }
+}
+
+void Curve::interpolateHermite(float s, Point* from, Point* to, float* dst) const
+{
+    // Calculate the hermite basis functions.
+    float s_2 = s * s;                   // t^2
+    float s_3 = s_2 * s;                 // t^3
+    float h00 = 2 * s_3 - 3 * s_2 + 1;   // basis function 0
+    float h01 = -2 * s_3 + 3 * s_2;      // basis function 1
+    float h10 = s_3 - 2 * s_2 + s;       // basis function 2
+    float h11 = s_3 - s_2;               // basis function 3
+
+    float* fromValue = from->value;
+    float* toValue = to->value;
+    float* outValue = from->outValue;
+    float* inValue = to->inValue;
+
+    if (!_quaternionOffset)
+    {
+        for (unsigned int i = 0; i < _componentCount; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = hermite(h00, h01, h10, h11, fromValue[i], outValue[i], toValue[i], inValue[i]);
+        }
+    }
+    else
+    {
+        // Interpolate any values up to the quaternion offset as scalars.
+        unsigned int quaternionOffset = *_quaternionOffset;
+        unsigned int i = 0;
+        for (i = 0; i < quaternionOffset; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = hermite(h00, h01, h10, h11, fromValue[i], outValue[i], toValue[i], inValue[i]);
+        }
+
+        // Handle quaternion component.
+        float interpTime = hermite(h00, h01, h10, h11, from->time, outValue[i], to->time, inValue[i]);
+        interpolateQuaternion(interpTime, (fromValue + i), (toValue + i), (dst + i));
+        
+        // Handle remaining components (if any) as scalars
+        for (i += 4; i < _componentCount; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = hermite(h00, h01, h10, h11, fromValue[i], outValue[i], toValue[i], inValue[i]);
+        }
+    }
+}
+
+void Curve::interpolateHermiteFlat(float s, Point* from, Point* to, float* dst) const
+{
+    // Calculate the hermite basis functions.
+    float s_2 = s * s;                   // t^2
+    float s_3 = s_2 * s;                 // t^3
+    float h00 = 2 * s_3 - 3 * s_2 + 1;   // basis function 0
+    float h01 = -2 * s_3 + 3 * s_2;      // basis function 1
+
+    float* fromValue = from->value;
+    float* toValue = to->value;
+
+    if (!_quaternionOffset)
+    {
+        for (unsigned int i = 0; i < _componentCount; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = hermiteFlat(h00, h01, fromValue[i], toValue[i]);
+        }
+    }
+    else
+    {
+        // Interpolate any values up to the quaternion offset as scalars.
+        unsigned int quaternionOffset = *_quaternionOffset;
+        unsigned int i = 0;
+        for (i = 0; i < quaternionOffset; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = hermiteFlat(h00, h01, fromValue[i], toValue[i]);
+        }
+
+        // Handle quaternion component.
+        float interpTime = hermiteFlat(h00, h01, from->time, to->time);
+        interpolateQuaternion(interpTime, (fromValue + i), (toValue + i), (dst + i));
+        
+        // Handle remaining components (if any) as scalars
+        for (i += 4; i < _componentCount; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = hermiteFlat(h00, h01, fromValue[i], toValue[i]);
+        }
+    }
+}
+
+void Curve::interpolateHermiteSmooth(float s, unsigned int index, Point* from, Point* to, float* dst) const
+{
+    // Calculate the hermite basis functions.
+    float s_2 = s * s;                   // t^2
+    float s_3 = s_2 * s;                 // t^3
+    float h00 = 2 * s_3 - 3 * s_2 + 1;   // basis function 0
+    float h01 = -2 * s_3 + 3 * s_2;      // basis function 1
+    float h10 = s_3 - 2 * s_2 + s;       // basis function 2
+    float h11 = s_3 - s_2;               // basis function 3
+
+    float inValue;
+    float outValue;
+
+    float* fromValue = from->value;
+    float* toValue = to->value;
+
+    if (!_quaternionOffset)
+    {
+        for (unsigned int i = 0; i < _componentCount; i++)
+        {
+            if (fromValue[i] == toValue[i])
+            {
+                dst[i] = fromValue[i];
+            }
+            else
+            {
+                if (index == 0)
+                {
+                    outValue = toValue[i] - fromValue[i];
+                }
+                else
+                {
+                    outValue = (toValue[i] - (from - 1)->value[i]) * ((from->time - (from - 1)->time) / (to->time - (from - 1)->time));
+                }
+
+                if (index == _pointCount - 2)
+                {
+                    inValue = toValue[i] - fromValue[i];
+                }
+                else
+                {
+                    inValue = ((to + 1)->value[i] - fromValue[i]) * ((to->time - from->time) / ((to + 1)->time - from->time));
+                }
+
+                dst[i] = hermiteSmooth(h00, h01, h10, h11, fromValue[i], outValue, toValue[i], inValue);
+            }
+        }
+    }
+    else
+    {
+        // Interpolate any values up to the quaternion offset as scalars.
+        unsigned int quaternionOffset = *_quaternionOffset;
+        unsigned int i = 0;
+        for (i = 0; i < quaternionOffset; i++)
+        {   
+            if (fromValue[i] == toValue[i])
+            {
+                dst[i] = fromValue[i];
+            }
+            else
+            {    
+                if (index == 0)
+                {
+                    outValue = toValue[i] - fromValue[i];
+                }
+                else
+                {
+                    outValue = (toValue[i] - (from - 1)->value[i]) * ((from->time - (from - 1)->time) / (to->time - (from - 1)->time));
+                }
+
+                if (index == _pointCount - 2)
+                {
+                    inValue = toValue[i] - fromValue[i];
+                }
+                else
+                {
+                    inValue = ((to + 1)->value[i] - fromValue[i]) * ((to->time - from->time) / ((to + 1)->time - from->time));
+                }
+
+                dst[i] = hermiteSmooth(h00, h01, h10, h11, fromValue[i], outValue, toValue[i], inValue);
+            }
+        }
+
+        // Handle quaternion component.
+        if (index == 0)
+        {
+            outValue = to->time - from->time;
+        }
+        else
+        {
+            outValue = (to->time - (from - 1)->time) * ((from->time - (from - 1)->time) / (to->time - (from - 1)->time));
+        }
+
+        if (index == _pointCount - 2)
+        {
+            inValue = to->time - from->time;
+        }
+        else
+        {
+            inValue = ((to + 1)->time - from->time) * ((to->time - from->time) / ((to + 1)->time - from->time));
+        }
+
+        float interpTime = hermiteSmooth(h00, h01, h10, h11, from->time, outValue, to->time, inValue);
+        interpolateQuaternion(interpTime, (fromValue + i), (toValue + i), (dst + i));
+        
+        // Handle remaining components (if any) as scalars
+        for (i += 4; i < _componentCount; i++)
+        {
+            if (fromValue[i] == toValue[i])
+            {
+                dst[i] = fromValue[i];
+            }
+            else
+            {
+                // Interpolate as scalar.
+                if (index == 0)
+                {
+                    outValue = toValue[i] - fromValue[i];
+                }
+                else
+                {
+                    outValue = (toValue[i] - (from - 1)->value[i]) * ((from->time - (from - 1)->time) / (to->time - (from - 1)->time));
+                }
+
+                if (index == _pointCount - 2)
+                {
+                    inValue = toValue[i] - fromValue[i];
+                }
+                else
+                {
+                    inValue = ((to + 1)->value[i] - fromValue[i]) * ((to->time - from->time) / ((to + 1)->time - from->time));
+                }
+
+                dst[i] = hermiteSmooth(h00, h01, h10, h11, fromValue[i], outValue, toValue[i], inValue);
+            }
+        }
+    }
+}
+
+void Curve::interpolateLinear(float s, Point* from, Point* to, float* dst) const
+{
+    float* fromValue = from->value;
+    float* toValue = to->value;
+
+    if (!_quaternionOffset)
+    {
+        for (unsigned int i = 0; i < _componentCount; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = lerpInl(s, fromValue[i], toValue[i]);
+        }
+    }
+    else
+    {
+        // Interpolate any values up to the quaternion offset as scalars.
+        unsigned int quaternionOffset = *_quaternionOffset;
+        unsigned int i = 0;
+        for (i = 0; i < quaternionOffset; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = lerpInl(s, fromValue[i], toValue[i]);
+        }
+
+        // Handle quaternion component.
+        interpolateQuaternion(s, (fromValue + i), (toValue + i), (dst + i));
+        
+        // handle any remaining components as scalars
+        for (i += 4; i < _componentCount; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = lerpInl(s, fromValue[i], toValue[i]);
+        }
+    }
+}
+
+void Curve::interpolateQuaternion(float s, float* from, float* to, float* dst) const
+{
+    // Evaluate.
+    if (s >= 0)
+    {
+        Quaternion::slerp(from[0], from[1], from[2], from[3], to[0], to[1], to[2], to[3], s, dst, dst + 1, dst + 2, dst + 3);
+    }
+    else
+        Quaternion::slerp(to[0], to[1], to[2], to[3], from[0], from[1], from[2], from[3], s, dst, dst + 1, dst + 2, dst + 3);
+
+    //((Quaternion*) dst)->normalize();
+}
+
+int Curve::determineIndex(float time) const
+{
+    unsigned int min = 0;
+    unsigned int max = _pointCount - 1;
+    unsigned int mid = 0;
+
+    // Do a binary search to determine the index.
+    do 
+    {
+        mid = (min + max) >> 1;
+
+        if (time >= _points[mid].time && time <= _points[mid + 1].time)
+            return mid;
+        else if (time < _points[mid].time)
+            max = mid - 1;
+        else
+            min = mid + 1;
+    } while (min <= max);
+    
+    // We should never hit this!
+    return -1;
+}
+
+int Curve::getInterpolationType(const char* curveId)
+{
+    if (strcmp(curveId, "BEZIER") == 0)
+    {
+        return Curve::BEZIER;
+    }
+    else if (strcmp(curveId, "BSPLINE") == 0)
+    {
+        return Curve::BSPLINE;
+    }
+    else if (strcmp(curveId, "FLAT") == 0)
+    {
+        return Curve::FLAT;
+    }
+    else if (strcmp(curveId, "HERMITE") == 0)
+    {
+        return Curve::HERMITE;
+    }
+    else if (strcmp(curveId, "LINEAR") == 0)
+    {
+        return Curve::LINEAR;
+    }
+    else if (strcmp(curveId, "SMOOTH") == 0)
+    {
+        return Curve::SMOOTH;
+    }
+    else if (strcmp(curveId, "STEP") == 0)
+    {
+        return Curve::STEP;
+    }
+    else if (strcmp(curveId, "QUADRATIC_IN") == 0)
+    {
+        return Curve::QUADRATIC_IN;
+    }
+    else if (strcmp(curveId, "QUADRATIC_OUT") == 0)
+    {
+        return Curve::QUADRATIC_OUT;
+    }
+    else if (strcmp(curveId, "QUADRATIC_IN_OUT") == 0)
+    {
+        return Curve::QUADRATIC_IN_OUT;
+    }
+    else if (strcmp(curveId, "QUADRATIC_OUT_IN") == 0)
+    {
+        return Curve::QUADRATIC_OUT_IN;
+    }
+    else if (strcmp(curveId, "CUBIC_IN") == 0)
+    {
+        return Curve::CUBIC_IN;
+    }
+    else if (strcmp(curveId, "CUBIC_OUT") == 0)
+    {
+        return Curve::CUBIC_OUT;
+    }
+    else if (strcmp(curveId, "CUBIC_IN_OUT") == 0)
+    {
+        return Curve::CUBIC_IN_OUT;
+    }
+    else if (strcmp(curveId, "CUBIC_OUT_IN") == 0)
+    {
+        return Curve::CUBIC_OUT_IN;
+    }
+    else if (strcmp(curveId, "QUARTIC_IN") == 0)
+    {
+        return Curve::QUARTIC_IN;
+    }
+    else if (strcmp(curveId, "QUARTIC_OUT") == 0)
+    {
+        return Curve::QUARTIC_OUT;
+    }
+    else if (strcmp(curveId, "QUARTIC_IN_OUT") == 0)
+    {
+        return Curve::QUARTIC_IN_OUT;
+    }
+    else if (strcmp(curveId, "QUARTIC_OUT_IN") == 0)
+    {
+        return Curve::QUARTIC_OUT_IN;
+    }
+    else if (strcmp(curveId, "QUINTIC_IN") == 0)
+    {
+        return Curve::QUINTIC_IN;
+    }
+    else if (strcmp(curveId, "QUINTIC_OUT") == 0)
+    {
+        return Curve::QUINTIC_OUT;
+    }
+    else if (strcmp(curveId, "QUINTIC_IN_OUT") == 0)
+    {
+        return Curve::QUINTIC_IN_OUT;
+    }
+    else if (strcmp(curveId, "QUINTIC_OUT_IN") == 0)
+    {
+        return Curve::QUINTIC_OUT_IN;
+    }
+    else if (strcmp(curveId, "SINE_IN") == 0)
+    {
+        return Curve::SINE_IN;
+    }
+    else if (strcmp(curveId, "SINE_OUT") == 0)
+    {
+        return Curve::SINE_OUT;
+    }
+    else if (strcmp(curveId, "SINE_IN_OUT") == 0)
+    {
+        return Curve::SINE_IN_OUT;
+    }
+    else if (strcmp(curveId, "SINE_OUT_IN") == 0)
+    {
+        return Curve::SINE_OUT_IN;
+    }
+    else if (strcmp(curveId, "EXPONENTIAL_IN") == 0)
+    {
+        return Curve::EXPONENTIAL_IN;
+    }
+    else if (strcmp(curveId, "EXPONENTIAL_OUT") == 0)
+    {
+        return Curve::EXPONENTIAL_OUT;
+    }
+    else if (strcmp(curveId, "EXPONENTIAL_IN_OUT") == 0)
+    {
+        return Curve::EXPONENTIAL_IN_OUT;
+    }
+    else if (strcmp(curveId, "EXPONENTIAL_OUT_IN") == 0)
+    {
+        return Curve::EXPONENTIAL_OUT_IN;
+    }
+    else if (strcmp(curveId, "CIRCULAR_IN") == 0)
+    {
+        return Curve::CIRCULAR_IN;
+    }
+    else if (strcmp(curveId, "CIRCULAR_OUT") == 0)
+    {
+        return Curve::CIRCULAR_OUT;
+    }
+    else if (strcmp(curveId, "CIRCULAR_IN_OUT") == 0)
+    {
+        return Curve::CIRCULAR_IN_OUT;
+    }
+    else if (strcmp(curveId, "CIRCULAR_OUT_IN") == 0)
+    {
+        return Curve::CIRCULAR_OUT_IN;
+    }
+    else if (strcmp(curveId, "ELASTIC_IN") == 0)
+    {
+        return Curve::ELASTIC_IN;
+    }
+    else if (strcmp(curveId, "ELASTIC_OUT") == 0)
+    {
+        return Curve::ELASTIC_OUT;
+    }
+    else if (strcmp(curveId, "ELASTIC_IN_OUT") == 0)
+    {
+        return Curve::ELASTIC_IN_OUT;
+    }
+    else if (strcmp(curveId, "ELASTIC_OUT_IN") == 0)
+    {
+        return Curve::ELASTIC_OUT_IN;
+    }
+    else if (strcmp(curveId, "OVERSHOOT_IN") == 0)
+    {
+        return Curve::OVERSHOOT_IN;
+    }
+    else if (strcmp(curveId, "OVERSHOOT_OUT") == 0)
+    {
+        return Curve::OVERSHOOT_OUT;
+    }
+    else if (strcmp(curveId, "OVERSHOOT_IN_OUT") == 0)
+    {
+        return Curve::OVERSHOOT_IN_OUT;
+    }
+    else if (strcmp(curveId, "OVERSHOOT_OUT_IN") == 0)
+    {
+        return Curve::OVERSHOOT_OUT_IN;
+    }
+    else if (strcmp(curveId, "BOUNCE_IN") == 0)
+    {
+        return Curve::BOUNCE_IN;
+    }
+    else if (strcmp(curveId, "BOUNCE_OUT") == 0)
+    {
+        return Curve::BOUNCE_OUT;
+    }
+    else if (strcmp(curveId, "BOUNCE_IN_OUT") == 0)
+    {
+        return Curve::BOUNCE_IN_OUT;
+    }
+    else if (strcmp(curveId, "BOUNCE_OUT_IN") == 0)
+    {
+        return Curve::BOUNCE_OUT_IN;
+    }
+
+    return -1;
+}
+
+}

+ 484 - 0
gameplay-encoder/src/Curve.h

@@ -0,0 +1,484 @@
+#ifndef CURVE_H_
+#define CURVE_H_
+
+namespace gameplay
+{
+
+/**
+ * Represents an n-dimensional curve.
+ */
+class Curve
+{
+    friend class Animation;
+    friend class AnimationClip;
+    friend class AnimationController;
+    friend class MeshSkin;
+
+public:
+
+    /**
+     * Types of interpolation.
+     *
+     * Defines how the points in the curve are connected.
+     *
+     * Note: InterpolationType::BEZIER requires control points and InterpolationType::HERMITE requires tangents.
+     */
+    enum InterpolationType
+    {
+        /**
+         * Bezier Interpolation. 
+         *
+         * Requires that two control points are set for each segment.
+         */
+        BEZIER,
+
+        /**
+         * B-Spline Interpolation. 
+         *
+         * Uses the points as control points, and the curve is guaranteed to only pass through the
+         * first and last point.
+         */
+        BSPLINE,
+
+        /**
+         * Flat Interpolation. 
+         * 
+         * A form of Hermite interpolation that generates flat tangents for you. The tangents have a value equal to 0.
+         */
+        FLAT,
+
+        /**
+         * Hermite Interpolation. 
+         *
+         * Requires that two tangents for each segment.
+         */
+        HERMITE,
+
+        /**
+         * Linear Interpolation.
+         */
+        LINEAR,
+
+        /** 
+         * Smooth Interpolation. 
+         *
+         * A form of Hermite interpolation that generates tangents for each segment based on the points prior to and after the segment.
+         */
+        SMOOTH,
+
+        /**
+         * Discrete Interpolation.
+         */ 
+        STEP,
+
+        /**
+         * Quadratic-In Interpolation.
+         */
+        QUADRATIC_IN, 
+        
+        /**
+         * Quadratic-Out Interpolation.
+         */
+        QUADRATIC_OUT,
+
+        /**
+         * Quadratic-In-Out Interpolation.
+         */
+        QUADRATIC_IN_OUT,
+
+        /**
+         * Quadratic-Out-In Interpolation.
+         */
+        QUADRATIC_OUT_IN,
+
+        /**
+         * Cubic-In Interpolation.
+         */
+        CUBIC_IN,
+        
+        /**
+         * Cubic-Out Interpolation.
+         */
+        CUBIC_OUT,
+        
+        /**
+         * Cubic-In-Out Interpolation.
+         */
+        CUBIC_IN_OUT,
+        
+        /**
+         * Cubic-Out-In Interpolation.
+         */
+        CUBIC_OUT_IN,
+
+        /**
+         * Quartic-In Interpolation.
+         */
+        QUARTIC_IN,
+
+        /**
+         * Quartic-Out Interpolation.
+         */
+        QUARTIC_OUT,
+
+        /**
+         * Quartic-In-Out Interpolation.
+         */
+        QUARTIC_IN_OUT,
+
+        /**
+         * Quartic-Out-In Interpolation.
+         */
+        QUARTIC_OUT_IN,
+
+        /**
+         * Quintic-In Interpolation.
+         */
+        QUINTIC_IN,
+        
+        /**
+         * Quintic-Out Interpolation.
+         */
+        QUINTIC_OUT,
+        
+        /**
+         * Quintic-In-Out Interpolation.
+         */
+        QUINTIC_IN_OUT,
+        
+        /**
+         * Quintic-Out-In Interpolation.
+         */
+        QUINTIC_OUT_IN,
+        
+        /**
+         * Sine-In Interpolation.
+         */
+        SINE_IN,
+        
+        /**
+         * Sine-Out Interpolation.
+         */
+        SINE_OUT,
+        
+        /**
+         * Sine-In-Out Interpolation.
+         */
+        SINE_IN_OUT,
+        
+        /**
+         * Sine-Out-In Interpolation.
+         */
+        SINE_OUT_IN,
+
+        /**
+         * Exponential-In Interpolation.
+         */
+        EXPONENTIAL_IN,
+
+        /**
+         * Exponential-Out Interpolation.
+         */
+        EXPONENTIAL_OUT,
+
+        /**
+         * Exponential-In-Out Interpolation.
+         */
+        EXPONENTIAL_IN_OUT,
+
+        /**
+         * Exponential-Out-In Interpolation.
+         */
+        EXPONENTIAL_OUT_IN,
+
+        /**
+         * Circular-In Interpolation.
+         */
+        CIRCULAR_IN,
+
+        /**
+         * Circular-Out Interpolation.
+         */
+        CIRCULAR_OUT,
+
+        /**
+         * Circular-In-Out Interpolation.
+         */
+        CIRCULAR_IN_OUT,
+
+        /**
+         * Circular-Out-In Interpolation.
+         */
+        CIRCULAR_OUT_IN,
+
+        /**
+         * Elastic-In Interpolation.
+         */
+        ELASTIC_IN,
+
+        /**
+         * Elastic-Out Interpolation.
+         */
+        ELASTIC_OUT,
+
+        /**
+         * Elastic-In-Out Interpolation.
+         */
+        ELASTIC_IN_OUT,
+
+        /**
+         * Elastic-Out-In Interpolation.
+         */
+        ELASTIC_OUT_IN,
+
+        /**
+         * Overshoot-In Interpolation.
+         */
+        OVERSHOOT_IN,
+
+        /**
+         * Overshoot-Out Interpolation.
+         */
+        OVERSHOOT_OUT,
+
+        /**
+         * Overshoot-In-Out Interpolation.
+         */
+        OVERSHOOT_IN_OUT,
+
+        /**
+         * Overshoot-Out-In Interpolation.
+         */
+        OVERSHOOT_OUT_IN,
+
+        /**
+         * Bounce-In Interpolation.
+         */
+        BOUNCE_IN,
+
+        /**
+         * Bounce-Out Interpolation.
+         */
+        BOUNCE_OUT,
+
+        /**
+         * Bounce-In-Out Interpolation.
+         */
+        BOUNCE_IN_OUT,
+
+        /**
+         * Bounce-Out-In Interpolation.
+         */
+        BOUNCE_OUT_IN
+    };
+
+
+    /**
+     * Constructs a new curve and the specified parameters.
+     *
+     * @param pointCount The number of points in the curve.
+     * @param componentCount The number of float component values per key value.
+     */
+    Curve(unsigned int pointCount, unsigned int componentCount);
+
+    /**
+     * Destructor.
+     */
+    ~Curve();
+
+    /**
+     * Gets the number of points in the curve.
+     *
+     * @return The number of points in the curve.
+     */
+    unsigned int getPointCount() const;
+
+    /**
+     * Gets the number of float component values per points.
+     *
+     * @return The number of float component values per point.
+     */
+    unsigned int getComponentCount() const;
+
+    /**
+     * Returns the start time for the curve.
+     *
+     * @return The curve's start time.
+     */
+    float getStartTime() const;
+
+    /**
+     * Returns the end time for the curve.
+     *
+     * @return The curve's end time.
+     */
+    float getEndTime() const;
+
+    /**
+     * Sets the given point values on the curve the curve.
+     *
+     * @param index The index of the point.
+     * @param time The time for the key.
+     * @param value The point to add.
+     * @param type The curve interpolation type.
+     */
+    void setPoint(unsigned int index, float time, float* value, InterpolationType type);
+
+    /**
+     * Sets the given point on the curve for the specified index and the specified parameters.
+     *
+     * @param index The index of the point.
+     * @param time The time of the point within the curve.
+     * @param value The value of the point to copy the data from.
+     * @param type The curve interpolation type.
+     * @param inValue The tangent approaching the point.
+     * @param outValue The tangent leaving the point.
+     */
+    void setPoint(unsigned int index, float time, float* value, InterpolationType type, float* inValue, float* outValue);
+
+    /**
+     * Sets the tangents for a point on the curve specified by the index.
+     *
+     * @param index The index of the point.
+     * @param type The curve interpolation type.
+     * @param inValue The tangent approaching the point.
+     * @param outValue The tangent leaving the point.
+     */
+    void setTangent(unsigned int index, InterpolationType type, float* inValue, float* outValue);
+    
+    /**
+     * Evaluates the curve at the given position value (between 0.0 and 1.0 inclusive).
+     *
+     * @param time The position to evaluate the curve at.
+     * @param dst The evaluated value of the curve at the given time.
+     */
+    void evaluate(float time, float* dst) const;
+
+    /**
+     * Linear interpolation function.
+     */
+    static float lerp(float t, float from, float to);
+
+private:
+
+    /**
+     * Defines a single point within a curve.
+     */
+    class Point
+    {
+    public:
+
+        /** The time of the point within the curve. */
+        float time;
+        /** The value of the point. */
+        float* value;
+        /** The value of the tangent when approaching this point (from the previous point in the curve). */
+        float* inValue;
+        /** The value of the tangent when leaving this point (towards the next point in the curve). */
+        float* outValue;
+        /** The type of interpolation to use between this point and the next point. */
+        InterpolationType type;
+
+        /**
+         * Constructor.
+         */
+        Point();
+
+        /**
+         * Destructor.
+         */
+        ~Point();
+    };
+
+    /**
+     * Constructor.
+     */
+    Curve();
+
+    /**
+     * Constructor.
+     */
+    Curve(const Curve& copy);
+
+    /**
+     * Bezier interpolation function.
+     */
+    void interpolateBezier(float s, Point* from, Point* to, float* dst) const;
+
+    /**
+     * Bspline interpolation function.
+     */
+    void interpolateBSpline(float s, Point* c0, Point* c1, Point* c2, Point* c3, float* dst) const;
+
+    /**
+     * Hermite interpolation function.
+     */
+    void interpolateHermite(float s, Point* from, Point* to, float* dst) const;
+
+    /**
+     * Hermite interpolation function.
+     */
+    void interpolateHermiteFlat(float s, Point* from, Point* to, float* dst) const;
+
+    /**
+     * Hermite interpolation function.
+     */
+    void interpolateHermiteSmooth(float s, unsigned int index, Point* from, Point* to, float* dst) const;
+
+    /** 
+     * Linear interpolation function.
+     */ 
+    void interpolateLinear(float s, Point* from, Point* to, float* dst) const;
+
+    /**
+     * Quaternion interpolation function.
+     */
+    void interpolateQuaternion(float s, float* from, float* to, float* dst) const;
+    
+    /**
+     * Determines the current keyframe to interpolate from based on the specified time.
+     */ 
+    int determineIndex(float time) const;
+
+    /**
+     * Sets the offset for the beginning of a Quaternion piece of data within the curve's value span at the specified
+     * index. The next four components of data starting at the given index will be interpolated as a Quaternion.
+     * This function will assert an error if the given index is greater than the component size subtracted by the four components required
+     * to store a quaternion.
+     * 
+     * @param index The index of the Quaternion rotation data.
+     */
+    void setQuaternionOffset(unsigned int index);
+
+    /**
+     * Gets the InterpolationType value for the given string ID
+     *
+     * @param interpolationId The string representation of the InterpolationType
+     * @return the InterpolationType value; -1 if the string does not represent an InterpolationType.
+     */
+    static int getInterpolationType(const char* interpolationId);
+
+    unsigned int _pointCount;           // Number of points on the curve.
+    unsigned int _componentCount;       // Number of components on the curve.
+    unsigned int _componentSize;        // The component size (in bytes).
+    unsigned int* _quaternionOffset;    // Offset for the rotation component.
+    Point* _points;                     // The points on the curve.
+};
+
+inline static float bezier(float eq0, float eq1, float eq2, float eq3, float from, float out, float to, float in);
+
+inline static float bspline(float eq0, float eq1, float eq2, float eq3, float c0, float c1, float c2, float c3);
+
+inline static float hermite(float h00, float h01, float h10, float h11, float from, float out, float to, float in);
+
+inline static float hermiteFlat(float h00, float h01, float from, float to);
+
+inline static float hermiteSmooth(float h00, float h01, float h10, float h11, float from, float out, float to, float in);
+
+inline static float lerpInl(float s, float from, float to);
+
+}
+
+#include "Curve.inl"
+
+#endif

+ 36 - 0
gameplay-encoder/src/Curve.inl

@@ -0,0 +1,36 @@
+
+
+namespace gameplay
+{
+
+inline float bezier(float eq0, float eq1, float eq2, float eq3, float from, float out, float to, float in)
+{
+    return from * eq0 + out * eq1 + in * eq2 + to * eq3;
+}
+
+inline float bspline(float eq0, float eq1, float eq2, float eq3, float c0, float c1, float c2, float c3)
+{
+    return c0 * eq0 + c1 * eq1 + c2 * eq2 + c3 * eq3;
+}
+
+inline float hermite(float h00, float h01, float h10, float h11, float from, float out, float to, float in)
+{
+    return h00 * from + h01 * to + h10 * out + h11 * in;
+}
+
+inline float hermiteFlat(float h00, float h01, float from, float to)
+{
+    return h00 * from + h01 * to;
+}
+
+inline float hermiteSmooth(float h00, float h01, float h10, float h11, float from, float out, float to, float in)
+{
+    return h00 * from + h01 * to + h10 * out + h11 * in;
+}
+
+inline float lerpInl(float s, float from, float to)
+{
+    return from + (to - from) * s;
+}
+
+}

+ 1 - 0
gameplay-encoder/src/DAEChannelTarget.h

@@ -55,6 +55,7 @@ public:
     void getPropertyName(size_t index, std::string* str);
 
 private:
+    
     /**
      * The channel element.
      */

+ 1 - 0
gameplay-encoder/src/DAESceneEncoder.h

@@ -190,6 +190,7 @@ private:
     static int getVertexUsageType(const std::string& semantic);
     
 private:
+    
     DAE* _collada;        // Collada datastore in memory to read from.
     domCOLLADA* _dom;
     FILE* file;        // Output file to write to.

+ 1 - 0
gameplay-encoder/src/Effect.h

@@ -29,6 +29,7 @@ public:
     virtual void writeText(FILE* file);
 
 private:
+    
     std::string _vertexShader;
     std::string _fragmentShader;
 };

+ 3 - 0
gameplay-encoder/src/FileIO.h

@@ -1,6 +1,9 @@
 #ifndef FILEIO_H_
 #define FILEIO_H_
 
+#include <cstdio>
+#include <list>
+#include <vector>
 
 #include "Vector2.h"
 #include "Vector3.h"

+ 15 - 13
gameplay-encoder/src/MeshSkin.cpp

@@ -6,7 +6,7 @@
 #include "GPBFile.h"
 #include "Animations.h"
 #include "Transform.h"
-#include "../../gameplay/src/Curve.h"
+#include "Curve.h"
 #include "Matrix.h"
 
 namespace gameplay
@@ -313,26 +313,28 @@ void MeshSkin::computeBounds()
         if (duration > maxDuration)
             maxDuration = duration;
 
-        // Set curve points
-        float* keyValuesPtr = keyValues;
-        for (unsigned int j = 0; j < keyCount; ++j)
+        if (duration > 0.0f)
         {
-            // Store time normalized, between 0-1
-            float t = (keyTimes[j] - startTime) / duration;
+            // Set curve points
+            float* keyValuesPtr = keyValues;
+            for (unsigned int j = 0; j < keyCount; ++j)
+            {
+                // Store time normalized, between 0-1
+                float t = (keyTimes[j] - startTime) / duration;
 
-            // Set the curve point
-            // TODO: Handle other interpolation types
-            curve->setPoint(j, t, keyValuesPtr, gameplay::Curve::LINEAR);
+                // Set the curve point
+                // TODO: Handle other interpolation types
+                curve->setPoint(j, t, keyValuesPtr, gameplay::Curve::LINEAR);
 
-            // Move to the next point on the curve
-            keyValuesPtr += curve->getComponentCount();
+                // Move to the next point on the curve
+                keyValuesPtr += curve->getComponentCount();
+            }
+            curves.push_back(curve);
         }
 
         delete[] keyValues;
         keyValues = NULL;
 
-        curves.push_back(curve);
-
         DEBUGPRINT_VARG("> %d%%\r", (int)((float)(i+1) / (float)channelCount * 100.0f));
     }
     DEBUGPRINT("\n");

+ 2 - 2
gameplay-encoder/src/Reference.h

@@ -1,5 +1,5 @@
-#ifndef REF_H_
-#define REF_H_
+#ifndef REFERENCE_H_
+#define REFERENCE_H_
 
 #include "Object.h"
 

+ 1 - 1
gameplay/android/jni/Android.mk

@@ -16,7 +16,7 @@ LOCAL_PATH := $(call my-dir)/../../src
 
 include $(CLEAR_VARS)
 LOCAL_MODULE    := libgameplay
-LOCAL_SRC_FILES := Animation.cpp DepthStencilTarget.cpp MeshBatch.cpp PhysicsRigidBody.cpp SceneLoader.cpp AnimationClip.cpp Effect.cpp MeshPart.cpp PhysicsSocketConstraint.cpp SpriteBatch.cpp AnimationController.cpp FileSystem.cpp MeshSkin.cpp PhysicsSpringConstraint.cpp Technique.cpp AnimationTarget.cpp Font.cpp Model.cpp Plane.cpp Texture.cpp AnimationValue.cpp FrameBuffer.cpp Node.cpp PlatformAndroid.cpp PlatformQNX.cpp AudioBuffer.cpp Frustum.cpp Package.cpp PlatformWin32.cpp Transform.cpp AudioController.cpp Game.cpp ParticleEmitter.cpp Properties.cpp Vector2.cpp AudioListener.cpp Image.cpp Pass.cpp Quaternion.cpp Vector3.cpp AudioSource.cpp Joint.cpp PhysicsConstraint.cpp Ray.cpp Vector4.cpp BoundingBox.cpp Light.cpp PhysicsController.cpp Rectangle.cpp VertexAttributeBinding.cpp BoundingSphere.cpp Material.cpp PhysicsFixedConstraint.cpp Ref.cpp VertexFormat.cpp Camera.cpp MaterialParameter.cpp PhysicsGenericConstraint.cpp RenderState.cpp Viewport.cpp Curve.cpp Matrix.cpp PhysicsHingeConstraint.cpp RenderTarget.cpp DebugNew.cpp Mesh.cpp PhysicsMotionState.cpp Scene.cpp
+LOCAL_SRC_FILES := AbsoluteLayout.cpp Animation.cpp AnimationClip.cpp AnimationController.cpp AnimationTarget.cpp AnimationValue.cpp AudioBuffer.cpp AudioController.cpp AudioListener.cpp AudioSource.cpp BoundingBox.cpp BoundingSphere.cpp Button.cpp Camera.cpp CheckBox.cpp Container.cpp Control.cpp Curve.cpp DebugNew.cpp DepthStencilTarget.cpp Effect.cpp FileSystem.cpp Font.cpp Form.cpp FrameBuffer.cpp Frustum.cpp Game.cpp gameplay-main-android.cpp gameplay-main-qnx.cpp gameplay-main-win32.cpp Image.cpp Joint.cpp Label.cpp Light.cpp Material.cpp MaterialParameter.cpp Matrix.cpp Mesh.cpp MeshBatch.cpp MeshPart.cpp MeshSkin.cpp Model.cpp Node.cpp Package.cpp ParticleEmitter.cpp Pass.cpp PhysicsCharacter.cpp PhysicsCollisionObject.cpp PhysicsCollisionShape.cpp PhysicsConstraint.cpp PhysicsController.cpp PhysicsFixedConstraint.cpp PhysicsGenericConstraint.cpp PhysicsGhostObject.cpp PhysicsHingeConstraint.cpp PhysicsMotionState.cpp PhysicsRigidBody.cpp PhysicsSocketConstraint.cpp PhysicsSpringConstraint.cpp Plane.cpp PlatformAndroid.cpp PlatformQNX.cpp PlatformWin32.cpp Properties.cpp Quaternion.cpp RadioButton.cpp Ray.cpp Rectangle.cpp Ref.cpp RenderState.cpp RenderTarget.cpp Scene.cpp SceneLoader.cpp Slider.cpp SpriteBatch.cpp Technique.cpp TextBox.cpp Texture.cpp Theme.cpp Transform.cpp Vector2.cpp Vector3.cpp Vector4.cpp VertexAttributeBinding.cpp VertexFormat.cpp VerticalLayout.cpp
 LOCAL_CFLAGS := -D__ANDROID__ -I"../../external-deps/bullet/include" -I"../../external-deps/libpng/include"
 LOCAL_STATIC_LIBRARIES := android_native_app_glue
 

+ 1 - 2
gameplay/gameplay.vcxproj

@@ -101,7 +101,6 @@
     <ClCompile Include="src\VertexAttributeBinding.cpp" />
     <ClCompile Include="src\VertexFormat.cpp" />
     <ClCompile Include="src\VerticalLayout.cpp" />
-    <ClCompile Include="src\Viewport.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\AbsoluteLayout.h" />
@@ -177,6 +176,7 @@
     <ClInclude Include="src\RenderTarget.h" />
     <ClInclude Include="src\Scene.h" />
     <ClInclude Include="src\SceneLoader.h" />
+    <ClInclude Include="src\ScreenDisplayer.h" />
     <ClInclude Include="src\Slider.h" />
     <ClInclude Include="src\SpriteBatch.h" />
     <ClInclude Include="src\Technique.h" />
@@ -192,7 +192,6 @@
     <ClInclude Include="src\VertexAttributeBinding.h" />
     <ClInclude Include="src\VertexFormat.h" />
     <ClInclude Include="src\VerticalLayout.h" />
-    <ClInclude Include="src\Viewport.h" />
   </ItemGroup>
   <ItemGroup>
     <None Include="res\logo_black.png" />

+ 3 - 6
gameplay/gameplay.vcxproj.filters

@@ -126,9 +126,6 @@
     <ClCompile Include="src\VertexFormat.cpp">
       <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\Viewport.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
     <ClCompile Include="src\AudioController.cpp">
       <Filter>src</Filter>
     </ClCompile>
@@ -395,9 +392,6 @@
     <ClInclude Include="src\VertexFormat.h">
       <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\Viewport.h">
-      <Filter>src</Filter>
-    </ClInclude>
     <ClInclude Include="src\AudioController.h">
       <Filter>src</Filter>
     </ClInclude>
@@ -545,6 +539,9 @@
     <ClInclude Include="src\PhysicsCollisionShape.h">
       <Filter>src</Filter>
     </ClInclude>
+    <ClInclude Include="src\ScreenDisplayer.h">
+      <Filter>src</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="res\shaders\bumped-specular.vsh">

+ 12 - 12
gameplay/gameplay.xcodeproj/project.pbxproj

@@ -14,6 +14,10 @@
 		4208DEEC14A407B900D3C511 /* Keyboard.h in Headers */ = {isa = PBXBuildFile; fileRef = 4208DEEB14A407B900D3C511 /* Keyboard.h */; };
 		4208DEEE14A407D500D3C511 /* Touch.h in Headers */ = {isa = PBXBuildFile; fileRef = 4208DEED14A407D500D3C511 /* Touch.h */; };
 		4234D99E14686C52003031B3 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4234D99D14686C52003031B3 /* Cocoa.framework */; };
+		42554EA1152BC35C000ED910 /* PhysicsCollisionShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42554E9F152BC35C000ED910 /* PhysicsCollisionShape.cpp */; };
+		42554EA2152BC35C000ED910 /* PhysicsCollisionShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42554E9F152BC35C000ED910 /* PhysicsCollisionShape.cpp */; };
+		42554EA3152BC35C000ED910 /* PhysicsCollisionShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 42554EA0152BC35C000ED910 /* PhysicsCollisionShape.h */; };
+		42554EA4152BC35C000ED910 /* PhysicsCollisionShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 42554EA0152BC35C000ED910 /* PhysicsCollisionShape.h */; };
 		428390991489D6E800E2B2F5 /* SceneLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 428390971489D6E800E2B2F5 /* SceneLoader.cpp */; };
 		4283909A1489D6E800E2B2F5 /* SceneLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 428390981489D6E800E2B2F5 /* SceneLoader.h */; };
 		42CCD556146EC1EB00353661 /* libpng.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42CCD555146EC1EB00353661 /* libpng.a */; };
@@ -149,8 +153,6 @@
 		42CD0EC8147D8FF60000361E /* VertexAttributeBinding.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E41147D8FF50000361E /* VertexAttributeBinding.h */; };
 		42CD0EC9147D8FF60000361E /* VertexFormat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E42147D8FF50000361E /* VertexFormat.cpp */; };
 		42CD0ECA147D8FF60000361E /* VertexFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E43147D8FF50000361E /* VertexFormat.h */; };
-		42CD0ECB147D8FF60000361E /* Viewport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E44147D8FF50000361E /* Viewport.cpp */; };
-		42CD0ECC147D8FF60000361E /* Viewport.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E45147D8FF50000361E /* Viewport.h */; };
 		5B04C52D14BFCFE100EB0071 /* Animation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DB1147D8FF50000361E /* Animation.cpp */; };
 		5B04C52E14BFCFE100EB0071 /* AnimationClip.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DB3147D8FF50000361E /* AnimationClip.cpp */; };
 		5B04C52F14BFCFE100EB0071 /* AnimationController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DB5147D8FF50000361E /* AnimationController.cpp */; };
@@ -212,7 +214,6 @@
 		5B04C56D14BFCFE100EB0071 /* Vector4.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E3D147D8FF50000361E /* Vector4.cpp */; };
 		5B04C56E14BFCFE100EB0071 /* VertexAttributeBinding.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E40147D8FF50000361E /* VertexAttributeBinding.cpp */; };
 		5B04C56F14BFCFE100EB0071 /* VertexFormat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E42147D8FF50000361E /* VertexFormat.cpp */; };
-		5B04C57014BFCFE100EB0071 /* Viewport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E44147D8FF50000361E /* Viewport.cpp */; };
 		5B04C57114BFCFE100EB0071 /* SceneLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 428390971489D6E800E2B2F5 /* SceneLoader.cpp */; };
 		5B04C57214BFCFE100EB0071 /* Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4208DEE614A4079F00D3C511 /* Image.cpp */; };
 		5B04C57314BFCFE100EB0071 /* MeshBatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4201818D14A41B18008C3F56 /* MeshBatch.cpp */; };
@@ -286,7 +287,6 @@
 		5B04C5BE14BFCFE100EB0071 /* Vector4.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E3E147D8FF50000361E /* Vector4.h */; };
 		5B04C5BF14BFCFE100EB0071 /* VertexAttributeBinding.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E41147D8FF50000361E /* VertexAttributeBinding.h */; };
 		5B04C5C014BFCFE100EB0071 /* VertexFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E43147D8FF50000361E /* VertexFormat.h */; };
-		5B04C5C114BFCFE100EB0071 /* Viewport.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E45147D8FF50000361E /* Viewport.h */; };
 		5B04C5C214BFCFE100EB0071 /* SceneLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 428390981489D6E800E2B2F5 /* SceneLoader.h */; };
 		5B04C5C314BFCFE100EB0071 /* Image.h in Headers */ = {isa = PBXBuildFile; fileRef = 4208DEE714A4079F00D3C511 /* Image.h */; };
 		5B04C5C414BFCFE100EB0071 /* Keyboard.h in Headers */ = {isa = PBXBuildFile; fileRef = 4208DEEB14A407B900D3C511 /* Keyboard.h */; };
@@ -387,6 +387,8 @@
 		4208DEED14A407D500D3C511 /* Touch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Touch.h; path = src/Touch.h; sourceTree = SOURCE_ROOT; };
 		4234D99A14686C52003031B3 /* libgameplay.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgameplay.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		4234D99D14686C52003031B3 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
+		42554E9F152BC35C000ED910 /* PhysicsCollisionShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PhysicsCollisionShape.cpp; path = src/PhysicsCollisionShape.cpp; sourceTree = SOURCE_ROOT; };
+		42554EA0152BC35C000ED910 /* PhysicsCollisionShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PhysicsCollisionShape.h; path = src/PhysicsCollisionShape.h; sourceTree = SOURCE_ROOT; };
 		428390971489D6E800E2B2F5 /* SceneLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SceneLoader.cpp; path = src/SceneLoader.cpp; sourceTree = SOURCE_ROOT; };
 		428390981489D6E800E2B2F5 /* SceneLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SceneLoader.h; path = src/SceneLoader.h; sourceTree = SOURCE_ROOT; };
 		42C932AF14919FD10098216A /* Game.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Game.inl; path = src/Game.inl; sourceTree = SOURCE_ROOT; };
@@ -541,8 +543,6 @@
 		42CD0E41147D8FF50000361E /* VertexAttributeBinding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VertexAttributeBinding.h; path = src/VertexAttributeBinding.h; sourceTree = SOURCE_ROOT; };
 		42CD0E42147D8FF50000361E /* VertexFormat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VertexFormat.cpp; path = src/VertexFormat.cpp; sourceTree = SOURCE_ROOT; };
 		42CD0E43147D8FF50000361E /* VertexFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VertexFormat.h; path = src/VertexFormat.h; sourceTree = SOURCE_ROOT; };
-		42CD0E44147D8FF50000361E /* Viewport.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Viewport.cpp; path = src/Viewport.cpp; sourceTree = SOURCE_ROOT; };
-		42CD0E45147D8FF50000361E /* Viewport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Viewport.h; path = src/Viewport.h; sourceTree = SOURCE_ROOT; };
 		5B04C5CA14BFCFE100EB0071 /* libgameplay.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgameplay.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		5B04C5CB14BFD48500EB0071 /* gameplay-main-ios.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "gameplay-main-ios.mm"; path = "src/gameplay-main-ios.mm"; sourceTree = SOURCE_ROOT; };
 		5B04C5CC14BFD48500EB0071 /* PlatformiOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PlatformiOS.mm; path = src/PlatformiOS.mm; sourceTree = SOURCE_ROOT; };
@@ -784,6 +784,8 @@
 				5BD5266C150F8257004C9099 /* PhysicsCharacter.h */,
 				5BD5266D150F8257004C9099 /* PhysicsCollisionObject.cpp */,
 				5BD5266E150F8258004C9099 /* PhysicsCollisionObject.h */,
+				42554E9F152BC35C000ED910 /* PhysicsCollisionShape.cpp */,
+				42554EA0152BC35C000ED910 /* PhysicsCollisionShape.h */,
 				42CD0DFF147D8FF50000361E /* PhysicsConstraint.cpp */,
 				42CD0E00147D8FF50000361E /* PhysicsConstraint.h */,
 				42CD0E01147D8FF50000361E /* PhysicsConstraint.inl */,
@@ -868,8 +870,6 @@
 				42CD0E43147D8FF50000361E /* VertexFormat.h */,
 				5BD5264D150F822A004C9099 /* VerticalLayout.cpp */,
 				5BD5264E150F822A004C9099 /* VerticalLayout.h */,
-				42CD0E44147D8FF50000361E /* Viewport.cpp */,
-				42CD0E45147D8FF50000361E /* Viewport.h */,
 			);
 			name = src;
 			path = gameplay;
@@ -1019,7 +1019,6 @@
 				42CD0EC6147D8FF60000361E /* Vector4.h in Headers */,
 				42CD0EC8147D8FF60000361E /* VertexAttributeBinding.h in Headers */,
 				42CD0ECA147D8FF60000361E /* VertexFormat.h in Headers */,
-				42CD0ECC147D8FF60000361E /* Viewport.h in Headers */,
 				4283909A1489D6E800E2B2F5 /* SceneLoader.h in Headers */,
 				4208DEEA14A4079F00D3C511 /* Image.h in Headers */,
 				4208DEEC14A407B900D3C511 /* Keyboard.h in Headers */,
@@ -1044,6 +1043,7 @@
 				5BD52671150F8258004C9099 /* PhysicsCharacter.h in Headers */,
 				5BD52675150F8258004C9099 /* PhysicsCollisionObject.h in Headers */,
 				5BBE14401513E400003FB362 /* PhysicsGhostObject.h in Headers */,
+				42554EA3152BC35C000ED910 /* PhysicsCollisionShape.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1115,7 +1115,6 @@
 				5B04C5BE14BFCFE100EB0071 /* Vector4.h in Headers */,
 				5B04C5BF14BFCFE100EB0071 /* VertexAttributeBinding.h in Headers */,
 				5B04C5C014BFCFE100EB0071 /* VertexFormat.h in Headers */,
-				5B04C5C114BFCFE100EB0071 /* Viewport.h in Headers */,
 				5B04C5C214BFCFE100EB0071 /* SceneLoader.h in Headers */,
 				5B04C5C314BFCFE100EB0071 /* Image.h in Headers */,
 				5B04C5C414BFCFE100EB0071 /* Keyboard.h in Headers */,
@@ -1139,6 +1138,7 @@
 				5BC4E756150F843D00CBE1C0 /* Theme.h in Headers */,
 				5BC4E758150F843D00CBE1C0 /* VerticalLayout.h in Headers */,
 				5BBE14411513E400003FB362 /* PhysicsGhostObject.h in Headers */,
+				42554EA4152BC35C000ED910 /* PhysicsCollisionShape.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1273,7 +1273,6 @@
 				42CD0EC5147D8FF60000361E /* Vector4.cpp in Sources */,
 				42CD0EC7147D8FF60000361E /* VertexAttributeBinding.cpp in Sources */,
 				42CD0EC9147D8FF60000361E /* VertexFormat.cpp in Sources */,
-				42CD0ECB147D8FF60000361E /* Viewport.cpp in Sources */,
 				428390991489D6E800E2B2F5 /* SceneLoader.cpp in Sources */,
 				4208DEE914A4079F00D3C511 /* Image.cpp in Sources */,
 				4201819014A41B18008C3F56 /* MeshBatch.cpp in Sources */,
@@ -1292,6 +1291,7 @@
 				5BD5266F150F8258004C9099 /* PhysicsCharacter.cpp in Sources */,
 				5BD52673150F8258004C9099 /* PhysicsCollisionObject.cpp in Sources */,
 				5BBE143E1513E400003FB362 /* PhysicsGhostObject.cpp in Sources */,
+				42554EA1152BC35C000ED910 /* PhysicsCollisionShape.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1360,7 +1360,6 @@
 				5B04C56D14BFCFE100EB0071 /* Vector4.cpp in Sources */,
 				5B04C56E14BFCFE100EB0071 /* VertexAttributeBinding.cpp in Sources */,
 				5B04C56F14BFCFE100EB0071 /* VertexFormat.cpp in Sources */,
-				5B04C57014BFCFE100EB0071 /* Viewport.cpp in Sources */,
 				5B04C57114BFCFE100EB0071 /* SceneLoader.cpp in Sources */,
 				5B04C57214BFCFE100EB0071 /* Image.cpp in Sources */,
 				5B04C57314BFCFE100EB0071 /* MeshBatch.cpp in Sources */,
@@ -1381,6 +1380,7 @@
 				5BC4E755150F843D00CBE1C0 /* Theme.cpp in Sources */,
 				5BC4E757150F843D00CBE1C0 /* VerticalLayout.cpp in Sources */,
 				5BBE143F1513E400003FB362 /* PhysicsGhostObject.cpp in Sources */,
+				42554EA2152BC35C000ED910 /* PhysicsCollisionShape.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 9 - 29
gameplay/src/Animation.cpp

@@ -59,9 +59,9 @@ Animation::~Animation()
 }
 
 Animation::Channel::Channel(Animation* animation, AnimationTarget* target, int propertyId, Curve* curve, unsigned long duration)
-    : _animation(animation), _target(target), _propertyId(propertyId), _duration(duration)
+    : _animation(animation), _target(target), _propertyId(propertyId), _curve(curve), _duration(duration)
 {
-    _curveRef = Animation::CurveRef::create(curve);
+    _curve->addRef();
     // get property component count, and ensure the property exists on the AnimationTarget by getting the property component count.
     assert(_target->getAnimationPropertyComponentCount(propertyId));
 
@@ -71,46 +71,24 @@ Animation::Channel::Channel(Animation* animation, AnimationTarget* target, int p
 }
 
 Animation::Channel::Channel(const Channel& copy, Animation* animation, AnimationTarget* target)
-    : _animation(animation), _target(target), _propertyId(copy._propertyId), _duration(copy._duration)
+    : _animation(animation), _target(target), _propertyId(copy._propertyId), _curve(copy._curve), _duration(copy._duration)
 {
-    _curveRef = copy._curveRef;
-    _curveRef->addRef();
-
+    _curve->addRef();
     _animation->addRef();
     _target->addChannel(this);
 }
 
 Animation::Channel::~Channel()
 {
-    SAFE_RELEASE(_curveRef);
+    SAFE_RELEASE(_curve);
     SAFE_RELEASE(_animation);
 }
 
 Curve* Animation::Channel::getCurve() const
-{
-    return _curveRef->getCurve();
-}
-
-Animation::CurveRef* Animation::CurveRef::create(Curve* curve)
-{
-    return new CurveRef(curve);
-}
-
-Curve* Animation::CurveRef::getCurve() const
 {
     return _curve;
 }
 
-Animation::CurveRef::CurveRef(Curve* curve)
-    : _curve(curve)
-{
-}
-
-Animation::CurveRef::~CurveRef()
-{
-    SAFE_DELETE(_curve);
-}
-
 const char* Animation::getId() const
 {
     return _id.c_str();
@@ -301,7 +279,7 @@ Animation::Channel* Animation::createChannel(AnimationTarget* target, int proper
     unsigned int propertyComponentCount = target->getAnimationPropertyComponentCount(propertyId);
     assert(propertyComponentCount > 0);
 
-    Curve* curve = new Curve(keyCount, propertyComponentCount);
+    Curve* curve = Curve::create(keyCount, propertyComponentCount);
     if (target->_targetType == AnimationTarget::TRANSFORM)
         setTransformRotationOffset(curve, propertyId);
 
@@ -328,6 +306,7 @@ Animation::Channel* Animation::createChannel(AnimationTarget* target, int proper
     SAFE_DELETE(normalizedKeyTimes);
 
     Channel* channel = new Channel(this, target, propertyId, curve, duration);
+    curve->release();
     addChannel(channel);
     return channel;
 }
@@ -337,7 +316,7 @@ Animation::Channel* Animation::createChannel(AnimationTarget* target, int proper
     unsigned int propertyComponentCount = target->getAnimationPropertyComponentCount(propertyId);
     assert(propertyComponentCount > 0);
 
-    Curve* curve = new Curve(keyCount, propertyComponentCount);
+    Curve* curve = Curve::create(keyCount, propertyComponentCount);
     if (target->_targetType == AnimationTarget::TRANSFORM)
         setTransformRotationOffset(curve, propertyId);
     
@@ -364,6 +343,7 @@ Animation::Channel* Animation::createChannel(AnimationTarget* target, int proper
     SAFE_DELETE(normalizedKeyTimes);
 
     Channel* channel = new Channel(this, target, propertyId, curve, duration);
+    curve->release();
     addChannel(channel);
     return channel;
 }

+ 1 - 21
gameplay/src/Animation.h

@@ -96,26 +96,6 @@ public:
 
 private:
 
-    /**
-     * Defines a reference counted Curve wrapper.
-     * 
-     * Multiple channels can share the same Curve.
-     */
-    class CurveRef : public Ref
-    {
-    public:
-        static CurveRef* create(Curve* curve);
-        Curve* getCurve() const;
-
-    private:
-        CurveRef(Curve* curve);
-        CurveRef(const CurveRef&); // Hidden copy constructor.
-        ~CurveRef();
-        CurveRef& operator=(const CurveRef&); // Hidden copy assignment operator.
-
-        Curve* _curve;
-    };
-
     /**
      * Defines a channel which holds the target, target property, curve values, and duration.
      *
@@ -141,7 +121,7 @@ private:
         Animation* _animation;                // Reference to the animation this channel belongs to.
         AnimationTarget* _target;             // The target of this channel.
         int _propertyId;                      // The target property this channel targets.
-        CurveRef* _curveRef;                  // The curve used to represent the animation data.
+        Curve* _curve;                        // The curve used to represent the animation data.
         unsigned long _duration;              // The length of the animation (in milliseconds).
     };
 

+ 3 - 3
gameplay/src/AudioController.cpp

@@ -38,9 +38,9 @@ void AudioController::initialize()
         return;  
     }
         
-	_alcContext = alcCreateContext(_alcDevice, NULL);
+    _alcContext = alcCreateContext(_alcDevice, NULL);
     ALCenum alcErr = alcGetError(_alcDevice);
-	if (!_alcContext || alcErr != ALC_NO_ERROR)
+    if (!_alcContext || alcErr != ALC_NO_ERROR)
     {
         alcCloseDevice (_alcDevice);
         LOG_ERROR_VARG("AudioController::initialize() error. Unable to create OpenAL context. Error: %d\n", alcErr);
@@ -181,7 +181,7 @@ void AudioController::update(long elapsedTime)
             SLresult result = (*_engineEngine)->CreateListener(_engineEngine, &_listenerObject, 2, interfaces, required);
             if (result != SL_RESULT_SUCCESS)
             {
-                WARN("AudioController: failed to create listener.");
+                WARN_VARG("AudioController: failed to create listener (%u).", result);
                 return;
             }
 

+ 2 - 2
gameplay/src/AudioSource.cpp

@@ -466,7 +466,7 @@ void AudioSource::transformChanged(Transform* transform, long cookie)
 #ifndef __ANDROID__
     if (_node)
     {
-    	Vector3 translation = _node->getTranslationWorld();
+        Vector3 translation = _node->getTranslationWorld();
         alSourcefv(_alSource, AL_POSITION, (const ALfloat*)&translation.x);
     }
 #else
@@ -498,7 +498,7 @@ AudioSource* AudioSource::clone(NodeCloneContext &context) const
     AudioSource* audioClone = new AudioSource(_buffer, alSource);
 #else
     // TODO: Implement cloning audio source for Android
-    AudioSource* audioClone = new AudioSource(AudioBuffer* buffer, const SLObjectItf& player);
+    AudioSource* audioClone = new AudioSource(_buffer, _playerObject);
 
 #endif
     _buffer->addRef();

+ 3 - 3
gameplay/src/BoundingBox.cpp

@@ -57,9 +57,9 @@ void BoundingBox::getCorners(Vector3* dst) const
 
 Vector3 BoundingBox::getCenter() const
 {
-	Vector3 center;
-	getCenter(&center);
-	return center;
+    Vector3 center;
+    getCenter(&center);
+    return center;
 }
 
 void BoundingBox::getCenter(Vector3* dst) const

+ 1 - 1
gameplay/src/BoundingBox.h

@@ -53,7 +53,7 @@ public:
      */
     static const BoundingBox& empty();
 
-	/**
+    /**
      * Gets the center point of the bounding box.
      *
      * This method computes the center point of the box from its min and max.

+ 11 - 33
gameplay/src/Camera.cpp

@@ -243,24 +243,13 @@ const Frustum& Camera::getFrustum() const
     return _bounds;
 }
 
-void Camera::project(const Viewport* viewport, const Vector3& position, float* x, float* y, float* depth)
+void Camera::project(const Rectangle& viewport, const Vector3& position, float* x, float* y, float* depth)
 {
     // Determine viewport coords to use.
-    float vpx, vpy, vpw, vph;
-    if (viewport)
-    {
-        vpx = viewport->getX();
-        vpy = viewport->getY();
-        vpw = viewport->getWidth();
-        vph = viewport->getHeight();
-    }
-    else
-    {
-        vpx = 0;
-        vpy = 0;
-        vpw = Game::getInstance()->getWidth();
-        vph = Game::getInstance()->getHeight();
-    }
+    float vpx = viewport.x;
+    float vpy = viewport.y;
+    float vpw = viewport.width;
+    float vph = viewport.height;
 
     // Transform the point to clip-space.
     Vector4 clipPos;
@@ -280,24 +269,13 @@ void Camera::project(const Viewport* viewport, const Vector3& position, float* x
     }
 }
 
-void Camera::unproject(const Viewport* viewport, float x, float y, float depth, Vector3* dst)
+void Camera::unproject(const Rectangle& viewport, float x, float y, float depth, Vector3* dst)
 {
     // Determine viewport coords to use.
-    float vpx, vpy, vpw, vph;
-    if (viewport)
-    {
-        vpx = viewport->getX();
-        vpy = viewport->getY();
-        vpw = viewport->getWidth();
-        vph = viewport->getHeight();
-    }
-    else
-    {
-        vpx = 0;
-        vpy = 0;
-        vpw = Game::getInstance()->getWidth();
-        vph = Game::getInstance()->getHeight();
-    }
+    float vpx = viewport.x;
+    float vpy = viewport.y;
+    float vpw = viewport.width;
+    float vph = viewport.height;
     
     // Create our screen space position in NDC.
     Vector4 screen(
@@ -325,7 +303,7 @@ void Camera::unproject(const Viewport* viewport, float x, float y, float depth,
     dst->set(screen.x, screen.y, screen.z);
 }
 
-void Camera::pickRay(const Viewport* viewport, float x, float y, Ray* dst)
+void Camera::pickRay(const Rectangle& viewport, float x, float y, Ray* dst)
 {
     // Get the world-space position at the near clip plane.
     Vector3 nearPoint;

+ 7 - 7
gameplay/src/Camera.h

@@ -4,7 +4,7 @@
 #include "Ref.h"
 #include "Transform.h"
 #include "Frustum.h"
-#include "Viewport.h"
+#include "Rectangle.h"
 
 namespace gameplay
 {
@@ -197,13 +197,13 @@ public:
     /**
      * Projects the specified world position into the viewport coordinates.
      *
-     * @param viewport The viewport to use, or NULL to use a viewport the size of the window.
+     * @param viewport The viewport rectangle to use.
      * @param position The world space position.
      * @param x The returned viewport x coordinate.
      * @param y The returned viewport y coordinate.
      * @param depth The returned pixel depth (can be NULL).
      */
-    void project(const Viewport* viewport, const Vector3& position, float* x, float* y, float* depth = NULL);
+    void project(const Rectangle& viewport, const Vector3& position, float* x, float* y, float* depth = NULL);
 
     /**
      * Converts a viewport-space coordinate to a world-space position for the given depth value.
@@ -211,23 +211,23 @@ public:
      * The depth parameter is a value ranging between 0 and 1, where 0 returns a point on the
      * near clipping plane and 1 returns a point on the far clipping plane.
      *
-     * @param viewport The viewport to use, or NULL to use a viewport the size of the window.
+     * @param viewport The viewport rectangle to use.
      * @param x The viewport-space x coordinate.
      * @param y The viewport-space y coordinate.
      * @param depth The depth range.
      * @param dst The world space position.
      */
-    void unproject(const Viewport* viewport, float x, float y, float depth, Vector3* dst);
+    void unproject(const Rectangle& viewport, float x, float y, float depth, Vector3* dst);
 
     /**
      * Picks a ray that can be used for picking given the specified viewport-space coordinates.
      *
-     * @param viewport The viewport to use, or NULL to use a viewport the size of the window.
+     * @param viewport The viewport rectangle to use.
      * @param x The viewport x-coordinate.
      * @param y The viewport y-coordinate.
      * @param dst The computed pick ray.
      */
-    void pickRay(const Viewport* viewport, float x, float y, Ray* dst);
+    void pickRay(const Rectangle& viewport, float x, float y, Ray* dst);
 
 private:
 

+ 0 - 2
gameplay/src/Control.cpp

@@ -43,9 +43,7 @@ namespace gameplay
 
         const char* id = properties->getId();
         if (id)
-        {
             _id = id;
-        }
     }
 
     const char* Control::getID() const

+ 5 - 0
gameplay/src/Curve.cpp

@@ -54,6 +54,11 @@ using std::strcmp;
 namespace gameplay
 {
 
+Curve* Curve::create(unsigned int pointCount, unsigned int componentCount)
+{
+    return new Curve(pointCount, componentCount);
+}
+
 Curve::Curve(unsigned int pointCount, unsigned int componentCount)
     : _pointCount(pointCount), _componentCount(componentCount), _componentSize(sizeof(float)*componentCount), _quaternionOffset(NULL), _points(NULL)
 {

+ 25 - 11
gameplay/src/Curve.h

@@ -1,13 +1,15 @@
 #ifndef CURVE_H_
 #define CURVE_H_
 
+#include "Ref.h"
+
 namespace gameplay
 {
 
 /**
  * Represents an n-dimensional curve.
  */
-class Curve
+class Curve : public Ref
 {
     friend class Animation;
     friend class AnimationClip;
@@ -272,19 +274,13 @@ public:
         BOUNCE_OUT_IN
     };
 
-
     /**
-     * Constructs a new curve and the specified parameters.
-     *
+     * Creates a new curve.
+     * 
      * @param pointCount The number of points in the curve.
      * @param componentCount The number of float component values per key value.
      */
-    Curve(unsigned int pointCount, unsigned int componentCount);
-
-    /**
-     * Destructor.
-     */
-    ~Curve();
+    static Curve* create(unsigned int pointCount, unsigned int componentCount);
 
     /**
      * Gets the number of points in the curve.
@@ -396,10 +392,28 @@ private:
     Curve();
 
     /**
-     * Constructor.
+     * Constructs a new curve and the specified parameters.
+     *
+     * @param pointCount The number of points in the curve.
+     * @param componentCount The number of float component values per key value.
+     */
+    Curve(unsigned int pointCount, unsigned int componentCount);
+
+    /**
+     * Hidden copy constructor.
      */
     Curve(const Curve& copy);
 
+    /**
+     * Destructor.
+     */
+    ~Curve();
+
+    /**
+     * Hidden copy assignment operator.
+     */
+    Curve& operator=(const Curve&);
+
     /**
      * Bezier interpolation function.
      */

+ 19 - 19
gameplay/src/FileSystem.cpp

@@ -117,9 +117,9 @@ bool FileSystem::listFiles(const char* dirPath, std::vector<std::string>& files)
 #else
     std::string path(FileSystem::getResourcePath());
     if (dirPath && strlen(dirPath) > 0)
-	{
-		path.append(dirPath);
-	}
+    {
+        path.append(dirPath);
+    }
     path.append("/.");
     struct dirent* dp;
     DIR* dir = opendir(path.c_str());
@@ -127,23 +127,23 @@ bool FileSystem::listFiles(const char* dirPath, std::vector<std::string>& files)
     {
         return false;
     }
-	while ((dp = readdir(dir)) != NULL)
-	{
-		std::string filepath(path);
-		filepath.append("/");
-		filepath.append(dp->d_name);
-
-		struct stat buf;
-		if (!stat(filepath.c_str(), &buf))
-		{
+    while ((dp = readdir(dir)) != NULL)
+    {
+        std::string filepath(path);
+        filepath.append("/");
+        filepath.append(dp->d_name);
+
+        struct stat buf;
+        if (!stat(filepath.c_str(), &buf))
+        {
             // Add to the list if this is not a directory
-			if (!S_ISDIR(buf.st_mode))
-			{
-				files.push_back(dp->d_name);
-			}
-		}
-	}
-	closedir(dir);
+            if (!S_ISDIR(buf.st_mode))
+            {
+                files.push_back(dp->d_name);
+            }
+        }
+    }
+    closedir(dir);
     return true;
 #endif
 }

+ 7 - 4
gameplay/src/Font.h

@@ -149,8 +149,8 @@ public:
      * @param rightToLeft Whether to draw text from right to left.
      * @param clip A region to clip text within after applying justification to the viewport area.
      */
-    void drawText(const char* text, const Rectangle& area, const Vector4& color,
-        unsigned int size = 0, Justify justify = ALIGN_TOP_LEFT, bool wrap = true, bool rightToLeft = false, const Rectangle* clip = NULL);
+    void drawText(const char* text, const Rectangle& area, const Vector4& color, unsigned int size = 0, 
+                  Justify justify = ALIGN_TOP_LEFT, bool wrap = true, bool rightToLeft = false, const Rectangle* clip = NULL);
 
     /**
      * Measures a string's width and height without alignment, wrapping or clipping.
@@ -217,12 +217,14 @@ private:
 
     // Utilities
     unsigned int getTokenWidth(const char* token, unsigned int length, unsigned int size, float scale);
+
     unsigned int getReversedTokenLength(const char* token, const char* bufStart);
 
     // Returns 0 if EOF was reached, 1 if delimiters were handles correctly, and 2 if the stopAtPosition was reached while handling delimiters.
     int handleDelimiters(const char** token, const unsigned int size, const int iteration, const int areaX, int* xPos, int* yPos, unsigned int* lineLength,
-                          std::vector<int>::const_iterator* xPositionsIt, std::vector<int>::const_iterator xPositionsEnd, unsigned int* charIndex = NULL,
-                          const Vector2* stopAtPosition = NULL, const int currentIndex = -1, const int destIndex = -1);
+                         std::vector<int>::const_iterator* xPositionsIt, std::vector<int>::const_iterator xPositionsEnd, unsigned int* charIndex = NULL,
+                         const Vector2* stopAtPosition = NULL, const int currentIndex = -1, const int destIndex = -1);
+
     void addLineInfo(const Rectangle& area, int lineWidth, int lineLength, Justify hAlign,
                      std::vector<int>* xPositions, std::vector<unsigned int>* lineLengths, bool rightToLeft);
 
@@ -235,6 +237,7 @@ private:
     unsigned int _glyphCount;
     Texture* _texture;
     SpriteBatch* _batch;
+    Rectangle _viewport;
 };
 
 }

+ 13 - 13
gameplay/src/Form.cpp

@@ -13,7 +13,7 @@ namespace gameplay
 {
     static std::vector<Form*> __forms;
 
-    Form::Form() : _theme(NULL), _quad(NULL), _node(NULL), _frameBuffer(NULL), _viewport(NULL)
+    Form::Form() : _theme(NULL), _quad(NULL), _node(NULL), _frameBuffer(NULL)
     {
     }
 
@@ -27,7 +27,6 @@ namespace gameplay
         SAFE_RELEASE(_node);
         SAFE_RELEASE(_frameBuffer);
         SAFE_RELEASE(_theme);
-        SAFE_DELETE(_viewport);
 
         // Remove this Form from the global list.
         std::vector<Form*>::iterator it = std::find(__forms.begin(), __forms.end(), this);
@@ -45,9 +44,7 @@ namespace gameplay
         Properties* properties = Properties::create(path);
         assert(properties);
         if (properties == NULL)
-        {
             return NULL;
-        }
 
         // Check if the Properties is valid and has a valid namespace.
         Properties* formProperties = properties->getNextNamespace();
@@ -121,14 +118,14 @@ namespace gameplay
     void Form::setQuad(const Vector3& p1, const Vector3& p2, const Vector3& p3, const Vector3& p4)
     {
         Mesh* mesh = Mesh::createQuad(p1, p2, p3, p4);
-        initQuad(mesh);
+        initializeQuad(mesh);
         SAFE_RELEASE(mesh);
     }
 
     void Form::setQuad(float x, float y, float width, float height)
     {
         Mesh* mesh = Mesh::createQuad(x, y, width, height);
-        initQuad(mesh);
+        initializeQuad(mesh);
         SAFE_RELEASE(mesh);
     }
 
@@ -143,7 +140,6 @@ namespace gameplay
 
             Matrix::createOrthographicOffCenter(0, _size.x, _size.y, 0, 0, 1, &_projectionMatrix);
             _theme->setProjectionMatrix(_projectionMatrix);
-            _viewport = new Viewport(0, 0, _size.x, _size.y);
             
             _node->setModel(_quad);
         }
@@ -171,14 +167,19 @@ namespace gameplay
             if (isDirty())
             {
                 _frameBuffer->bind();
-                _viewport->bind();
+
+                Game* game = Game::getInstance();
+                Rectangle prevViewport = game->getViewport();
+                
+                game->setViewport(Rectangle(_position.x, _position.y, _size.x, _size.y));
 
                 draw(_theme->getSpriteBatch(), _clip);
 
                 // Rebind the default framebuffer and game viewport.
                 FrameBuffer::bindDefault();
-                Game* game = Game::getInstance();
-                GL_ASSERT( glViewport(0, 0, game->getWidth(), game->getHeight()) );
+
+                // restore the previous game viewport
+                game->setViewport(prevViewport);
             }
 
             _quad->draw();
@@ -229,7 +230,7 @@ namespace gameplay
         _dirty = false;
     }
 
-    void Form::initQuad(Mesh* mesh)
+    void Form::initializeQuad(Mesh* mesh)
     {
         // Release current model.
         SAFE_RELEASE(_quad);
@@ -266,7 +267,6 @@ namespace gameplay
         Texture::Sampler* sampler = Texture::Sampler::create(_frameBuffer->getRenderTarget()->getTexture());
         sampler->setWrapMode(Texture::CLAMP, Texture::CLAMP);
         material->getParameter("u_texture")->setValue(sampler);
-
         material->getParameter("u_textureRepeat")->setValue(Vector2::one());
         material->getParameter("u_textureTransform")->setValue(Vector2::zero());
 
@@ -299,7 +299,7 @@ namespace gameplay
 
                         // Unproject point into world space.
                         Ray ray;
-                        camera->pickRay(NULL, x, y, &ray);
+                        camera->pickRay(Game::getInstance()->getViewport(), x, y, &ray);
 
                         // Find the quad's plane.
                         // We know its normal is the quad's forward vector.

+ 5 - 2
gameplay/src/Form.h

@@ -22,6 +22,7 @@ class Form : public Container
     friend class Platform;
 
 public:
+
     /**
      * Create from properties file.
      * The top-most namespace in the file must be named 'form'.  The following properties are available for forms:
@@ -105,7 +106,9 @@ public:
     void draw();
 
 protected:
+    
     Form();
+
     virtual ~Form();
 
     static Form* create(const char* textureFile, Layout::Type type);
@@ -115,7 +118,7 @@ protected:
      *
      * @param mesh The mesh to create a model from.
      */
-    void initQuad(Mesh* mesh);
+    void initializeQuad(Mesh* mesh);
 
     /**
      * Draw this form into the current framebuffer.
@@ -142,9 +145,9 @@ protected:
     Node* _node;                // Node for transforming this Form in world-space.
     FrameBuffer* _frameBuffer;  // FBO the Form is rendered into for texturing the quad.
     Matrix _projectionMatrix;   // Orthographic projection matrix to be set on SpriteBatch objects when rendering into the FBO.
-    Viewport* _viewport;        // Viewport for setting before rendering into the FBO.
 
 private:
+
     Form(const Form& copy);
 };
 

+ 8 - 0
gameplay/src/Game.cpp

@@ -93,6 +93,8 @@ bool Game::startup()
     if (_state != UNINITIALIZED)
         return false;
 
+    setViewport(Rectangle(0.0f, 0.0f, (float)_width, (float)_height));
+
     RenderState::initialize();
 
     _animationController = new AnimationController();
@@ -213,6 +215,12 @@ void Game::frame()
     }
 }
 
+void Game::setViewport(const Rectangle& viewport)
+{
+    _viewport = viewport;
+    glViewport((GLuint)viewport.x, (GLuint)viewport.y, (GLuint)viewport.width, (GLuint)viewport.height); 
+}
+
 void Game::clear(ClearFlags flags, const Vector4& clearColor, float clearDepth, int clearStencil)
 {
     GLbitfield bits = 0;

+ 19 - 44
gameplay/src/Game.h

@@ -10,6 +10,7 @@
 #include "AnimationController.h"
 #include "PhysicsController.h"
 #include "AudioListener.h"
+#include "Rectangle.h"
 #include "Vector4.h"
 #include "TimeListener.h"
 
@@ -151,6 +152,22 @@ public:
      */
     inline unsigned int getHeight() const;
 
+    /**
+     * Gets the game current viewport.
+     *
+     * The default viewport is Rectangle(0, 0, Game::getWidth(), Game::getHeight()).
+     */
+    inline const Rectangle& getViewport() const;
+
+    /**
+     * Set the game current viewport.
+     *
+     * The x, y, width and height of the viewport must all be positive.
+     *
+     * viewport The custom viewport to be set on the game.
+     */
+    void setViewport(const Rectangle& viewport);
+
     /**
      * Clears the specified resource buffers to the specified clear values. 
      *
@@ -385,6 +402,7 @@ private:
     unsigned int _frameRate;                    // The current frame rate.
     unsigned int _width;                        // The game's display width.
     unsigned int _height;                       // The game's display height.
+    Rectangle _viewport;                        // the games's current viewport.
     Vector4 _clearColor;                        // The clear color value last used for clearing the color buffer.
     float _clearDepth;                          // The clear depth value last used for clearing the depth buffer.
     int _clearStencil;                          // The clear stencil value last used for clearing the stencil buffer.
@@ -396,52 +414,9 @@ private:
 
     // Note: Do not add STL object member variables on the stack; this will cause false memory leaks to be reported.
 
-    friend class SplashDisplayer;
+    friend class ScreenDisplayer;
 };
 
-/**
- * Used for displaying splash screens.
- */
-class SplashDisplayer
-{
-public:
-
-    /**
-     * Displays a splash screen using the {@link Game#renderOnce} mechanism for at least the given amount of time.
-     * 
-     * @param instance See {@link Game#renderOnce}.
-     * @param method See {@link Game#renderOnce}.
-     * @param cookie See {@link Game#renderOnce}.
-     * @param time The minimum amount of time to display the splash screen (in milliseconds).
-     */
-    template <typename T> void run(T* instance, void (T::*method) (void*), void* cookie, long time);
-
-    /**
-     * Destructor.
-     */
-    ~SplashDisplayer();
-
-private:
-
-    long _time;
-    long _startTime;
-};
-
-/**
- * Displays a splash screen using the {@link Game#renderOnce} mechanism for at least the given amount
- * of time. This function is intended to be called at the beginning of a block of code that is be 
- * executed while the splash screen is displayed (i.e. Game#initialize). This function will block 
- * at the end of the block of code in which it is called for the amount of time that has not yet elapsed.
- * 
- * @param instance See {@link Game#renderOnce}.
- * @param method See {@link Game#renderOnce}.
- * @param cookie See {@link Game#renderOnce}.
- * @param time The minimum amount of time to display the splash screen (in milliseconds).
- */
-#define displaySplash(instance, method, cookie, time) \
-    SplashDisplayer __##instance##SplashDisplayer; \
-    __##instance##SplashDisplayer.run(instance, method, cookie, time)
-
 }
 
 #include "Game.inl"

+ 5 - 14
gameplay/src/Game.inl

@@ -24,6 +24,11 @@ inline unsigned int Game::getHeight() const
     return _height;
 }
 
+inline const Rectangle& Game::getViewport() const
+{
+    return _viewport;
+}
+
 inline AnimationController* Game::getAnimationController() const
 {
     return _animationController;
@@ -66,18 +71,4 @@ inline void Game::displayKeyboard(bool display)
     Platform::displayKeyboard(display);
 }
 
-template <typename T> void SplashDisplayer::run(T* instance, void (T::*method) (void*), void* cookie, long time)
-{
-    _time = time;
-    Game::getInstance()->renderOnce(instance, method, cookie);
-    _startTime = Game::getInstance()->getGameTime();
-}
-
-inline SplashDisplayer::~SplashDisplayer()
-{
-    long elapsedTime = Game::getInstance()->getGameTime() - _startTime;
-    if (elapsedTime < _time)
-        Platform::sleep(_time - (Game::getInstance()->getGameTime() - _startTime));
-}
-
 }

+ 93 - 24
gameplay/src/Node.cpp

@@ -7,17 +7,22 @@
 #include "PhysicsCharacter.h"
 #include "Game.h"
 
+// Node dirty flags
 #define NODE_DIRTY_WORLD 1
 #define NODE_DIRTY_BOUNDS 2
 #define NODE_DIRTY_ALL (NODE_DIRTY_WORLD | NODE_DIRTY_BOUNDS)
 
+// Node property flags
+#define NODE_FLAG_VISIBLE 1
+#define NODE_FLAG_TRANSPARENT 2
+
 namespace gameplay
 {
 
 Node::Node(const char* id)
     : _scene(NULL), _firstChild(NULL), _nextSibling(NULL), _prevSibling(NULL), _parent(NULL), _childCount(NULL),
-    _camera(NULL), _light(NULL), _model(NULL), _form(NULL), _audioSource(NULL), _particleEmitter(NULL),
-	_collisionObject(NULL), _dirtyBits(NODE_DIRTY_ALL), _notifyHierarchyChanged(true)
+    _nodeFlags(NODE_FLAG_VISIBLE), _camera(NULL), _light(NULL), _model(NULL), _form(NULL), _audioSource(NULL), _particleEmitter(NULL),
+    _collisionObject(NULL), _dirtyBits(NODE_DIRTY_ALL), _notifyHierarchyChanged(true), _userData(NULL)
 {
     if (id)
     {
@@ -45,6 +50,15 @@ Node::~Node()
     SAFE_RELEASE(_particleEmitter);
     SAFE_RELEASE(_form);
     SAFE_DELETE(_collisionObject);
+
+    // Cleanup user data
+    if (_userData)
+    {
+        // Call custom cleanup callback if specified
+        if (_userData->cleanupCallback)
+            _userData->cleanupCallback(_userData->pointer);
+        SAFE_DELETE(_userData);
+    }
 }
 
 Node* Node::create(const char* id)
@@ -195,6 +209,61 @@ Node* Node::getParent() const
     return _parent;
 }
 
+bool Node::isVisible() const
+{
+    return ((_nodeFlags & NODE_FLAG_VISIBLE) == NODE_FLAG_VISIBLE);
+}
+
+void Node::setVisible(bool visible)
+{
+    if (visible)
+        _nodeFlags |= NODE_FLAG_VISIBLE;
+    else
+        _nodeFlags &= ~NODE_FLAG_VISIBLE;
+}
+
+bool Node::isTransparent() const
+{
+    return ((_nodeFlags & NODE_FLAG_TRANSPARENT) == NODE_FLAG_TRANSPARENT);
+}
+
+void Node::setTransparent(bool transparent)
+{
+    if (transparent)
+        _nodeFlags |= NODE_FLAG_TRANSPARENT;
+    else
+        _nodeFlags &= ~NODE_FLAG_TRANSPARENT;
+}
+
+void* Node::getUserPointer() const
+{
+    return (_userData ? _userData->pointer : NULL);
+}
+
+void Node::setUserPointer(void* pointer, void (*cleanupCallback)(void*))
+{
+    // If existing user pointer is being changed, call cleanup function to free previous pointer
+    if (_userData && _userData->pointer && _userData->cleanupCallback && pointer != _userData->pointer)
+    {
+        _userData->cleanupCallback(_userData->pointer);
+    }
+
+    if (pointer)
+    {
+        // Assign user pointer
+        if (_userData == NULL)
+            _userData = new UserData();
+
+        _userData->pointer = pointer;
+        _userData->cleanupCallback = cleanupCallback;
+    }
+    else
+    {
+        // Clear user pointer
+        SAFE_DELETE(_userData);
+    }
+}
+
 unsigned int Node::getChildCount() const
 {
     return _childCount;
@@ -294,7 +363,7 @@ const Matrix& Node::getWorldMatrix() const
         // If we have a parent, multiply our parent world transform by our local
         // transform to obtain our final resolved world transform.
         Node* parent = getParent();
-		if (parent && (!_collisionObject || _collisionObject->isKinematic()))
+        if (parent && (!_collisionObject || _collisionObject->isKinematic()))
         {
             Matrix::multiply(parent->getWorldMatrix(), getMatrix(), &_world);
         }
@@ -822,30 +891,30 @@ PhysicsCollisionObject* Node::getCollisionObject() const
 
 PhysicsCollisionObject* Node::setCollisionObject(PhysicsCollisionObject::Type type, const PhysicsCollisionShape::Definition& shape, PhysicsRigidBody::Parameters* rigidBodyParameters)
 {
-	SAFE_DELETE(_collisionObject);
+    SAFE_DELETE(_collisionObject);
 
-	switch (type)
-	{
-	case PhysicsCollisionObject::RIGID_BODY:
-		{
-			_collisionObject = new PhysicsRigidBody(this, shape, rigidBodyParameters ? *rigidBodyParameters : PhysicsRigidBody::Parameters());
-		}
-		break;
+    switch (type)
+    {
+    case PhysicsCollisionObject::RIGID_BODY:
+        {
+            _collisionObject = new PhysicsRigidBody(this, shape, rigidBodyParameters ? *rigidBodyParameters : PhysicsRigidBody::Parameters());
+        }
+        break;
 
-	case PhysicsCollisionObject::GHOST_OBJECT:
-		{
-			_collisionObject = new PhysicsGhostObject(this, shape);
-		}
-		break;
+    case PhysicsCollisionObject::GHOST_OBJECT:
+        {
+            _collisionObject = new PhysicsGhostObject(this, shape);
+        }
+        break;
 
-	case PhysicsCollisionObject::CHARACTER:
-		{
-			_collisionObject = new PhysicsCharacter(this, shape);
-		}
-		break;
-	}
+    case PhysicsCollisionObject::CHARACTER:
+        {
+            _collisionObject = new PhysicsCharacter(this, shape, rigidBodyParameters ? rigidBodyParameters->mass : 1.0f);
+        }
+        break;
+    }
 
-	return _collisionObject;
+    return _collisionObject;
 }
 
 PhysicsCollisionObject* Node::setCollisionObject(const char* filePath)
@@ -891,7 +960,7 @@ PhysicsCollisionObject* Node::setCollisionObject(Properties* properties)
     {
         _collisionObject = PhysicsRigidBody::create(this, properties);
     }
-	return _collisionObject;
+    return _collisionObject;
 }
 
 NodeCloneContext::NodeCloneContext()

+ 122 - 49
gameplay/src/Node.h

@@ -113,6 +113,70 @@ public:
      */
     Node* getParent() const;
 
+    /**
+     * Returns whether this node is visible (true by default).
+     *
+     * @return Whether the node is visible.
+     */
+    bool isVisible() const;
+
+    /**
+     * Sets whether this node is visible.
+     *
+     * @return Whether this node is visible.
+     */
+    void setVisible(bool visible);
+
+    /**
+     * Returns whether this node is transparent (false by default).
+     *
+     * All nodes are opaque by default, unless otherwise set as
+     * transparent using the setTransparent method. These methods
+     * can be used to flag nodes as transparent and then query the
+     * property during game execution, for example to render all
+     * opaque objects first, followed by transparent objects with
+     * alpha blending enabled.
+     *
+     * @return Whether the node is transparent.
+     */
+    bool isTransparent() const;
+
+    /**
+     * Sets whether this node is transparent.
+     *
+     * @param transparent Whether the node is transparent.
+     */
+    void setTransparent(bool transparent);
+
+    /**
+     * Returns the user pointer for this node.
+     *
+     * @return The user pointer for this node.
+     * @see setUserPointer(void*)
+     */
+    void* getUserPointer() const;
+
+    /**
+     * Sets the user pointer for this node.
+     *
+     * The user pointer is initially NULL and can be set to anything.
+     * This is normally used to store game-specific data, such as 
+     * game state for a particular node.  For example, attributes
+     * for a game character, such as hit points, stamina, etc can
+     * be defined in a game structure and stored in this field.
+     *
+     * When a node is deleted, the (optional) cleanup callback
+     * function passed to this function is called to allow the 
+     * user to free any memory associated with the user pointer.
+     *
+     * @param pointer User pointer.
+     * @param cleanupCallback Optional callback that is called when the
+     *      Node is being destroyed (or when the user pointer changes),
+     *      to allow the user to cleanup any memory associated with the
+     *      user pointer.
+     */
+    void setUserPointer(void* pointer, void (*cleanupCallback)(void*) = NULL);
+
     /**
      * Returns the number of direct children of this item.
      *
@@ -367,59 +431,59 @@ public:
      */
     void setParticleEmitter(ParticleEmitter* emitter);
 
-	/**
-	 * Returns the pointer to this node's physics collision object.
-	 *
-	 * The type of the returned collision object can be queried using
-	 * the PhysicsCollisionObject::getType() method.
-	 *
-	 * @return The pointer to this node's physics collision object.
-	 */
-	PhysicsCollisionObject* getCollisionObject() const;
-
-	/**
-	 * Sets (or disables) the physics collision object for this node.
-	 *
-	 * The supported collision object types include rigid bodies, ghost objects and 
-	 * characters.
-	 *
-	 * Rigid bodies are used to represent most physical objects in a game. The important
-	 * feature of rigid bodies is that they can be simulated by the physics system as other
-	 * rigid bodies or collision objects collide with them. To support this physics simulation,
-	 * rigid bodies require additional parameters, such as mass, friction and restitution to
-	 * define their physical features. These parameters can be passed into the
-	 * 'rigidBodyParameters' parameter.
-	 *
-	 * Ghost objects are a simple type of collision object that are not simulated. By default
-	 * they pass through other objects in the scene without affecting them. Ghost objects do
-	 * receive collision events however, which makes them useful for representing non-simulated
-	 * entities in a game that still require collision events, such as volumetric triggers, 
-	 * power-ups, etc.
-	 *
-	 * Characters are an extention of ghost objects which provide a number of additional features
-	 * for animating and moving characters within a game. Characters are represented as ghost
-	 * objects instead of rigid bodies to allow more direct control over character movement,
-	 * since attempting to model a physics character with a simulated rigid body usually results
-	 * in unresponse and unpredictable character movement. Unlike normal ghost objects,
-	 * characters to react to other characters and rigid bodies in the world. Characters react
-	 * to gravity and collide (and respond) with rigid bodies to allow them to walk on the ground,
-	 * slide along walls and walk up/down slopes and stairs.
-	 *
-	 * @param type The type of the collision object to set; to disable the physics
-	 *		collision object, pass PhysicsCollisionObject::NONE.
-	 * @param shape Definition of a physics collision shape to be used for this collision object.
-	 *		Use the static shape methods on the PhysicsCollisionShape class to specificy a shape
-	 *		definition, such as PhysicsCollisionShape::box().
-	 * @param rigidBodyParameters If type is PhysicsCollisionObject::RIGID_BODY, this
-	 *		must point to a valid rigid body parameters object containing information
-	 *		about the rigid body; otherwise, this parmater may be NULL.
-	 */
-	PhysicsCollisionObject* setCollisionObject(PhysicsCollisionObject::Type type, const PhysicsCollisionShape::Definition& shape, PhysicsRigidBody::Parameters* rigidBodyParameters = NULL);
+    /**
+     * Returns the pointer to this node's physics collision object.
+     *
+     * The type of the returned collision object can be queried using
+     * the PhysicsCollisionObject::getType() method.
+     *
+     * @return The pointer to this node's physics collision object.
+     */
+    PhysicsCollisionObject* getCollisionObject() const;
+
+    /**
+     * Sets (or disables) the physics collision object for this node.
+     *
+     * The supported collision object types include rigid bodies, ghost objects and 
+     * characters.
+     *
+     * Rigid bodies are used to represent most physical objects in a game. The important
+     * feature of rigid bodies is that they can be simulated by the physics system as other
+     * rigid bodies or collision objects collide with them. To support this physics simulation,
+     * rigid bodies require additional parameters, such as mass, friction and restitution to
+     * define their physical features. These parameters can be passed into the
+     * 'rigidBodyParameters' parameter.
+     *
+     * Ghost objects are a simple type of collision object that are not simulated. By default
+     * they pass through other objects in the scene without affecting them. Ghost objects do
+     * receive collision events however, which makes them useful for representing non-simulated
+     * entities in a game that still require collision events, such as volumetric triggers, 
+     * power-ups, etc.
+     *
+     * Characters are an extention of ghost objects which provide a number of additional features
+     * for animating and moving characters within a game. Characters are represented as ghost
+     * objects instead of rigid bodies to allow more direct control over character movement,
+     * since attempting to model a physics character with a simulated rigid body usually results
+     * in unresponse and unpredictable character movement. Unlike normal ghost objects,
+     * characters to react to other characters and rigid bodies in the world. Characters react
+     * to gravity and collide (and respond) with rigid bodies to allow them to walk on the ground,
+     * slide along walls and walk up/down slopes and stairs.
+     *
+     * @param type The type of the collision object to set; to disable the physics
+     *        collision object, pass PhysicsCollisionObject::NONE.
+     * @param shape Definition of a physics collision shape to be used for this collision object.
+     *        Use the static shape methods on the PhysicsCollisionShape class to specificy a shape
+     *        definition, such as PhysicsCollisionShape::box().
+     * @param rigidBodyParameters If type is PhysicsCollisionObject::RIGID_BODY, this
+     *        must point to a valid rigid body parameters object containing information
+     *        about the rigid body; otherwise, this parmater may be NULL.
+     */
+    PhysicsCollisionObject* setCollisionObject(PhysicsCollisionObject::Type type, const PhysicsCollisionShape::Definition& shape, PhysicsRigidBody::Parameters* rigidBodyParameters = NULL);
 
     /**
      * Sets the physics collision object for this node using the definition in the given file.
      * 
-     * @param filePath The path to the file that contains the collision object definition.
+     * @param filePath The path to the file that set the collision object definition.
      */
     PhysicsCollisionObject* setCollisionObject(const char* filePath);
 
@@ -530,6 +594,13 @@ private:
 
 protected:
 
+    struct UserData
+    {
+        UserData() : pointer(NULL), cleanupCallback(NULL) {}
+        void* pointer;
+        void (*cleanupCallback)(void*);
+    };
+
     Scene* _scene;
     std::string _id;
     Node* _firstChild;
@@ -537,6 +608,7 @@ protected:
     Node* _prevSibling;
     Node* _parent;
     unsigned int _childCount;
+    unsigned int _nodeFlags;
     Camera* _camera;
     Light* _light;
     Model* _model;
@@ -548,6 +620,7 @@ protected:
     mutable int _dirtyBits;
     bool _notifyHierarchyChanged;
     mutable BoundingSphere _bounds;
+    UserData* _userData;
 };
 
 /**

+ 1 - 1
gameplay/src/ParticleEmitter.cpp

@@ -50,7 +50,7 @@ ParticleEmitter* ParticleEmitter::create(const char* textureFile, TextureBlendin
     Texture* texture = NULL;
     texture = Texture::create(textureFile, true);    
 
-	if (!texture)
+    if (!texture)
     {
         LOG_ERROR_VARG("Error creating ParticleEmitter: Could not read texture file: %s", textureFile);
         return NULL;

+ 184 - 193
gameplay/src/PhysicsCharacter.cpp

@@ -10,16 +10,6 @@
 #include "Game.h"
 #include "PhysicsController.h"
 
-// Amount to walk collision normal when attempting to repair a collision.
-// To small a value will result in inefficient collision repairs (several iterations
-// to fix a collision and slow resolution), whereas larger values will result
-// in less accurate collision resolution.
-//#define COLLISION_REPAIR_INCREMENT 0.2f
-#define COLLISION_REPAIR_MARGIN 1.0f
-
-// Maximum number of iterations used to perform perform collision repair each update.
-#define COLLISION_REPAIR_MAX_ITERATIONS 4
-
 namespace gameplay
 {
 
@@ -27,49 +17,51 @@ class ClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexR
 {
 public:
 
-	ClosestNotMeConvexResultCallback(btCollisionObject* me, const btVector3& up, btScalar minSlopeDot)
+    ClosestNotMeConvexResultCallback(btCollisionObject* me, const btVector3& up, btScalar minSlopeDot)
         : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)), _me(me), _up(up), _minSlopeDot(minSlopeDot)
-	{
-	}
-
-	btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult, bool normalInWorldSpace)
-	{
-		if (convexResult.m_hitCollisionObject == _me)
-			return btScalar(1.0);
-
-		btVector3 hitNormalWorld;
-		if (normalInWorldSpace)
-		{
-			hitNormalWorld = convexResult.m_hitNormalLocal;
-		} else
-		{
-			// transform normal into worldspace
-			hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal;
-		}
-
-		btScalar dotUp = _up.dot(hitNormalWorld);
-		if (dotUp < _minSlopeDot)
+    {
+    }
+
+    btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult, bool normalInWorldSpace)
+    {
+        if (convexResult.m_hitCollisionObject == _me)
+            return btScalar(1.0);
+
+        /*
+        btVector3 hitNormalWorld;
+        if (normalInWorldSpace)
         {
-			return btScalar(1.0);
-		}
+            hitNormalWorld = convexResult.m_hitNormalLocal;
+        } else
+        {
+            // transform normal into worldspace
+            hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal;
+        }
 
-		return ClosestConvexResultCallback::addSingleResult (convexResult, normalInWorldSpace);
-	}
+        btScalar dotUp = _up.dot(hitNormalWorld);
+        if (dotUp < _minSlopeDot)
+        {
+            return btScalar(1.0);
+        }
+        */
+
+        return ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace);
+    }
 
 protected:
 
-	btCollisionObject* _me;
-	const btVector3 _up;
-	btScalar _minSlopeDot;
+    btCollisionObject* _me;
+    const btVector3 _up;
+    btScalar _minSlopeDot;
 };
 
-PhysicsCharacter::PhysicsCharacter(Node* node, const PhysicsCollisionShape::Definition& shape)
+PhysicsCharacter::PhysicsCharacter(Node* node, const PhysicsCollisionShape::Definition& shape, float mass)
     : PhysicsGhostObject(node, shape), _moveVelocity(0,0,0), _forwardVelocity(0.0f), _rightVelocity(0.0f),
     _fallVelocity(0, 0, 0), _currentVelocity(0,0,0), _normalizedVelocity(0,0,0),
     _colliding(false), _collisionNormal(0,0,0), _currentPosition(0,0,0),
-    _stepHeight(0.2f), _slopeAngle(0.0f), _cosSlopeAngle(0.0f), _physicsEnabled(true)
+    _stepHeight(0.1f), _slopeAngle(0.0f), _cosSlopeAngle(0.0f), _physicsEnabled(true), _mass(mass)
 {
-	setMaxSlopeAngle(45.0f);
+    setMaxSlopeAngle(45.0f);
 
     // Set the collision flags on the ghost object to indicate it's a character
     _ghostObject->setCollisionFlags(_ghostObject->getCollisionFlags() | btCollisionObject::CF_CHARACTER_OBJECT);
@@ -102,8 +94,20 @@ PhysicsCharacter* PhysicsCharacter::create(Node* node, Properties* properties)
         return NULL;
     }
 
+    // Load the character's parameters.
+    properties->rewind();
+    float mass = 1.0f;
+    const char* name = NULL;
+    while ((name = properties->getNextProperty()) != NULL)
+    {
+        if (strcmp(name, "mass") == 0)
+        {
+            mass = properties->getFloat();
+        }
+    }
+
     // Create the physics character.
-    PhysicsCharacter* character = new PhysicsCharacter(node, *shape);
+    PhysicsCharacter* character = new PhysicsCharacter(node, *shape, mass);
     SAFE_DELETE(shape);
 
     return character;
@@ -288,6 +292,7 @@ void PhysicsCharacter::setRotation(const Quaternion& rotation)
 {
     _node->setRotation(rotation);
 }
+
 void PhysicsCharacter::setForwardVelocity(float velocity)
 {
     _forwardVelocity = velocity;
@@ -361,27 +366,23 @@ void PhysicsCharacter::updateAction(btCollisionWorld* collisionWorld, btScalar d
     if (_physicsEnabled)
     {
         //_colliding = fixCollision(collisionWorld);
-        /*_colliding = false;
+        _colliding = false;
         int stepCount = 0;
-	    while (fixCollision(collisionWorld))
-	    {
+        while (fixCollision(collisionWorld))
+        {
             _colliding = true;
 
-            // After a small number of attempts to fix a collision/penetration, give up.
-            // This hanldes the case where we are deeply penetrating some object and attempting
-            // to step out of it (by COLLISION_REPAIR_INCREMENT units) does not fix the collision.
-            if (++stepCount > COLLISION_REPAIR_MAX_ITERATIONS)
-		    {
-                WARN_VARG("Character '%s' could not recover from collision.", _node->getId());
-			    break;
-		    }
-	    }*/
+            if (++stepCount > 4)
+            {
+                // Most likely we are wedged between a number of different collision objects
+                break;
+            }
+        }
     }
 
     // Update current and target world positions
-	Vector3 startPosition;
-	_node->getWorldMatrix().getTranslation(&startPosition);
-    _currentPosition = BV(startPosition);
+    btVector3 startPosition = _ghostObject->getWorldTransform().getOrigin();
+    _currentPosition = startPosition;
 
     // Process movement in the up direction
     if (_physicsEnabled)
@@ -391,11 +392,12 @@ void PhysicsCharacter::updateAction(btCollisionWorld* collisionWorld, btScalar d
     stepForwardAndStrafe(collisionWorld, deltaTimeStep);
 
     // Process movement in the down direction
-	if (_physicsEnabled)
-		stepDown(collisionWorld, deltaTimeStep);
+    if (_physicsEnabled)
+        stepDown(collisionWorld, deltaTimeStep);
 
     // Set new position
-	_node->translate(Vector3(_currentPosition.x(), _currentPosition.y(), _currentPosition.z()) - startPosition);
+    btVector3 translation = _currentPosition - startPosition;
+    _node->translate(translation.x(), translation.y(), translation.z());
 }
 
 void PhysicsCharacter::stepUp(btCollisionWorld* collisionWorld, btScalar time)
@@ -408,6 +410,7 @@ void PhysicsCharacter::stepUp(btCollisionWorld* collisionWorld, btScalar time)
     // 
     // Note that stepDown() will be called right after this, so the character will move back
     // down to collide with the ground so that he smoothly steps up stairs.
+    _currentPosition += btVector3(0, _stepHeight, 0);
 }
 
 void PhysicsCharacter::stepForwardAndStrafe(btCollisionWorld* collisionWorld, float time)
@@ -457,7 +460,7 @@ void PhysicsCharacter::stepForwardAndStrafe(btCollisionWorld* collisionWorld, fl
     {
         // No velocity, so we aren't moving
         return;
-	}
+    }
 
     // Translate the target position by the velocity vector (already scaled by t)
     btVector3 targetPosition = _currentPosition + velocity;
@@ -470,59 +473,61 @@ void PhysicsCharacter::stepForwardAndStrafe(btCollisionWorld* collisionWorld, fl
     }
 
     // Check for collisions by performing a bullet convex sweep test
-    btTransform start = _ghostObject->getWorldTransform();
-	btTransform end = _ghostObject->getWorldTransform();
+    btTransform start;
+    btTransform end;
+    start.setIdentity();
+    end.setIdentity();
 
-	btScalar fraction = 1.0;
-	btScalar distance2;
+    btScalar fraction = 1.0;
+    btScalar distance2;
 
-	if (_colliding && (_normalizedVelocity.dot(_collisionNormal) > btScalar(0.0)))
-	{
+    if (_colliding && (_normalizedVelocity.dot(_collisionNormal) > btScalar(0.0)))
+    {
         updateTargetPositionFromCollision(targetPosition, _collisionNormal);
-	}
- 
-	int maxIter = 10;
+    }
 
-	while (fraction > btScalar(0.01) && maxIter-- > 0)
-	{
-		start.setOrigin(_currentPosition);
-		end.setOrigin(targetPosition);
-		btVector3 sweepDirNegative(_currentPosition - targetPosition);
+    int maxIter = 10;
 
-		ClosestNotMeConvexResultCallback callback(_ghostObject, sweepDirNegative, btScalar(0.0));
-		callback.m_collisionFilterGroup = _ghostObject->getBroadphaseHandle()->m_collisionFilterGroup;
-		callback.m_collisionFilterMask = _ghostObject->getBroadphaseHandle()->m_collisionFilterMask;
-		//callback.m_collisionFilterGroup = btBroadphaseProxy::CharacterFilter;
-		//callback.m_collisionFilterMask = btBroadphaseProxy::StaticFilter | btBroadphaseProxy::CharacterFilter | btBroadphaseProxy::DefaultFilter;
+    while (fraction > btScalar(0.01) && maxIter-- > 0)
+    {
+        start.setOrigin(_currentPosition);
+        end.setOrigin(targetPosition);
 
-		_ghostObject->convexSweepTest(static_cast<btConvexShape*>(_collisionShape->getShape()), start, end, callback, 0.0f);//collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
+        btVector3 sweepDirNegative(_currentPosition - targetPosition);
 
-		fraction -= callback.m_closestHitFraction;
+        ClosestNotMeConvexResultCallback callback(_ghostObject, sweepDirNegative, btScalar(0.0));
+        callback.m_collisionFilterGroup = _ghostObject->getBroadphaseHandle()->m_collisionFilterGroup;
+        callback.m_collisionFilterMask = _ghostObject->getBroadphaseHandle()->m_collisionFilterMask;
 
-		if (callback.hasHit())
+        _ghostObject->convexSweepTest(static_cast<btConvexShape*>(_collisionShape->getShape()), start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
+
+        fraction -= callback.m_closestHitFraction;
+
+        if (callback.hasHit())
         {
-			/*Vector3 normal(callback.m_hitNormalWorld.x(), callback.m_hitNormalWorld.y(), callback.m_hitNormalWorld.z());
-			PhysicsCollisionObject* o = Game::getInstance()->getPhysicsController()->getCollisionObject(callback.m_hitCollisionObject);
-			if (o->getType() == PhysicsCollisionObject::RIGID_BODY && o->isDynamic())
-			{
-				PhysicsRigidBody* rb = static_cast<PhysicsRigidBody*>(o);
-				normal.normalize();
-				rb->applyImpulse(-normal);
-			}*/
-
-			updateTargetPositionFromCollision(targetPosition, callback.m_hitNormalWorld);
-			btVector3 currentDir = targetPosition - _currentPosition;
-			distance2 = currentDir.length2();
-			if (distance2 > FLT_EPSILON)
-			{
-				currentDir.normalize();
-
-				// If velocity is against original velocity, stop to avoid tiny oscilations in sloping corners.
-				if (currentDir.dot(_normalizedVelocity) <= btScalar(0.0))
-				{
-					break;
-				}
-			}
+            Vector3 normal(callback.m_hitNormalWorld.x(), callback.m_hitNormalWorld.y(), callback.m_hitNormalWorld.z());
+            PhysicsCollisionObject* o = Game::getInstance()->getPhysicsController()->getCollisionObject(callback.m_hitCollisionObject);
+            if (o->getType() == PhysicsCollisionObject::RIGID_BODY && o->isDynamic())
+            {
+                PhysicsRigidBody* rb = static_cast<PhysicsRigidBody*>(o);
+                normal.normalize();
+                rb->applyImpulse(_mass * -normal * velocity.length());
+            }
+
+            updateTargetPositionFromCollision(targetPosition, callback.m_hitNormalWorld);
+
+            btVector3 currentDir = targetPosition - _currentPosition;
+            distance2 = currentDir.length2();
+            if (distance2 > FLT_EPSILON)
+            {
+                currentDir.normalize();
+
+                // If velocity is against original velocity, stop to avoid tiny oscilations in sloping corners.
+                if (currentDir.dot(_normalizedVelocity) <= btScalar(0.0))
+                {
+                    break;
+                }
+            }
         }
         else
         {
@@ -536,46 +541,40 @@ void PhysicsCharacter::stepForwardAndStrafe(btCollisionWorld* collisionWorld, fl
 
 void PhysicsCharacter::stepDown(btCollisionWorld* collisionWorld, btScalar time)
 {
-    // Contribute gravity to fall velocity.
-    // TODO: This simple formula assumes no air friction, which is completely unrealistic
-    // (characters fall way too fast). We should consider how to support this without much
-    // added complexity.
+    // Contribute basic gravity to fall velocity.
     btVector3 gravity = Game::getInstance()->getPhysicsController()->_world->getGravity();
     _fallVelocity += (gravity * time);
 
-    btVector3 targetPosition = _currentPosition + _fallVelocity;
+    btVector3 targetPosition = _currentPosition + (_fallVelocity * time);
+    targetPosition -= btVector3(0, _stepHeight, 0);
 
     // Perform a convex sweep test between current and target position
-	btTransform start = _ghostObject->getWorldTransform();
-	btTransform end = _ghostObject->getWorldTransform();
+    btTransform start;
+    btTransform end;
+    start.setIdentity();
+    end.setIdentity();
     start.setOrigin(_currentPosition);
     end.setOrigin(targetPosition);
 
-    // TODO: We probably have to perform sweep tests separately in stepForward and stepDown (and stepUp) since
-    // combining the full move into a single targetPosition and computing sweep test between currentPosition and targetPosition
-    // is ALYWAYS going to result in a collision at almost exactly currentPosition... this is because, when you are already
-    // on the floor and applying gravity, 
     ClosestNotMeConvexResultCallback callback(_ghostObject, btVector3(0, 1, 0), _cosSlopeAngle);
-	callback.m_collisionFilterGroup = _ghostObject->getBroadphaseHandle()->m_collisionFilterGroup;
-	callback.m_collisionFilterMask = _ghostObject->getBroadphaseHandle()->m_collisionFilterMask;
-	//callback.m_collisionFilterGroup = btBroadphaseProxy::CharacterFilter;
-	//callback.m_collisionFilterMask = btBroadphaseProxy::StaticFilter | btBroadphaseProxy::CharacterFilter | btBroadphaseProxy::DefaultFilter;
+    callback.m_collisionFilterGroup = _ghostObject->getBroadphaseHandle()->m_collisionFilterGroup;
+    callback.m_collisionFilterMask = _ghostObject->getBroadphaseHandle()->m_collisionFilterMask;
 
-	_ghostObject->convexSweepTest(static_cast<btConvexShape*>(_collisionShape->getShape()), start, end, callback, 0.0f);//collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
+    _ghostObject->convexSweepTest(static_cast<btConvexShape*>(_collisionShape->getShape()), start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
 
-	if (callback.hasHit())
-	{
+    if (callback.hasHit())
+    {
         // Collision detected, fix it
-		_currentPosition.setInterpolate3(_currentPosition, targetPosition, callback.m_closestHitFraction);
+        _currentPosition.setInterpolate3(_currentPosition, targetPosition, callback.m_closestHitFraction);
 
         // Zero out fall velocity when we hit an object
         _fallVelocity.setZero();
-	}
+    }
     else
     {
         // We can move here
         _currentPosition = targetPosition;
-	}
+    }
 }
 
 /*
@@ -583,7 +582,7 @@ void PhysicsCharacter::stepDown(btCollisionWorld* collisionWorld, btScalar time)
  */
 btVector3 computeReflectionDirection(const btVector3& direction, const btVector3& normal)
 {
-	return direction - (btScalar(2.0) * direction.dot(normal)) * normal;
+    return direction - (btScalar(2.0) * direction.dot(normal)) * normal;
 }
 
 /*
@@ -591,8 +590,8 @@ btVector3 computeReflectionDirection(const btVector3& direction, const btVector3
  */
 btVector3 parallelComponent(const btVector3& direction, const btVector3& normal)
 {
-	btScalar magnitude = direction.dot(normal);
-	return normal * magnitude;
+    btScalar magnitude = direction.dot(normal);
+    return normal * magnitude;
 }
 
 /*
@@ -600,108 +599,100 @@ btVector3 parallelComponent(const btVector3& direction, const btVector3& normal)
  */
 btVector3 perpindicularComponent(const btVector3& direction, const btVector3& normal)
 {
-	return direction - parallelComponent(direction, normal);
+    return direction - parallelComponent(direction, normal);
 }
 
 void PhysicsCharacter::updateTargetPositionFromCollision(btVector3& targetPosition, const btVector3& collisionNormal)
 {
-    //btScalar tangentMag = 0.0;
-    //btScalar normalMag = 1.0;
-
-	btVector3 movementDirection = targetPosition - _currentPosition;
-	btScalar movementLength = movementDirection.length();
-
-	if (movementLength > FLT_EPSILON)
-	{
-		movementDirection.normalize();
+    btVector3 movementDirection = targetPosition - _currentPosition;
+    btScalar movementLength = movementDirection.length();
 
-		btVector3 reflectDir = computeReflectionDirection(movementDirection, collisionNormal);
-		reflectDir.normalize();
+    if (movementLength > FLT_EPSILON)
+    {
+        movementDirection.normalize();
 
-		//btVector3 parallelDir = parallelComponent(reflectDir, collisionNormal);
-		btVector3 perpindicularDir = perpindicularComponent(reflectDir, collisionNormal);
+        btVector3 reflectDir = computeReflectionDirection(movementDirection, collisionNormal);
+        reflectDir.normalize();
 
-		targetPosition = _currentPosition;
-		/*if (tangentMag != 0.0)
-		{
-			btVector3 parComponent = parallelDir * btScalar (tangentMag*movementLength);
-			targetPosition +=  parComponent;
-		}*/
+        btVector3 perpindicularDir = perpindicularComponent(reflectDir, collisionNormal);
+        targetPosition = _currentPosition;
 
-		//if (normalMag != 0.0)
-		//{
-			btVector3 perpComponent = perpindicularDir * btScalar (/*normalMag **/ movementLength);
-			targetPosition += perpComponent;
-		//}
-	}
+        // Disallow the character from moving up during collision recovery (using an arbitrary reasonable epsilon).
+        // Note that this will need to be generalized to allow for an arbitrary up axis.
+        if (perpindicularDir.y() < _stepHeight + 0.001)
+        {
+            btVector3 perpComponent = perpindicularDir * movementLength;
+            targetPosition += perpComponent;
+        }
+    }
 }
 
 bool PhysicsCharacter::fixCollision(btCollisionWorld* world)
 {
-	bool collision = false;
+    bool collision = false;
 
     btOverlappingPairCache* pairCache = _ghostObject->getOverlappingPairCache();
 
     // Tell the world to dispatch collision events for our ghost object
-	world->getDispatcher()->dispatchAllCollisionPairs(pairCache, world->getDispatchInfo(), world->getDispatcher());
+    world->getDispatcher()->dispatchAllCollisionPairs(pairCache, world->getDispatchInfo(), world->getDispatcher());
 
     // Store our current world position
     Vector3 startPosition;
-	_node->getWorldMatrix().getTranslation(&startPosition);
-	btVector3 currentPosition = BV(startPosition);
+    _node->getWorldMatrix().getTranslation(&startPosition);
+    btVector3 currentPosition = BV(startPosition);
 
     // Handle all collisions/overlappign pairs
-	btScalar maxPenetration = btScalar(0.0);
-	for (int i = 0, count = pairCache->getNumOverlappingPairs(); i < count; ++i)
-	{
-		_manifoldArray.resize(0);
+    btScalar maxPenetration = btScalar(0.0);
+    for (int i = 0, count = pairCache->getNumOverlappingPairs(); i < count; ++i)
+    {
+        _manifoldArray.resize(0);
 
         // Query contacts between this overlapping pair (store in _manifoldArray)
-		btBroadphasePair* collisionPair = &pairCache->getOverlappingPairArray()[i];
-		if (collisionPair->m_algorithm)
+        btBroadphasePair* collisionPair = &pairCache->getOverlappingPairArray()[i];
+        if (collisionPair->m_algorithm)
         {
-			collisionPair->m_algorithm->getAllContactManifolds(_manifoldArray);
+            collisionPair->m_algorithm->getAllContactManifolds(_manifoldArray);
         }
 
-		for (int j = 0, manifoldCount = _manifoldArray.size(); j < manifoldCount; ++j)
-		{
-			btPersistentManifold* manifold = _manifoldArray[j];
+        for (int j = 0, manifoldCount = _manifoldArray.size(); j < manifoldCount; ++j)
+        {
+            btPersistentManifold* manifold = _manifoldArray[j];
 
             // Get the direction of the contact points (used to scale normal vector in the correct direction).
             btScalar directionSign = manifold->getBody0() == _ghostObject ? -1.0f : 1.0f;
 
-			for (int p = 0, contactCount = manifold->getNumContacts(); p < contactCount; ++p)
-			{
-				const btManifoldPoint& pt = manifold->getContactPoint(p);
+            for (int p = 0, contactCount = manifold->getNumContacts(); p < contactCount; ++p)
+            {
+                const btManifoldPoint& pt = manifold->getContactPoint(p);
 
                 // Get penetration distance for this contact point
-				btScalar dist = pt.getDistance();
+                btScalar dist = pt.getDistance();
 
-				if (dist < 0.0)
-				{
+                if (dist < 0.0)
+                {
                     // A negative distance means the objects are overlapping
-					if (dist < maxPenetration)
-					{
+                    if (dist < maxPenetration)
+                    {
                         // Store collision normal for this point
-						maxPenetration = dist;
+                        maxPenetration = dist;
                         _collisionNormal = pt.m_normalWorldOnB * directionSign;
-					}
+                    }
+
+                    //Node* node = Game::getInstance()->getPhysicsController()->getCollisionObject((btCollisionObject*)(manifold->getBody0() == _ghostObject ? manifold->getBody1() : manifold->getBody0()))->getNode();
 
                     // Calculate new position for object, which is translated back along the collision normal
-                    btVector3 n(pt.m_normalWorldOnB);
-                    n.normalize();
-					currentPosition += /*pt.m_normalWorldOnB*/n * directionSign * dist * COLLISION_REPAIR_MARGIN;// + _collisionShape->getMargin());// * COLLISION_REPAIR_INCREMENT;
-					collision = true;
-				}
-			}
-			//manifold->clearManifold();
-		}
-	}
-
-	// Set the new world transformation to apply to fix the collision
-	_node->translate(Vector3(currentPosition.x(), currentPosition.y(), currentPosition.z()) - startPosition);
-
-	return collision;
+                    currentPosition += pt.m_normalWorldOnB * directionSign * dist * 0.2f;
+                    collision = true;
+                }
+            }
+            //manifold->clearManifold();
+        }
+    }
+
+    // Set the new world transformation to apply to fix the collision
+    _node->translate(Vector3(currentPosition.x(), currentPosition.y(), currentPosition.z()) - startPosition);
+
+    return collision;
 }
 
 void PhysicsCharacter::debugDraw(btIDebugDraw* debugDrawer)

+ 6 - 4
gameplay/src/PhysicsCharacter.h

@@ -258,7 +258,7 @@ public:
     /**
      * @see btActionInterface::debugDraw
      */
-	void debugDraw(btIDebugDraw* debugDrawer);
+    void debugDraw(btIDebugDraw* debugDrawer);
 
 protected:
 
@@ -287,9 +287,10 @@ private:
      * Use PhysicsController::createCharacter to create physics characters.
      *
      * @param node Scene node that represents the character.
-	 * @param shape Physis collision shape definition.
+     * @param shape Physis collision shape definition.
+     * @param mass The mass of the character.
      */
-	PhysicsCharacter(Node* node, const PhysicsCollisionShape::Definition& shape);
+    PhysicsCharacter(Node* node, const PhysicsCollisionShape::Definition& shape, float mass);
 
     /**
      * Destructor.
@@ -333,11 +334,12 @@ private:
     btVector3 _currentPosition;
     std::map<const char*, CharacterAnimation> _animations;
     std::map<unsigned int, CharacterAnimation*> _layers;
-    btManifoldArray	_manifoldArray;
+    btManifoldArray _manifoldArray;
     float _stepHeight;
     float _slopeAngle;
     float _cosSlopeAngle;
     bool _physicsEnabled;
+    float _mass;
 };
 
 }

+ 15 - 15
gameplay/src/PhysicsCollisionObject.cpp

@@ -10,56 +10,56 @@ namespace gameplay
 struct CollidesWithCallback : public btCollisionWorld::ContactResultCallback
 {
     btScalar addSingleResult(btManifoldPoint& cp, 
-		const btCollisionObject* a, int partIdA, int indexA, 
-		const btCollisionObject* b, int partIdB, int indexB)
-	{
-		result = true;
-		return 0.0f;
-	}
+        const btCollisionObject* a, int partIdA, int indexA, 
+        const btCollisionObject* b, int partIdB, int indexB)
+    {
+        result = true;
+        return 0.0f;
+    }
 
     bool result;
 };
 
 PhysicsCollisionObject::PhysicsCollisionObject(Node* node)
-	: _node(node), _motionState(NULL), _collisionShape(NULL)
+    : _node(node), _motionState(NULL), _collisionShape(NULL)
 {
 }
 
 PhysicsCollisionObject::~PhysicsCollisionObject()
 {
-	SAFE_DELETE(_motionState);
+    SAFE_DELETE(_motionState);
 
-	Game::getInstance()->getPhysicsController()->destroyShape(_collisionShape);
+    Game::getInstance()->getPhysicsController()->destroyShape(_collisionShape);
 }
 
 PhysicsCollisionShape::Type PhysicsCollisionObject::getShapeType() const
 {
-	return getCollisionShape()->getType();
+    return getCollisionShape()->getType();
 }
 
 Node* PhysicsCollisionObject::getNode() const
 {
-	return _node;
+    return _node;
 }
 
 PhysicsCollisionShape* PhysicsCollisionObject::getCollisionShape() const
 {
-	return _collisionShape;
+    return _collisionShape;
 }
 
 PhysicsMotionState* PhysicsCollisionObject::getMotionState() const
 {
-	return _motionState;
+    return _motionState;
 }
 
 bool PhysicsCollisionObject::isKinematic() const
 {
-	return getCollisionObject()->isKinematicObject();
+    return getCollisionObject()->isKinematicObject();
 }
 
 bool PhysicsCollisionObject::isDynamic() const
 {
-	return !getCollisionObject()->isStaticOrKinematicObject();
+    return !getCollisionObject()->isStaticOrKinematicObject();
 }
 
 void PhysicsCollisionObject::addCollisionListener(CollisionListener* listener, PhysicsCollisionObject* object)

+ 31 - 31
gameplay/src/PhysicsCollisionObject.h

@@ -16,7 +16,7 @@ class Node;
 class PhysicsCollisionObject
 {
     friend class PhysicsController;
-	friend class PhysicsConstraint;
+    friend class PhysicsConstraint;
 
 public:
 
@@ -40,10 +40,10 @@ public:
          */
         GHOST_OBJECT,
 
-		/**
-		 * No collision object.
-		 */
-		NONE
+        /**
+         * No collision object.
+         */
+        NONE
     };
 
     /** 
@@ -122,7 +122,7 @@ public:
                                     const Vector3& contactPointB = Vector3::zero()) = 0;
     };
 
-	/**
+    /**
      * Virtual destructor.
      */
     virtual ~PhysicsCollisionObject();
@@ -132,38 +132,38 @@ public:
      */
     virtual PhysicsCollisionObject::Type getType() const = 0;
 
-	/**
-	 * Returns the type of the shape for this collision object.
-	 */
-	PhysicsCollisionShape::Type getShapeType() const;
+    /**
+     * Returns the type of the shape for this collision object.
+     */
+    PhysicsCollisionShape::Type getShapeType() const;
 
     /**
      * Returns the node associated with this collision object.
      */
     Node* getNode() const;
 
-	/**
+    /**
      * Returns the collision shape.
      *
      * @return The collision shape.
      */
     PhysicsCollisionShape* getCollisionShape() const;
 
-	/**
-	 * Returns whether this collision object is kinematic.
-	 *
-	 * A kinematic collision object is an object that is not simulated by
-	 * the physics system and instead has its transform driven manually.
-	 *
-	 * @return Whether the collision object is kinematic.
-	 */
-	bool isKinematic() const;
+    /**
+     * Returns whether this collision object is kinematic.
+     *
+     * A kinematic collision object is an object that is not simulated by
+     * the physics system and instead has its transform driven manually.
+     *
+     * @return Whether the collision object is kinematic.
+     */
+    bool isKinematic() const;
 
     /**
      * Returns whether this collision object is dynamic.
-	 *
-	 * A dynamic collision object is simulated entirely by the physics system,
-	 * such as with dynamic rigid bodies. 
+     *
+     * A dynamic collision object is simulated entirely by the physics system,
+     * such as with dynamic rigid bodies. 
      *
      * @return Whether the collision object is dynamic.
      */
@@ -207,15 +207,15 @@ protected:
      */
     virtual btCollisionObject* getCollisionObject() const = 0;
 
-	/**
-	 * Returns the physics motion state.
-	 *
-	 * @return The motion state object.
-	 */
-	PhysicsMotionState* getMotionState() const;
+    /**
+     * Returns the physics motion state.
+     *
+     * @return The motion state object.
+     */
+    PhysicsMotionState* getMotionState() const;
 
-	// Common member variables
-	Node* _node;
+    // Common member variables
+    Node* _node;
     PhysicsMotionState* _motionState;
     PhysicsCollisionShape* _collisionShape;
 

+ 64 - 23
gameplay/src/PhysicsCollisionShape.cpp

@@ -14,7 +14,7 @@ PhysicsCollisionShape::PhysicsCollisionShape(Type type, btCollisionShape* shape)
 
 PhysicsCollisionShape::PhysicsCollisionShape(const PhysicsCollisionShape& copy)
 {
-	// hidden
+    // hidden
 }
 
 PhysicsCollisionShape::~PhysicsCollisionShape()
@@ -60,6 +60,24 @@ PhysicsCollisionShape::Definition::Definition()
     memset(&data, 0, sizeof(data));
 }
 
+PhysicsCollisionShape::Definition::Definition(const Definition& definition)
+{
+    // Bitwise-copy the definition object (equivalent to default copy constructor).
+    memcpy(this, &definition, sizeof(PhysicsCollisionShape::Definition));
+
+    // Handle the types that have reference-counted members.
+    switch (type)
+    {
+    case PhysicsCollisionShape::SHAPE_HEIGHTFIELD:
+        data.heightfield->addRef();
+        break;
+
+    case PhysicsCollisionShape::SHAPE_MESH:
+        data.mesh->addRef();
+        break;
+    }
+}
+
 PhysicsCollisionShape::Definition::~Definition()
 {
     switch (type)
@@ -74,6 +92,29 @@ PhysicsCollisionShape::Definition::~Definition()
     }
 }
 
+PhysicsCollisionShape::Definition& PhysicsCollisionShape::Definition::operator=(const Definition& definition)
+{
+    if (this != &definition)
+    {
+        // Bitwise-copy the definition object (equivalent to default copy constructor).
+        memcpy(this, &definition, sizeof(PhysicsCollisionShape::Definition));
+
+        // Handle the types that have reference-counted members.
+        switch (type)
+        {
+        case PhysicsCollisionShape::SHAPE_HEIGHTFIELD:
+            data.heightfield->addRef();
+            break;
+
+        case PhysicsCollisionShape::SHAPE_MESH:
+            data.mesh->addRef();
+            break;
+        }
+    }
+
+    return *this;
+}
+
 PhysicsCollisionShape::Definition* PhysicsCollisionShape::Definition::create(Node* node, Properties* properties)
 {
     // Check if the properties is valid and has a valid namespace.
@@ -290,13 +331,13 @@ PhysicsCollisionShape::Definition PhysicsCollisionShape::box()
 
 PhysicsCollisionShape::Definition PhysicsCollisionShape::box(const Vector3& extents, const Vector3& center, bool absolute)
 {
-	Definition d;
-	d.type = SHAPE_BOX;
-	memcpy(d.data.box.extents, &extents.x, sizeof(float) * 3);
-	memcpy(d.data.box.center, &center.x, sizeof(float) * 3);
-	d.isExplicit = true;
-	d.centerAbsolute = absolute;
-	return d;
+    Definition d;
+    d.type = SHAPE_BOX;
+    memcpy(d.data.box.extents, &extents.x, sizeof(float) * 3);
+    memcpy(d.data.box.center, &center.x, sizeof(float) * 3);
+    d.isExplicit = true;
+    d.centerAbsolute = absolute;
+    return d;
 }
 
 PhysicsCollisionShape::Definition PhysicsCollisionShape::sphere()
@@ -310,13 +351,13 @@ PhysicsCollisionShape::Definition PhysicsCollisionShape::sphere()
 
 PhysicsCollisionShape::Definition PhysicsCollisionShape::sphere(float radius, const Vector3& center, bool absolute)
 {
-	Definition d;
-	d.type = SHAPE_SPHERE;
-	d.data.sphere.radius = radius;
-	memcpy(d.data.sphere.center, &center.x, sizeof(float) * 3);
-	d.isExplicit  = true;
-	d.centerAbsolute = absolute;
-	return d;
+    Definition d;
+    d.type = SHAPE_SPHERE;
+    d.data.sphere.radius = radius;
+    memcpy(d.data.sphere.center, &center.x, sizeof(float) * 3);
+    d.isExplicit  = true;
+    d.centerAbsolute = absolute;
+    return d;
 }
 
 PhysicsCollisionShape::Definition PhysicsCollisionShape::capsule()
@@ -330,14 +371,14 @@ PhysicsCollisionShape::Definition PhysicsCollisionShape::capsule()
 
 PhysicsCollisionShape::Definition PhysicsCollisionShape::capsule(float radius, float height, const Vector3& center, bool absolute)
 {
-	Definition d;
-	d.type = SHAPE_CAPSULE;
-	d.data.capsule.radius = radius;
-	d.data.capsule.height = height;
-	memcpy(d.data.capsule.center, &center.x, sizeof(float) * 3);
-	d.isExplicit = true;
-	d.centerAbsolute = absolute;
-	return d;
+    Definition d;
+    d.type = SHAPE_CAPSULE;
+    d.data.capsule.radius = radius;
+    d.data.capsule.height = height;
+    memcpy(d.data.capsule.center, &center.x, sizeof(float) * 3);
+    d.isExplicit = true;
+    d.centerAbsolute = absolute;
+    return d;
 }
 
 PhysicsCollisionShape::Definition PhysicsCollisionShape::heightfield(Image* image)

+ 35 - 33
gameplay/src/PhysicsCollisionShape.h

@@ -54,6 +54,8 @@ public:
     private:
 
         Definition();
+        Definition(const Definition& definition);
+        Definition& operator=(const Definition& definition);
 
         /**
          * Creates a PhysicsCollisionShape#Definition object from the given properties object (for the given node).
@@ -67,19 +69,19 @@ public:
         // Shape type.
         PhysicsCollisionShape::Type type;
 
-		// Shape data.
-		struct BoxData { float center[3], extents[3]; };
-		struct SphereData { float center[3]; float radius; };
-		struct CapsuleData { float center[3]; float radius, height; };
+        // Shape data.
+        struct BoxData { float center[3], extents[3]; };
+        struct SphereData { float center[3]; float radius; };
+        struct CapsuleData { float center[3]; float radius, height; };
 
         union
         {
-			BoxData box;
-			SphereData sphere;
-			CapsuleData capsule;
-			Image* heightfield;
-			Mesh* mesh;
-		} data;
+            BoxData box;
+            SphereData sphere;
+            CapsuleData capsule;
+            Image* heightfield;
+            Mesh* mesh;
+        } data;
 
         // Whether the shape definition is explicit, or if it is inherited from node bounds.
         bool isExplicit;
@@ -95,15 +97,15 @@ public:
      */
     PhysicsCollisionShape::Type getType() const;
 
-	/**
-	 * Returns the internal bullet physics shape object.
-	 *
-	 * @return The bullet shape object.
-	 */
-	btCollisionShape* getShape() const
-	{
-		return _shape;
-	}
+    /**
+     * Returns the internal bullet physics shape object.
+     *
+     * @return The bullet shape object.
+     */
+    btCollisionShape* getShape() const
+    {
+        return _shape;
+    }
 
     /**
      * Defines a box shape, using the bounding volume of the node it is attached to.
@@ -118,8 +120,8 @@ public:
      * @param extents Extents of the box shape along the x, y and z axes.
      * @param center Center point of the box.
      * @param absolute True to specifiy that the given center point is an absolute position.
-     *		By default the center point is treated as relative to the location of the node
-     *		that the shape is attached to.
+     *        By default the center point is treated as relative to the location of the node
+     *        that the shape is attached to.
      *
      * @return Definition of a box shape.
      */
@@ -138,8 +140,8 @@ public:
      * @param radius Radius of the sphere.
      * @param center Center point of the sphere.
      * @param absolute True to specifiy that the given center point is an absolute position.
-     *		By default the center point is treated as relative to the location of the node
-     *		that the shape is attached to.
+     *        By default the center point is treated as relative to the location of the node
+     *        that the shape is attached to.
      *
      * @return Definition of a sphere shape.
      */
@@ -159,8 +161,8 @@ public:
      * @param height Height of the capsule.
      * @param center Center point of the capsule.
      * @param absolute True to specifiy that the given center point is an absolute position.
-     *		By default the center point is treated as relative to the location of the node
-     *		that the shape is attached to.
+     *        By default the center point is treated as relative to the location of the node
+     *        that the shape is attached to.
      *
      * @return Definition of a capsule shape.
      */
@@ -202,15 +204,15 @@ private:
      */
     PhysicsCollisionShape(Type type, btCollisionShape* shape);
 
-	/** 
-	 * Hidden copy constructor.
-	 */
-	PhysicsCollisionShape(const PhysicsCollisionShape& copy);
+    /** 
+     * Hidden copy constructor.
+     */
+    PhysicsCollisionShape(const PhysicsCollisionShape& copy);
 
-	/**
-	 * Destructor.
-	 */
-	~PhysicsCollisionShape();
+    /**
+     * Destructor.
+     */
+    ~PhysicsCollisionShape();
 
 
     // Shape type

+ 1 - 1
gameplay/src/PhysicsConstraint.cpp

@@ -155,7 +155,7 @@ Vector3 PhysicsConstraint::getWorldCenterOfMass(const Model* model)
 
 Vector3 PhysicsConstraint::offsetByCenterOfMass(const Node* node, const Vector3& v)
 {
-	btVector3 centerOfMassOffset = (node->getCollisionObject()->getMotionState())->_centerOfMassOffset.getOrigin();
+    btVector3 centerOfMassOffset = (node->getCollisionObject()->getMotionState())->_centerOfMassOffset.getOrigin();
     return Vector3(v.x + centerOfMassOffset.x(), v.y + centerOfMassOffset.y(), v.z + centerOfMassOffset.z());
 }
 

+ 241 - 239
gameplay/src/PhysicsController.cpp

@@ -235,6 +235,8 @@ void PhysicsController::initialize()
     _ghostPairCallback = bullet_new<btGhostPairCallback>();
     _world->getPairCache()->setInternalGhostPairCallback(_ghostPairCallback);
 
+    _world->getDispatchInfo().m_allowedCcdPenetration = 0.0001f;
+
     // Set up debug drawing.
     _debugDrawer = new DebugDrawer();
     _world->setDebugDrawer(_debugDrawer);
@@ -402,15 +404,15 @@ void PhysicsController::addCollisionObject(PhysicsCollisionObject* object)
     switch (object->getType())
     {
     case PhysicsCollisionObject::RIGID_BODY:
-		_world->addRigidBody(static_cast<btRigidBody*>(object->getCollisionObject()), btBroadphaseProxy::DefaultFilter, btBroadphaseProxy::DefaultFilter | btBroadphaseProxy::StaticFilter | btBroadphaseProxy::CharacterFilter | btBroadphaseProxy::AllFilter);
+        _world->addRigidBody(static_cast<btRigidBody*>(object->getCollisionObject()), btBroadphaseProxy::DefaultFilter, btBroadphaseProxy::DefaultFilter | btBroadphaseProxy::StaticFilter | btBroadphaseProxy::CharacterFilter | btBroadphaseProxy::AllFilter);
         break;
 
     case PhysicsCollisionObject::CHARACTER:
-		_world->addCollisionObject(object->getCollisionObject(), btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::DefaultFilter | btBroadphaseProxy::StaticFilter | btBroadphaseProxy::CharacterFilter | btBroadphaseProxy::AllFilter);
+        _world->addCollisionObject(object->getCollisionObject(), btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::DefaultFilter | btBroadphaseProxy::StaticFilter | btBroadphaseProxy::CharacterFilter | btBroadphaseProxy::AllFilter);
         break;
 
     case PhysicsCollisionObject::GHOST_OBJECT:
-		_world->addCollisionObject(object->getCollisionObject(), btBroadphaseProxy::DefaultFilter, btBroadphaseProxy::DefaultFilter | btBroadphaseProxy::StaticFilter | btBroadphaseProxy::CharacterFilter | btBroadphaseProxy::AllFilter);
+        _world->addCollisionObject(object->getCollisionObject(), btBroadphaseProxy::DefaultFilter, btBroadphaseProxy::DefaultFilter | btBroadphaseProxy::StaticFilter | btBroadphaseProxy::CharacterFilter | btBroadphaseProxy::AllFilter);
         break;
 
     default:
@@ -458,199 +460,199 @@ PhysicsCollisionObject* PhysicsController::getCollisionObject(const btCollisionO
 
 void getBoundingBox(Node* node, BoundingBox* out, bool merge = false)
 {
-	if (node->getModel())
-	{
-		if (merge)
-			out->merge(node->getModel()->getMesh()->getBoundingBox());
-		else
-		{
-			out->set(node->getModel()->getMesh()->getBoundingBox());
-			merge = true;
-		}
-	}
-
-	Node* child = node->getFirstChild();
-	while (child)
-	{
-		getBoundingBox(child, out, merge);
-		child = child->getNextSibling();
-	}
+    if (node->getModel())
+    {
+        if (merge)
+            out->merge(node->getModel()->getMesh()->getBoundingBox());
+        else
+        {
+            out->set(node->getModel()->getMesh()->getBoundingBox());
+            merge = true;
+        }
+    }
+
+    Node* child = node->getFirstChild();
+    while (child)
+    {
+        getBoundingBox(child, out, merge);
+        child = child->getNextSibling();
+    }
 }
 
 void getBoundingSphere(Node* node, BoundingSphere* out, bool merge = false)
 {
-	if (node->getModel())
-	{
-		if (merge)
-			out->merge(node->getModel()->getMesh()->getBoundingSphere());
-		else
-		{
-			out->set(node->getModel()->getMesh()->getBoundingSphere());
-			merge = true;
-		}
-	}
-
-	Node* child = node->getFirstChild();
-	while (child)
-	{
-		getBoundingSphere(child, out, merge);
-		child = child->getNextSibling();
-	}
+    if (node->getModel())
+    {
+        if (merge)
+            out->merge(node->getModel()->getMesh()->getBoundingSphere());
+        else
+        {
+            out->set(node->getModel()->getMesh()->getBoundingSphere());
+            merge = true;
+        }
+    }
+
+    Node* child = node->getFirstChild();
+    while (child)
+    {
+        getBoundingSphere(child, out, merge);
+        child = child->getNextSibling();
+    }
 }
 
 void computeCenterOfMass(const Vector3& center, const Vector3& scale, Vector3* centerOfMassOffset)
 {
-	// Update center of mass offset
-	*centerOfMassOffset = center;
-	centerOfMassOffset->x *= scale.x;
-	centerOfMassOffset->y *= scale.y;
-	centerOfMassOffset->z *= scale.z;
-	centerOfMassOffset->negate();
+    // Update center of mass offset
+    *centerOfMassOffset = center;
+    centerOfMassOffset->x *= scale.x;
+    centerOfMassOffset->y *= scale.y;
+    centerOfMassOffset->z *= scale.z;
+    centerOfMassOffset->negate();
 }
 
 PhysicsCollisionShape* PhysicsController::createShape(Node* node, const PhysicsCollisionShape::Definition& shape, Vector3* centerOfMassOffset)
 {
-	PhysicsCollisionShape* collisionShape = NULL;
+    PhysicsCollisionShape* collisionShape = NULL;
 
     // Get the node's world scale (we need to apply this during creation since rigid bodies don't scale dynamically).
     Vector3 scale;
     node->getWorldMatrix().getScale(&scale);
 
-	switch (shape.type)
+    switch (shape.type)
     {
-	case PhysicsCollisionShape::SHAPE_BOX:
+    case PhysicsCollisionShape::SHAPE_BOX:
+        {
+            if (shape.isExplicit)
+            {
+                // Use the passed in box information
+                collisionShape = createBox(Vector3(shape.data.box.extents), Vector3::one());
+
+                if (shape.centerAbsolute)
+                {
+                    computeCenterOfMass(Vector3(shape.data.box.center), Vector3::one(), centerOfMassOffset);
+                }
+                else
+                {
+                    BoundingBox box;
+                    getBoundingBox(node, &box);
+                    computeCenterOfMass(box.getCenter() + Vector3(shape.data.box.center), scale, centerOfMassOffset);
+                }
+            }
+            else
+            {
+                // Automatically compute bounding box from mesh's bounding box
+                BoundingBox box;
+                getBoundingBox(node, &box);
+                collisionShape = createBox(Vector3(std::abs(box.max.x - box.min.x), std::abs(box.max.y - box.min.y), std::abs(box.max.z - box.min.z)), scale);
+
+                computeCenterOfMass(box.getCenter(), scale, centerOfMassOffset);
+            }
+        }
+        break;
+
+    case PhysicsCollisionShape::SHAPE_SPHERE:
+        {
+            if (shape.isExplicit)
+            {
+                // Use the passed in sphere information
+                collisionShape = createSphere(shape.data.sphere.radius, Vector3::one());
+
+                if (shape.centerAbsolute)
+                {
+                    computeCenterOfMass(Vector3(shape.data.sphere.center), Vector3::one(), centerOfMassOffset);
+                }
+                else
+                {
+                    BoundingSphere sphere;
+                    getBoundingSphere(node, &sphere);
+                    computeCenterOfMass(sphere.center + Vector3(shape.data.sphere.center), scale, centerOfMassOffset);
+                }
+            }
+            else
+            {
+                // Automatically compute bounding sphere from mesh's bounding sphere
+                BoundingSphere sphere;
+                getBoundingSphere(node, &sphere);
+                collisionShape = createSphere(sphere.radius, scale);
+
+                computeCenterOfMass(sphere.center, scale, centerOfMassOffset);
+            }
+        }
+        break;
+
+    case PhysicsCollisionShape::SHAPE_CAPSULE:
         {
-			if (shape.isExplicit)
-			{
-				// Use the passed in box information
-				collisionShape = createBox(Vector3(shape.data.box.extents), Vector3::one());
-
-				if (shape.centerAbsolute)
-				{
-					computeCenterOfMass(Vector3(shape.data.box.center), scale, centerOfMassOffset);
-				}
-				else
-				{
-					BoundingBox box;
-					getBoundingBox(node, &box);
-					computeCenterOfMass(box.getCenter() + Vector3(shape.data.box.center), scale, centerOfMassOffset);
-				}
-			}
-			else
-			{
-				// Automatically compute bounding box from mesh's bounding box
-				BoundingBox box;
-				getBoundingBox(node, &box);
-				collisionShape = createBox(Vector3(std::abs(box.max.x - box.min.x), std::abs(box.max.y - box.min.y), std::abs(box.max.z - box.min.z)), scale);
-
-				computeCenterOfMass(box.getCenter(), scale, centerOfMassOffset);
-			}
+            if (shape.isExplicit)
+            {
+                // Use the passed in capsule information
+                collisionShape = createCapsule(shape.data.capsule.radius, shape.data.capsule.height, Vector3::one());
+
+                if (shape.centerAbsolute)
+                {
+                    computeCenterOfMass(Vector3(shape.data.capsule.center), Vector3::one(), centerOfMassOffset);
+                }
+                else
+                {
+                    BoundingBox box;
+                    getBoundingBox(node, &box);
+                    computeCenterOfMass(box.getCenter() + Vector3(shape.data.capsule.center), scale, centerOfMassOffset);
+                }
+            }
+            else
+            {
+                // Compute a capsule shape that roughly matches the bounding box of the mesh
+                BoundingBox box;
+                getBoundingBox(node, &box);
+                float radius = std::max((box.max.x - box.min.x) * 0.5f, (box.max.z - box.min.z) * 0.5f);
+                float height = box.max.y - box.min.y;
+                collisionShape = createCapsule(radius, height, scale);
+
+                computeCenterOfMass(box.getCenter(), scale, centerOfMassOffset);
+            }
         }
-		break;
+        break;
 
-	case PhysicsCollisionShape::SHAPE_SPHERE:
+    case PhysicsCollisionShape::SHAPE_HEIGHTFIELD:
         {
-			if (shape.isExplicit)
-			{
-				// Use the passed in sphere information
-				collisionShape = createSphere(shape.data.sphere.radius, Vector3::one());
-
-				if (shape.centerAbsolute)
-				{
-					computeCenterOfMass(Vector3(shape.data.sphere.center), scale, centerOfMassOffset);
-				}
-				else
-				{
-					BoundingSphere sphere;
-					getBoundingSphere(node, &sphere);
-					computeCenterOfMass(sphere.center + Vector3(shape.data.sphere.center), scale, centerOfMassOffset);
-				}
-			}
-			else
-			{
-				// Automatically compute bounding sphere from mesh's bounding sphere
-				BoundingSphere sphere;
-				getBoundingSphere(node, &sphere);
-				collisionShape = createSphere(sphere.radius, scale);
-
-				computeCenterOfMass(sphere.center, scale, centerOfMassOffset);
-			}
+            // Build heightfield rigid body from the passed in shape
+            collisionShape = createHeightfield(node, shape.data.heightfield, centerOfMassOffset);
         }
-		break;
-
-	case PhysicsCollisionShape::SHAPE_CAPSULE:
-		{
-			if (shape.isExplicit)
-			{
-				// Use the passed in capsule information
-				collisionShape = createCapsule(shape.data.capsule.radius, shape.data.capsule.height, Vector3::one());
-
-				if (shape.centerAbsolute)
-				{
-					computeCenterOfMass(Vector3(shape.data.capsule.center), scale, centerOfMassOffset);
-				}
-				else
-				{
-					BoundingBox box;
-					getBoundingBox(node, &box);
-					computeCenterOfMass(box.getCenter() + Vector3(shape.data.capsule.center), scale, centerOfMassOffset);
-				}
-			}
-			else
-			{
-				// Compute a capsule shape that roughly matches the bounding box of the mesh
-				BoundingBox box;
-				getBoundingBox(node, &box);
-				float radius = std::max((box.max.x - box.min.x) * 0.5f, (box.max.z - box.min.z) * 0.5f);
-				float height = (box.max.y - box.min.y) - radius * 2.0f;
-				collisionShape = createCapsule(radius, height, scale);
-
-				computeCenterOfMass(box.getCenter(), scale, centerOfMassOffset);
-			}
-		}
-		break;
-
-	case PhysicsCollisionShape::SHAPE_HEIGHTFIELD:
-		{
-			// Build heightfield rigid body from the passed in shape
-			collisionShape = createHeightfield(node, shape.data.heightfield, centerOfMassOffset);
-		}
-		break;
-
-	case PhysicsCollisionShape::SHAPE_MESH:
+        break;
+
+    case PhysicsCollisionShape::SHAPE_MESH:
         {
-			// Build mesh from passed in shape
-			collisionShape = createMesh(shape.data.mesh, scale);
+            // Build mesh from passed in shape
+            collisionShape = createMesh(shape.data.mesh, scale);
         }
-		break;
+        break;
     }
 
-	return collisionShape;
+    return collisionShape;
 }
 
 PhysicsCollisionShape* PhysicsController::createBox(const Vector3& extents, const Vector3& scale)
 {
     btVector3 halfExtents(scale.x * 0.5 * extents.x, scale.y * 0.5 * extents.y, scale.z * 0.5 * extents.z);
 
-	PhysicsCollisionShape* shape;
+    PhysicsCollisionShape* shape;
 
     // Return the box shape from the cache if it already exists.
     for (unsigned int i = 0; i < _shapes.size(); ++i)
     {
-		shape = _shapes[i];
-		if (shape->getType() == PhysicsCollisionShape::SHAPE_BOX)
+        shape = _shapes[i];
+        if (shape->getType() == PhysicsCollisionShape::SHAPE_BOX)
         {
-			btBoxShape* box = static_cast<btBoxShape*>(shape->_shape);
+            btBoxShape* box = static_cast<btBoxShape*>(shape->_shape);
             if (box->getHalfExtentsWithMargin() == halfExtents)
             {
-				shape->addRef();
+                shape->addRef();
                 return shape;
             }
         }
     }
 
     // Create the box shape and add it to the cache.
-	shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_BOX, bullet_new<btBoxShape>(halfExtents));
+    shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_BOX, bullet_new<btBoxShape>(halfExtents));
     _shapes.push_back(shape);
 
     return shape;
@@ -666,15 +668,15 @@ PhysicsCollisionShape* PhysicsController::createSphere(float radius, const Vecto
     if (uniformScale < scale.z)
         uniformScale = scale.z;
 
-	float scaledRadius = radius * uniformScale;
+    float scaledRadius = radius * uniformScale;
 
-	PhysicsCollisionShape* shape;
+    PhysicsCollisionShape* shape;
 
     // Return the sphere shape from the cache if it already exists.
     for (unsigned int i = 0; i < _shapes.size(); ++i)
     {
-		shape = _shapes[i];
-		if (shape->getType() == PhysicsCollisionShape::SHAPE_SPHERE)
+        shape = _shapes[i];
+        if (shape->getType() == PhysicsCollisionShape::SHAPE_SPHERE)
         {
             btSphereShape* sphere = static_cast<btSphereShape*>(shape->_shape);
             if (sphere->getRadius() == scaledRadius)
@@ -686,7 +688,7 @@ PhysicsCollisionShape* PhysicsController::createSphere(float radius, const Vecto
     }
 
     // Create the sphere shape and add it to the cache.
-	shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_SPHERE, bullet_new<btSphereShape>(scaledRadius));
+    shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_SPHERE, bullet_new<btSphereShape>(scaledRadius));
     _shapes.push_back(shape);
 
     return shape;
@@ -694,19 +696,19 @@ PhysicsCollisionShape* PhysicsController::createSphere(float radius, const Vecto
 
 PhysicsCollisionShape* PhysicsController::createCapsule(float radius, float height, const Vector3& scale)
 {
-	float girthScale = scale.x;
-	if (girthScale < scale.z)
-		girthScale = scale.z;
-	float scaledRadius = radius * girthScale;
-	float scaledHeight = height * scale.y;
+    float girthScale = scale.x;
+    if (girthScale < scale.z)
+        girthScale = scale.z;
+    float scaledRadius = radius * girthScale;
+    float scaledHeight = height * scale.y - radius * 2;
 
-	PhysicsCollisionShape* shape;
+    PhysicsCollisionShape* shape;
 
     // Return the capsule shape from the cache if it already exists.
     for (unsigned int i = 0; i < _shapes.size(); i++)
     {
-		shape = _shapes[i];
-		if (shape->getType() == PhysicsCollisionShape::SHAPE_CAPSULE)
+        shape = _shapes[i];
+        if (shape->getType() == PhysicsCollisionShape::SHAPE_CAPSULE)
         {
             btCapsuleShape* capsule = static_cast<btCapsuleShape*>(shape->_shape);
             if (capsule->getRadius() == scaledRadius && capsule->getHalfHeight() == 0.5f * scaledHeight)
@@ -718,7 +720,7 @@ PhysicsCollisionShape* PhysicsController::createCapsule(float radius, float heig
     }
 
     // Create the capsule shape and add it to the cache.
-	shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_CAPSULE, bullet_new<btCapsuleShape>(scaledRadius, scaledHeight));
+    shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_CAPSULE, bullet_new<btCapsuleShape>(scaledRadius, scaledHeight));
     _shapes.push_back(shape);
 
     return shape;
@@ -726,25 +728,25 @@ PhysicsCollisionShape* PhysicsController::createCapsule(float radius, float heig
 
 PhysicsCollisionShape* PhysicsController::createHeightfield(Node* node, Image* image, Vector3* centerOfMassOffset)
 {
-	// Get the dimensions of the heightfield.
-	// If the node has a mesh defined, use the dimensions of the bounding box for the mesh.
-	// Otherwise simply use the image dimensions (with a max height of 255).
-	float width, length, minHeight, maxHeight;
-	if (node->getModel() && node->getModel()->getMesh())
-	{
-		const BoundingBox& box = node->getModel()->getMesh()->getBoundingBox();
-		width = box.max.x - box.min.x;
-		length = box.max.z - box.min.z;
-		minHeight = box.min.y;
-		maxHeight = box.max.y;
-	}
-	else
-	{
-		width = image->getWidth();
-		length = image->getHeight();
-		minHeight = 0.0f;
-		maxHeight = 255.0f;
-	}
+    // Get the dimensions of the heightfield.
+    // If the node has a mesh defined, use the dimensions of the bounding box for the mesh.
+    // Otherwise simply use the image dimensions (with a max height of 255).
+    float width, length, minHeight, maxHeight;
+    if (node->getModel() && node->getModel()->getMesh())
+    {
+        const BoundingBox& box = node->getModel()->getMesh()->getBoundingBox();
+        width = box.max.x - box.min.x;
+        length = box.max.z - box.min.z;
+        minHeight = box.min.y;
+        maxHeight = box.max.y;
+    }
+    else
+    {
+        width = image->getWidth();
+        length = image->getHeight();
+        minHeight = 0.0f;
+        maxHeight = 255.0f;
+    }
 
     // Get the size in bytes of a pixel (we ensure that the image's
     // pixel format is actually supported before calling this constructor).
@@ -757,14 +759,14 @@ PhysicsCollisionShape* PhysicsController::createHeightfield(Node* node, Image* i
         case Image::RGBA:
             pixelSize = 4;
             break;
-		default:
-			LOG_ERROR("Unsupported pixel format for heightmap image.");
-			return NULL;
+        default:
+            LOG_ERROR("Unsupported pixel format for heightmap image.");
+            return NULL;
     }
 
     // Calculate the heights for each pixel.
     float* heights = new float[image->getWidth() * image->getHeight()];
-	unsigned char* data = image->getData();
+    unsigned char* data = image->getData();
     for (unsigned int x = 0, w = image->getWidth(); x < w; ++x)
     {
         for (unsigned int y = 0, h = image->getHeight(); y < h; ++y)
@@ -775,16 +777,16 @@ PhysicsCollisionShape* PhysicsController::createHeightfield(Node* node, Image* i
         }
     }
 
-	PhysicsCollisionShape::HeightfieldData* heightfieldData = new PhysicsCollisionShape::HeightfieldData();
-	heightfieldData->heightData = NULL;
-	heightfieldData->inverseIsDirty = true;
+    PhysicsCollisionShape::HeightfieldData* heightfieldData = new PhysicsCollisionShape::HeightfieldData();
+    heightfieldData->heightData = NULL;
+    heightfieldData->inverseIsDirty = true;
 
     // Generate the heightmap data needed for physics (one height per world unit).
     unsigned int sizeWidth = width;
     unsigned int sizeHeight = length;
-	heightfieldData->width = sizeWidth + 1;
+    heightfieldData->width = sizeWidth + 1;
     heightfieldData->height = sizeHeight + 1;
-	heightfieldData->heightData = new float[heightfieldData->width * heightfieldData->height];
+    heightfieldData->heightData = new float[heightfieldData->width * heightfieldData->height];
     unsigned int heightIndex = 0;
     float widthImageFactor = (float)(image->getWidth() - 1) / sizeWidth;
     float heightImageFactor = (float)(image->getHeight() - 1) / sizeHeight;
@@ -794,8 +796,8 @@ PhysicsCollisionShape* PhysicsController::createHeightfield(Node* node, Image* i
     {
         for (unsigned int col = 0, x = 0.0f; col <= sizeWidth; col++, x += 1.0f)
         {
-			heightIndex = row * heightfieldData->width + col;
-			heightfieldData->heightData[heightIndex] = calculateHeight(heights, image->getWidth(), image->getHeight(), x * widthImageFactor, (sizeHeight - z) * heightImageFactor);
+            heightIndex = row * heightfieldData->width + col;
+            heightfieldData->heightData[heightIndex] = calculateHeight(heights, image->getWidth(), image->getHeight(), x * widthImageFactor, (sizeHeight - z) * heightImageFactor);
         }
     }
     SAFE_DELETE_ARRAY(heights);
@@ -804,15 +806,15 @@ PhysicsCollisionShape* PhysicsController::createHeightfield(Node* node, Image* i
     // of its heightfield collision shape; see documentation for the btHeightfieldTerrainShape for more info.
     Vector3 s;
     node->getWorldMatrix().getScale(&s);
-	centerOfMassOffset->set(0.0f, -(maxHeight - (0.5f * (maxHeight - minHeight))) / s.y, 0.0f);
+    centerOfMassOffset->set(0.0f, -(maxHeight - (0.5f * (maxHeight - minHeight))) / s.y, 0.0f);
 
-	// Create the bullet terrain shape
-	btHeightfieldTerrainShape* terrainShape = bullet_new<btHeightfieldTerrainShape>(
-		heightfieldData->width, heightfieldData->height, heightfieldData->heightData, 1.0f, minHeight, maxHeight, 1, PHY_FLOAT, false);
+    // Create the bullet terrain shape
+    btHeightfieldTerrainShape* terrainShape = bullet_new<btHeightfieldTerrainShape>(
+        heightfieldData->width, heightfieldData->height, heightfieldData->heightData, 1.0f, minHeight, maxHeight, 1, PHY_FLOAT, false);
 
-	// Create our collision shape object and store heightfieldData in it
-	PhysicsCollisionShape* shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_HEIGHTFIELD, terrainShape);
-	shape->_shapeData.heightfieldData = heightfieldData;
+    // Create our collision shape object and store heightfieldData in it
+    PhysicsCollisionShape* shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_HEIGHTFIELD, terrainShape);
+    shape->_shapeData.heightfieldData = heightfieldData;
 
     _shapes.push_back(shape);
 
@@ -823,29 +825,29 @@ PhysicsCollisionShape* PhysicsController::createMesh(Mesh* mesh, const Vector3&
 {
     assert(mesh);
 
-	// Only support meshes with triangle list primitive types
-	bool triMesh = true;
-	if (mesh->getPartCount() > 0)
-	{
-		for (unsigned int i = 0; i < mesh->getPartCount(); ++i)
-		{
-			if (mesh->getPart(i)->getPrimitiveType() != Mesh::TRIANGLES)
-			{
-				triMesh = false;
-				break;
-			}
-		}
-	}
-	else
-	{
-		triMesh = mesh->getPrimitiveType() == Mesh::TRIANGLES;
-	}
-
-	if (!triMesh)
-	{
-		LOG_ERROR("Mesh rigid bodies are currently only supported on meshes with TRIANGLES primitive type.");
-		return NULL;
-	}
+    // Only support meshes with triangle list primitive types
+    bool triMesh = true;
+    if (mesh->getPartCount() > 0)
+    {
+        for (unsigned int i = 0; i < mesh->getPartCount(); ++i)
+        {
+            if (mesh->getPart(i)->getPrimitiveType() != Mesh::TRIANGLES)
+            {
+                triMesh = false;
+                break;
+            }
+        }
+    }
+    else
+    {
+        triMesh = mesh->getPrimitiveType() == Mesh::TRIANGLES;
+    }
+
+    if (!triMesh)
+    {
+        LOG_ERROR("Mesh rigid bodies are currently only supported on meshes with TRIANGLES primitive type.");
+        return NULL;
+    }
 
     // The mesh must have a valid URL (i.e. it must have been loaded from a Package)
     // in order to fetch mesh data for computing mesh rigid body.
@@ -861,15 +863,15 @@ PhysicsCollisionShape* PhysicsController::createMesh(Mesh* mesh, const Vector3&
         return NULL;
     }
 
-	// Create mesh data to be populated and store in returned collision shape
-	PhysicsCollisionShape::MeshData* shapeMeshData = new PhysicsCollisionShape::MeshData();
-	shapeMeshData->vertexData = NULL;
+    // Create mesh data to be populated and store in returned collision shape
+    PhysicsCollisionShape::MeshData* shapeMeshData = new PhysicsCollisionShape::MeshData();
+    shapeMeshData->vertexData = NULL;
 
     // Copy the scaled vertex position data to the rigid body's local buffer.
     Matrix m;
     Matrix::createScale(scale, &m);
     unsigned int vertexCount = data->vertexCount;
-	shapeMeshData->vertexData = new float[vertexCount * 3];
+    shapeMeshData->vertexData = new float[vertexCount * 3];
     Vector3 v;
     int vertexStride = data->vertexFormat.getVertexSize();
     for (unsigned int i = 0; i < data->vertexCount; i++)
@@ -878,7 +880,7 @@ PhysicsCollisionShape* PhysicsController::createMesh(Mesh* mesh, const Vector3&
               *((float*)&data->vertexData[i * vertexStride + 1 * sizeof(float)]),
               *((float*)&data->vertexData[i * vertexStride + 2 * sizeof(float)]));
         v *= m;
-		memcpy(&(shapeMeshData->vertexData[i * 3]), &v, sizeof(float) * 3);
+        memcpy(&(shapeMeshData->vertexData[i * 3]), &v, sizeof(float) * 3);
     }
 
     btTriangleIndexVertexArray* meshInterface = bullet_new<btTriangleIndexVertexArray>();
@@ -911,7 +913,7 @@ PhysicsCollisionShape* PhysicsController::createMesh(Mesh* mesh, const Vector3&
 
             // Move the index data into the rigid body's local buffer.
             // Set it to NULL in the MeshPartData so it is not released when the data is freed.
-			shapeMeshData->indexData.push_back(meshPart->indexData);
+            shapeMeshData->indexData.push_back(meshPart->indexData);
             meshPart->indexData = NULL;
 
             // Create a btIndexedMesh object for the current mesh part.
@@ -919,9 +921,9 @@ PhysicsCollisionShape* PhysicsController::createMesh(Mesh* mesh, const Vector3&
             indexedMesh.m_indexType = indexType;
             indexedMesh.m_numTriangles = meshPart->indexCount / 3; // assume TRIANGLES primitive type
             indexedMesh.m_numVertices = meshPart->indexCount;
-			indexedMesh.m_triangleIndexBase = (const unsigned char*)shapeMeshData->indexData[i];
+            indexedMesh.m_triangleIndexBase = (const unsigned char*)shapeMeshData->indexData[i];
             indexedMesh.m_triangleIndexStride = indexStride*3;
-			indexedMesh.m_vertexBase = (const unsigned char*)shapeMeshData->vertexData;
+            indexedMesh.m_vertexBase = (const unsigned char*)shapeMeshData->vertexData;
             indexedMesh.m_vertexStride = sizeof(float)*3;
             indexedMesh.m_vertexType = PHY_FLOAT;
 
@@ -954,9 +956,9 @@ PhysicsCollisionShape* PhysicsController::createMesh(Mesh* mesh, const Vector3&
         meshInterface->addIndexedMesh(indexedMesh, indexedMesh.m_indexType);
     }
 
-	// Create our collision shape object and store shapeMeshData in it
-	PhysicsCollisionShape* shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_MESH, bullet_new<btBvhTriangleMeshShape>(meshInterface, true));
-	shape->_shapeData.meshData = shapeMeshData;
+    // Create our collision shape object and store shapeMeshData in it
+    PhysicsCollisionShape* shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_MESH, bullet_new<btBvhTriangleMeshShape>(meshInterface, true));
+    shape->_shapeData.meshData = shapeMeshData;
 
     _shapes.push_back(shape);
 
@@ -972,14 +974,14 @@ void PhysicsController::destroyShape(PhysicsCollisionShape* shape)
     {
         if (shape->getRefCount() == 1)
         {
-			// Remove shape from shape cache
+            // Remove shape from shape cache
             std::vector<PhysicsCollisionShape*>::iterator shapeItr = std::find(_shapes.begin(), _shapes.end(), shape);
             if (shapeItr != _shapes.end())
                 _shapes.erase(shapeItr);
         }
 
-		// Release the shape
-		shape->release();
+        // Release the shape
+        shape->release();
     }
 }
 
@@ -1167,7 +1169,7 @@ void PhysicsController::DebugDrawer::setDebugMode(int mode)
     _mode = mode;
 }
 
-int	PhysicsController::DebugDrawer::getDebugMode() const
+int PhysicsController::DebugDrawer::getDebugMode() const
 {
     return _mode;
 }

+ 11 - 11
gameplay/src/PhysicsController.h

@@ -229,7 +229,7 @@ private:
         int _status;
     };
 
-	/**
+    /**
      * Constructor.
      */
     PhysicsController();
@@ -279,30 +279,30 @@ private:
     // Gets the corresponding GamePlay object for the given Bullet object.
     PhysicsCollisionObject* getCollisionObject(const btCollisionObject* collisionObject) const;
 
-	// Creates a collision shape for the given node and gameplay shape definition.
-	// Populates 'centerOfMassOffset' with the correct calculated center of mass offset.
-	PhysicsCollisionShape* createShape(Node* node, const PhysicsCollisionShape::Definition& shape, Vector3* centerOfMassOffset);
+    // Creates a collision shape for the given node and gameplay shape definition.
+    // Populates 'centerOfMassOffset' with the correct calculated center of mass offset.
+    PhysicsCollisionShape* createShape(Node* node, const PhysicsCollisionShape::Definition& shape, Vector3* centerOfMassOffset);
     
     // Creates a box collision shape.
     PhysicsCollisionShape* createBox(const Vector3& extents, const Vector3& scale);
 
-	// Creates a sphere collision shape.
+    // Creates a sphere collision shape.
     PhysicsCollisionShape* createSphere(float radius, const Vector3& scale);
 
     // Creates a capsule collision shape.
     PhysicsCollisionShape* createCapsule(float radius, float height, const Vector3& scale);
 
-	// Creates a heightfield collision shape.
+    // Creates a heightfield collision shape.
     PhysicsCollisionShape* createHeightfield(Node* node, Image* image, Vector3* centerOfMassOffset);
 
     // Creates a triangle mesh collision shape.
     PhysicsCollisionShape* createMesh(Mesh* mesh, const Vector3& scale);
 
-	// Destroys a collision shape created through PhysicsController
-	void destroyShape(PhysicsCollisionShape* shape);
+    // Destroys a collision shape created through PhysicsController
+    void destroyShape(PhysicsCollisionShape* shape);
 
-	// Helper function for calculating heights from heightmap (image) or heightfield data.
-	static float calculateHeight(float* data, unsigned int width, unsigned int height, float x, float y);
+    // Helper function for calculating heights from heightmap (image) or heightfield data.
+    static float calculateHeight(float* data, unsigned int width, unsigned int height, float x, float y);
 
     // Sets up the given constraint for the given two rigid bodies.
     void addConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b, PhysicsConstraint* constraint);
@@ -337,7 +337,7 @@ private:
         void reportErrorWarning(const char* warningString);
         void draw3dText(const btVector3& location, const char* textString);        
         void setDebugMode(int mode);        
-        int	getDebugMode() const;
+        int    getDebugMode() const;
         
     private:
         

+ 1 - 1
gameplay/src/PhysicsGhostObject.cpp

@@ -17,7 +17,7 @@ PhysicsGhostObject::PhysicsGhostObject(Node* node, const PhysicsCollisionShape::
 
     // Create the ghost object.
     _ghostObject = bullet_new<btPairCachingGhostObject>();
-	_ghostObject->setCollisionShape(_collisionShape->getShape());
+    _ghostObject->setCollisionShape(_collisionShape->getShape());
 
     // Initialize a physics motion state object for syncing the transform.
     _motionState = new PhysicsMotionState(_node, &centerOfMassOffset);

+ 1 - 1
gameplay/src/PhysicsMotionState.cpp

@@ -23,7 +23,7 @@ PhysicsMotionState::~PhysicsMotionState()
 
 void PhysicsMotionState::getWorldTransform(btTransform &transform) const
 {
-	if (_node->getCollisionObject() && _node->getCollisionObject()->isKinematic())
+    if (_node->getCollisionObject() && _node->getCollisionObject()->isKinematic())
         updateTransformFromNode();
 
     transform = _centerOfMassOffset.inverse() * _worldTransform;

+ 4 - 4
gameplay/src/PhysicsMotionState.h

@@ -15,10 +15,10 @@ class Node;
  */
 class PhysicsMotionState : public btMotionState
 {
-	friend class PhysicsCollisionObject;
-	friend class PhysicsRigidBody;
-	friend class PhysicsGhostObject;
-	friend class PhysicsCharacter;
+    friend class PhysicsCollisionObject;
+    friend class PhysicsRigidBody;
+    friend class PhysicsGhostObject;
+    friend class PhysicsCharacter;
     friend class PhysicsConstraint;
 
 protected:

+ 2 - 2
gameplay/src/PhysicsRigidBody.cpp

@@ -24,8 +24,8 @@ PhysicsRigidBody::PhysicsRigidBody(Node* node, const PhysicsCollisionShape::Defi
     // inertia. However, if the collision shape is a triangle mesh, we don't calculate 
     // inertia since Bullet doesn't currently support this.
     btVector3 localInertia(0.0, 0.0, 0.0);
-	if (parameters.mass != 0.0 && _collisionShape->getType() != PhysicsCollisionShape::SHAPE_MESH)
-		_collisionShape->getShape()->calculateLocalInertia(parameters.mass, localInertia);
+    if (parameters.mass != 0.0 && _collisionShape->getType() != PhysicsCollisionShape::SHAPE_MESH)
+        _collisionShape->getShape()->calculateLocalInertia(parameters.mass, localInertia);
 
     // Create the Bullet physics rigid body object.
     btRigidBody::btRigidBodyConstructionInfo rbInfo(parameters.mass, _motionState, _collisionShape->getShape(), localInertia);

+ 83 - 83
gameplay/src/PhysicsRigidBody.h

@@ -30,75 +30,75 @@ class PhysicsRigidBody : public PhysicsCollisionObject, public Transform::Listen
 
 public:
 
-	/**
-	 * Rigid body construction parameters.
-	 */
-	struct Parameters
-	{
-		/**
-		 * The mass of the rigid body, in kilograms.
-		 */
-		float mass;
-
-		/**
-		 * The friction of the rigid body (non-zero values give best simulation results).
-		 */
-		float friction;
-
-		/**
-		 * The restitution of the rigid body (this controls the bounciness of
-		 * the rigid body; use zero for best simulation results).
-		 */
+    /**
+     * Rigid body construction parameters.
+     */
+    struct Parameters
+    {
+        /**
+         * The mass of the rigid body, in kilograms.
+         */
+        float mass;
+
+        /**
+         * The friction of the rigid body (non-zero values give best simulation results).
+         */
+        float friction;
+
+        /**
+         * The restitution of the rigid body (this controls the bounciness of
+         * the rigid body; use zero for best simulation results).
+         */
         float restitution;
 
-		/**
-		 * The percentage of linear velocity lost per second (between 0.0 and 1.0).
-		 */
-		float linearDamping;
-
-		/**
-		 * The percentage of angular velocity lost per second (between 0.0 and 1.0).
-		 */
-		float angularDamping;
-
-		/**
-		 * Whether the rigid body is kinematic.
-		 */
-		bool kinematic;
-
-		/**
-		 * The ansitropic friction term for the rigid body.
-		 */
-		Vector3 anisotropicFriction;
-
-		/**
-		 * The gravity acceleration factor for the rigid body.
-		 */
-		Vector3 gravity;
-
-		/**
-		 * Constructor.
-		 */
-		Parameters(float mass = 0.0f, float friction = 0.5f, float resititution = 0.0f,
-			float linearDamping = 0.0f, float angularDamping = 0.0f, bool kinematic = false,
-			const Vector3& anisotropicFriction = Vector3::one(), const Vector3& gravity = Vector3::zero())
-			: mass(mass), friction(friction), restitution(restitution), linearDamping(linearDamping), angularDamping(angularDamping),
-			  kinematic(kinematic), anisotropicFriction(anisotropicFriction), gravity(gravity)
-		{
-		}
-	};
+        /**
+         * The percentage of linear velocity lost per second (between 0.0 and 1.0).
+         */
+        float linearDamping;
+
+        /**
+         * The percentage of angular velocity lost per second (between 0.0 and 1.0).
+         */
+        float angularDamping;
+
+        /**
+         * Whether the rigid body is kinematic.
+         */
+        bool kinematic;
+
+        /**
+         * The ansitropic friction term for the rigid body.
+         */
+        Vector3 anisotropicFriction;
+
+        /**
+         * The gravity acceleration factor for the rigid body.
+         */
+        Vector3 gravity;
+
+        /**
+         * Constructor.
+         */
+        Parameters(float mass = 0.0f, float friction = 0.5f, float resititution = 0.0f,
+            float linearDamping = 0.0f, float angularDamping = 0.0f, bool kinematic = false,
+            const Vector3& anisotropicFriction = Vector3::one(), const Vector3& gravity = Vector3::zero())
+            : mass(mass), friction(friction), restitution(restitution), linearDamping(linearDamping), angularDamping(angularDamping),
+              kinematic(kinematic), anisotropicFriction(anisotropicFriction), gravity(gravity)
+        {
+        }
+    };
 
     /**
      * @see PhysicsCollisionObject#getType
      */
     PhysicsCollisionObject::Type getType() const;
 
-	/**
-	 * Gets the rigid body's mass.
-	 *
-	 * @return The mass.
-	 */
-	inline float getMass() const;
+    /**
+     * Gets the rigid body's mass.
+     *
+     * @return The mass.
+     */
+    inline float getMass() const;
 
     /**
      * Gets the rigid body's friction.
@@ -114,12 +114,12 @@ public:
      */
     inline void setFriction(float friction);
 
-	/**
-	 * Gets the rigid body's restitution.
-	 *
-	 * @return The restitution.
-	 */
-	inline float getRestitution() const;
+    /**
+     * Gets the rigid body's restitution.
+     *
+     * @return The restitution.
+     */
+    inline float getRestitution() const;
 
     /**
      * Sets the rigid body's restitution (or bounciness).
@@ -128,19 +128,19 @@ public:
      */
     inline void setRestitution(float restitution);
 
-	/**
-	 * Gets the rigid body's linear damping.
-	 *
-	 * @return The linear damping.
-	 */
-	inline float getLinearDamping() const;
+    /**
+     * Gets the rigid body's linear damping.
+     *
+     * @return The linear damping.
+     */
+    inline float getLinearDamping() const;
 
-	/**
-	 * Gets the rigid body's angular damping.
-	 *
-	 * @return The angular damping.
-	 */
-	inline float getAngularDamping() const;
+    /**
+     * Gets the rigid body's angular damping.
+     *
+     * @return The angular damping.
+     */
+    inline float getAngularDamping() const;
 
     /**
      * Sets the rigid body's linear and angular damping.
@@ -150,7 +150,7 @@ public:
      */
     inline void setDamping(float linearDamping, float angularDamping);
 
-	/**
+    /**
      * Gets the rigid body's linear velocity.
      * 
      * @return The linear velocity.
@@ -277,7 +277,7 @@ private:
      * @param shape The rigid body shape construction information.
      * @param parameters The rigid body construction parameters.
      */
-	PhysicsRigidBody(Node* node, const PhysicsCollisionShape::Definition& shape, const Parameters& parameters);
+    PhysicsRigidBody(Node* node, const PhysicsCollisionShape::Definition& shape, const Parameters& parameters);
 
     /**
      * Destructor.
@@ -312,8 +312,8 @@ private:
     void transformChanged(Transform* transform, long cookie);
 
     btRigidBody* _body;
-	float _mass;
-	std::vector<PhysicsConstraint*>* _constraints;
+    float _mass;
+    std::vector<PhysicsConstraint*>* _constraints;
 
 };
 

+ 2 - 2
gameplay/src/PhysicsRigidBody.inl

@@ -6,7 +6,7 @@ namespace gameplay
 
 inline float PhysicsRigidBody::getMass() const
 {
-	return _mass;
+    return _mass;
 }
 
 inline float PhysicsRigidBody::getFriction() const
@@ -47,7 +47,7 @@ inline void PhysicsRigidBody::setDamping(float linearDamping, float angularDampi
 inline Vector3 PhysicsRigidBody::getLinearVelocity() const
 {
     const btVector3& v = _body->getLinearVelocity();
-	return Vector3(v.x(), v.y(), v.z());
+    return Vector3(v.x(), v.y(), v.z());
 }
 
 inline void PhysicsRigidBody::setLinearVelocity(const Vector3& velocity)

+ 98 - 98
gameplay/src/PlatformMacOS.mm

@@ -4,7 +4,7 @@
 #include "Platform.h"
 #include "FileSystem.h"
 #include "Game.h"
-
+#include "Form.h"
 #include <unistd.h>
 
 #import <Cocoa/Cocoa.h>
@@ -15,10 +15,10 @@
 using namespace std;
 using namespace gameplay;
 
-// Default to 720p
-#define WINDOW_WIDTH    1280
-#define WINDOW_HEIGHT   720
-
+// 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;
 
@@ -32,7 +32,7 @@ static int __ly;
 static bool __hasMouse = false;
 static bool __leftMouseDown = false;
 static bool __rightMouseDown = false;
-static bool __otherMouseDown = false;
+static bool __otherMouseDown = false;
 static bool __shiftDown = false;
 
 long getMachTimeInMilliseconds()
@@ -109,7 +109,7 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
 
 - (id) initWithFrame: (NSRect) frame
 {    
-
+
     NSOpenGLPixelFormatAttribute attrs[] = 
     {
         NSOpenGLPFAAccelerated,
@@ -125,12 +125,12 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     if (!pf)
         NSLog(@"OpenGL pixel format not supported.");
     
-    if((self = [super initWithFrame:frame pixelFormat:[pf autorelease]])) 
-    {
-        lock = [[NSRecursiveLock alloc] init];
-        _game = Game::getInstance();
-        __timeStart = getMachTimeInMilliseconds();
-    }
+    if((self = [super initWithFrame:frame pixelFormat:[pf autorelease]])) 
+    {
+        lock = [[NSRecursiveLock alloc] init];
+        _game = Game::getInstance();
+        __timeStart = getMachTimeInMilliseconds();
+    }
     
     return self;
 }
@@ -183,16 +183,16 @@ 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) 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];
@@ -220,12 +220,12 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     [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)mouseMoved:(NSEvent *) event 
+{
+    NSPoint point = [event locationInWindow];
+    Game::getInstance()->mouseEvent(Mouse::MOUSE_MOVE, point.x, WINDOW_HEIGHT - point.y, 0);
+}
+
 - (void) mouseDragged: (NSEvent*) event
 {
     NSPoint point = [event locationInWindow];
@@ -240,15 +240,15 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     __rightMouseDown = true;
      NSPoint point = [event locationInWindow];
     __lx = point.x;
-    __ly = WINDOW_HEIGHT - point.y;    
-    _game->mouseEvent(Mouse::MOUSE_PRESS_RIGHT_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
+    __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);
+    NSPoint point = [event locationInWindow];
+    _game->mouseEvent(Mouse::MOUSE_RELEASE_RIGHT_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
 }
 
 - (void) rightMouseDragged: (NSEvent*) event
@@ -268,48 +268,48 @@ 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);
-}
-
+    
+    // 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
 {
     __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)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;
+    __otherMouseDown = false;
     __hasMouse = false;
 }
 
@@ -525,28 +525,28 @@ int getKey(unsigned short keyCode, unsigned int modifierFlags)
             _game->keyEvent((flags & NSAlphaShiftKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_CAPS_LOCK);
             break;
         case 0x38:
-            _game->keyEvent((flags & NSShiftKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_SHIFT);
+            _game->keyEvent((flags & NSShiftKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_SHIFT);
             break;
         case 0x3C:
-            _game->keyEvent((flags & NSShiftKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_SHIFT);
+            _game->keyEvent((flags & NSShiftKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_SHIFT);
             break;
         case 0x3A:
-            _game->keyEvent((flags & NSAlternateKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_ALT);
+            _game->keyEvent((flags & NSAlternateKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_ALT);
             break;
         case 0x3D:
-            _game->keyEvent((flags & NSAlternateKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_ALT);
+            _game->keyEvent((flags & NSAlternateKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_ALT);
             break;
         case 0x3B:
-            _game->keyEvent((flags & NSControlKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_CTRL);
+            _game->keyEvent((flags & NSControlKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_CTRL);
             break;
         case 0x3E:
-            _game->keyEvent((flags & NSControlKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_CTRL);
+            _game->keyEvent((flags & NSControlKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_CTRL);
             break;
         case 0x37:
-            _game->keyEvent((flags & NSCommandKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_HYPER);
+            _game->keyEvent((flags & NSCommandKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_HYPER);
             break;
         case 0x36:
-            _game->keyEvent((flags & NSCommandKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_HYPER);
+            _game->keyEvent((flags & NSCommandKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_HYPER);
             break;
     }
 }
@@ -600,7 +600,7 @@ Platform* Platform::create(Game* game)
 int Platform::enterMessagePump()
 {
     NSAutoreleasePool* pool = [NSAutoreleasePool new];
-    NSApplication* app = [NSApplication sharedApplication];
+    NSApplication* app = [NSApplication sharedApplication];
     NSRect screenBounds = [[NSScreen mainScreen] frame];
     NSRect viewBounds = NSMakeRect(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
     
@@ -617,27 +617,27 @@ int Platform::enterMessagePump()
                         backing:NSBackingStoreBuffered
                         defer:NO];
     
-    [window setAcceptsMouseMovedEvents:YES];
+    [window setAcceptsMouseMovedEvents:YES];
     [window setContentView:__view];
     [window setDelegate:__view];
     [__view release];
     
-    [app run];
+    [app run];
     
     [pool release];
     return EXIT_SUCCESS;
 }
-
-unsigned int Platform::getDisplayWidth()
-{
-    return WINDOW_WIDTH;
-}
-
-unsigned int Platform::getDisplayHeight()
-{
-    return WINDOW_HEIGHT;
-}
-
+
+unsigned int Platform::getDisplayWidth()
+{
+    return WINDOW_WIDTH;
+}
+
+unsigned int Platform::getDisplayHeight()
+{
+    return WINDOW_HEIGHT;
+}
+
 long Platform::getAbsoluteTime()
 {
     __timeAbsolute = getMachTimeInMilliseconds();
@@ -680,18 +680,18 @@ void Platform::displayKeyboard(bool display)
 {
     // Do nothing.
 }
-
-void Platform::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
-{
-    if (!Form::touchEventInternal(evt, x, y, contactIndex))
-    {
-        Game::getInstance()->touchEvent(evt, x, y, contactIndex);
-    }
+
+void Platform::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
+{
+    if (!Form::touchEventInternal(evt, x, y, contactIndex))
+    {
+        Game::getInstance()->touchEvent(evt, x, y, contactIndex);
+    }
 }
 
-void Platform::sleep(long ms)
-{
-    usleep(ms * 1000);
+void Platform::sleep(long ms)
+{
+    usleep(ms * 1000);
 }
 
 }

+ 57 - 57
gameplay/src/PlatformQNX.cpp

@@ -573,70 +573,70 @@ Platform* Platform::create(Game* game)
         goto error;
     }
 
-	screen_display_t screen_display;
+    screen_display_t screen_display;
     rc = screen_get_window_property_pv(__screenWindow, SCREEN_PROPERTY_DISPLAY, (void **)&screen_display);
     if (rc)
     {
-    	perror("screen_get_window_property_pv(SCREEN_PROPERTY_DISPLAY)");
-    	goto error;
+        perror("screen_get_window_property_pv(SCREEN_PROPERTY_DISPLAY)");
+        goto error;
     }
 
-	screen_display_mode_t screen_mode;
-	rc = screen_get_display_property_pv(screen_display, SCREEN_PROPERTY_MODE, (void**)&screen_mode);
-	if (rc)
-	{
-		perror("screen_get_display_property_pv(SCREEN_PROPERTY_MODE)");
-		goto error;
-	}
+    screen_display_mode_t screen_mode;
+    rc = screen_get_display_property_pv(screen_display, SCREEN_PROPERTY_MODE, (void**)&screen_mode);
+    if (rc)
+    {
+        perror("screen_get_display_property_pv(SCREEN_PROPERTY_MODE)");
+        goto error;
+    }
 
     int size[2];
-	rc = screen_get_window_property_iv(__screenWindow, SCREEN_PROPERTY_BUFFER_SIZE, size);
-	if (rc)
-	{
-		perror("screen_get_window_property_iv(SCREEN_PROPERTY_BUFFER_SIZE)");
-		goto error;
-	}
-
-	__screenWindowSize[0] = size[0];
-	__screenWindowSize[1] = size[1];
-
-	if ((angle == 0) || (angle == 180))
-	{
-		if (((screen_mode.width > screen_mode.height) && (size[0] < size[1])) ||
-			((screen_mode.width < screen_mode.height) && (size[0] > size[1])))
-		{
-			__screenWindowSize[1] = size[0];
-			__screenWindowSize[0] = size[1];
-		}
-	}
-	else if ((angle == 90) || (angle == 270))
-	{
-		if (((screen_mode.width > screen_mode.height) && (size[0] > size[1])) ||
-			((screen_mode.width < screen_mode.height) && (size[0] < size[1])))
-		{
-			__screenWindowSize[1] = size[0];
-			__screenWindowSize[0] = size[1];
-		}
-	}
-	else
-	{
-		perror("Navigator returned an unexpected orientation angle.");
-		goto error;
-	}
-
-	rc = screen_set_window_property_iv(__screenWindow, SCREEN_PROPERTY_BUFFER_SIZE, __screenWindowSize);
-	if (rc)
-	{
-		perror("screen_set_window_property_iv(SCREEN_PROPERTY_BUFFER_SIZE)");
-		goto error;
-	}
-
-	rc = screen_set_window_property_iv(__screenWindow, SCREEN_PROPERTY_ROTATION, &angle);
-	if (rc)
-	{
-		perror("screen_set_window_property_iv(SCREEN_PROPERTY_ROTATION)");
-		goto error;
-	}
+    rc = screen_get_window_property_iv(__screenWindow, SCREEN_PROPERTY_BUFFER_SIZE, size);
+    if (rc)
+    {
+        perror("screen_get_window_property_iv(SCREEN_PROPERTY_BUFFER_SIZE)");
+        goto error;
+    }
+
+    __screenWindowSize[0] = size[0];
+    __screenWindowSize[1] = size[1];
+
+    if ((angle == 0) || (angle == 180))
+    {
+        if (((screen_mode.width > screen_mode.height) && (size[0] < size[1])) ||
+            ((screen_mode.width < screen_mode.height) && (size[0] > size[1])))
+        {
+            __screenWindowSize[1] = size[0];
+            __screenWindowSize[0] = size[1];
+        }
+    }
+    else if ((angle == 90) || (angle == 270))
+    {
+        if (((screen_mode.width > screen_mode.height) && (size[0] > size[1])) ||
+            ((screen_mode.width < screen_mode.height) && (size[0] < size[1])))
+        {
+            __screenWindowSize[1] = size[0];
+            __screenWindowSize[0] = size[1];
+        }
+    }
+    else
+    {
+        perror("Navigator returned an unexpected orientation angle.");
+        goto error;
+    }
+
+    rc = screen_set_window_property_iv(__screenWindow, SCREEN_PROPERTY_BUFFER_SIZE, __screenWindowSize);
+    if (rc)
+    {
+        perror("screen_set_window_property_iv(SCREEN_PROPERTY_BUFFER_SIZE)");
+        goto error;
+    }
+
+    rc = screen_set_window_property_iv(__screenWindow, SCREEN_PROPERTY_ROTATION, &angle);
+    if (rc)
+    {
+        perror("screen_set_window_property_iv(SCREEN_PROPERTY_ROTATION)");
+        goto error;
+    }
 
     if (windowPosition[0] != 0 || windowPosition[1] != 0)
     {

+ 3 - 3
gameplay/src/PlatformWin32.cpp

@@ -290,7 +290,7 @@ LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
     case WM_LBUTTONDOWN:
         if (!gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_PRESS_LEFT_BUTTON, LOWORD(lParam), HIWORD(lParam), 0))
         {
-	        gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_PRESS, LOWORD(lParam), HIWORD(lParam), 0);
+            gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_PRESS, LOWORD(lParam), HIWORD(lParam), 0);
         }
         lMouseDown = true;
         return 0;
@@ -299,7 +299,7 @@ LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
         lMouseDown = false;
         if (!gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_RELEASE_LEFT_BUTTON, LOWORD(lParam), HIWORD(lParam), 0))
         {
-	        gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_RELEASE, LOWORD(lParam), HIWORD(lParam), 0);
+            gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_RELEASE, LOWORD(lParam), HIWORD(lParam), 0);
         }
         return 0;
 
@@ -380,7 +380,7 @@ LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 
         // Suppress key repeats
         if ((lParam & 0x40000000) == 0)
-	        gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_PRESS, getKey(wParam, shiftDown ^ capsOn));
+            gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_PRESS, getKey(wParam, shiftDown ^ capsOn));
         break;
         
     case WM_KEYUP:

+ 4 - 4
gameplay/src/Rectangle.cpp

@@ -44,18 +44,18 @@ void Rectangle::set(const Rectangle& r)
     set(r.x, r.y, r.width, r.height);
 }
 
-void Rectangle::set(float x, float y)
+void Rectangle::set(float x, float y, float width, float height)
 {
     this->x = x;
     this->y = y;
+    this->width = width;
+    this->height = height;
 }
 
-void Rectangle::set(float x, float y, float width, float height)
+void Rectangle::setPosition(float x, float y)
 {
     this->x = x;
     this->y = y;
-    this->width = width;
-    this->height = height;
 }
 
 float Rectangle::left() const

+ 7 - 7
gameplay/src/Rectangle.h

@@ -92,19 +92,19 @@ public:
     void set(float x, float y, float width, float height);
 
     /**
-     * Sets the x-coordinate and y-coordinate values of this rectangle to the specified values.
+     * Sets the values of this rectangle to those in the specified rectangle.
      *
-     * @param x The x-coordinate of the rectangle.
-     * @param y The y-coordinate of the rectangle.
+     * @param r The rectangle to copy.
      */
-    void set(float x, float y);
+    void set(const Rectangle& r);
 
     /**
-     * Sets the values of this rectangle to those in the specified rectangle.
+     * Sets the x-coordinate and y-coordinate values of this rectangle to the specified values.
      *
-     * @param r The rectangle to copy.
+     * @param x The x-coordinate of the rectangle.
+     * @param y The y-coordinate of the rectangle.
      */
-    void set(const Rectangle& r);
+    void setPosition(float x, float y);
 
     /**
      * Returns the x-coordinate of the left side of the rectangle.

+ 145 - 155
gameplay/src/Scene.cpp

@@ -270,16 +270,6 @@ void Scene::bindAudioListenerToCamera(bool bind)
     }
 }
 
-const Viewport& Scene::getViewport() const
-{
-    return _viewport;
-}
-
-void Scene::setViewport(const Viewport& viewport)
-{
-    _viewport = viewport;
-}
-
 const Vector3& Scene::getAmbientColor() const
 {
     return _ambientColor;
@@ -292,38 +282,38 @@ void Scene::setAmbientColor(float red, float green, float blue)
 
 Material* createDebugMaterial()
 {
-	// Vertex shader for drawing colored lines.
-	const char* vs_str = 
-	{
-		"uniform mat4 u_viewProjectionMatrix;\n"
-		"attribute vec4 a_position;\n"
-		"attribute vec4 a_color;\n"
-		"varying vec4 v_color;\n"
-		"void main(void) {\n"
-		"    v_color = a_color;\n"
-		"    gl_Position = u_viewProjectionMatrix * a_position;\n"
-		"}"
-	};
-
-	// Fragment shader for drawing colored lines.
-	const char* fs_str = 
-	{
-	#ifdef OPENGL_ES
-		"precision highp float;\n"
-	#endif
-		"varying vec4 v_color;\n"
-		"void main(void) {\n"
-		"   gl_FragColor = v_color;\n"
-		"}"
-	};
-
-	Effect* effect = Effect::createFromSource(vs_str, fs_str);
-	Material* material = Material::create(effect);
-	material->getStateBlock()->setDepthTest(true);
-
-	SAFE_RELEASE(effect);
-
-	return material;
+    // Vertex shader for drawing colored lines.
+    const char* vs_str = 
+    {
+        "uniform mat4 u_viewProjectionMatrix;\n"
+        "attribute vec4 a_position;\n"
+        "attribute vec4 a_color;\n"
+        "varying vec4 v_color;\n"
+        "void main(void) {\n"
+        "    v_color = a_color;\n"
+        "    gl_Position = u_viewProjectionMatrix * a_position;\n"
+        "}"
+    };
+
+    // Fragment shader for drawing colored lines.
+    const char* fs_str = 
+    {
+    #ifdef OPENGL_ES
+        "precision highp float;\n"
+    #endif
+        "varying vec4 v_color;\n"
+        "void main(void) {\n"
+        "   gl_FragColor = v_color;\n"
+        "}"
+    };
+
+    Effect* effect = Effect::createFromSource(vs_str, fs_str);
+    Material* material = Material::create(effect);
+    material->getStateBlock()->setDepthTest(true);
+
+    SAFE_RELEASE(effect);
+
+    return material;
 }
 
 struct DebugVertex
@@ -339,7 +329,7 @@ void drawDebugLine(MeshBatch* batch, const Vector3& point1, const Vector3& point
     verts[0].x = point1.x;
     verts[0].y = point1.y;
     verts[0].z = point1.z;
-	verts[0].r = color.x;
+    verts[0].r = color.x;
     verts[0].g = color.y;
     verts[0].b = color.z;
     verts[0].a = 1.0f;
@@ -352,7 +342,7 @@ void drawDebugLine(MeshBatch* batch, const Vector3& point1, const Vector3& point
     verts[1].b = color.z;
     verts[1].a = 1.0f;
 
-	batch->add(verts, 2);
+    batch->add(verts, 2);
 }
 
 #define DEBUG_BOX_COLOR Vector3(0, 1, 0)
@@ -360,141 +350,141 @@ void drawDebugLine(MeshBatch* batch, const Vector3& point1, const Vector3& point
 
 void drawDebugBox(MeshBatch* batch, const BoundingBox& box, const Matrix& matrix)
 {
-	// Transform box into world space (since we only store local boxes on mesh)
-	BoundingBox worldSpaceBox(box);
-	worldSpaceBox.transform(matrix);
+    // Transform box into world space (since we only store local boxes on mesh)
+    BoundingBox worldSpaceBox(box);
+    worldSpaceBox.transform(matrix);
 
-	// Get box corners
+    // Get box corners
     static Vector3 corners[8];
     worldSpaceBox.getCorners(corners);
 
-	// Draw box lines
-	drawDebugLine(batch, corners[0], corners[1], DEBUG_BOX_COLOR);
-	drawDebugLine(batch, corners[1], corners[2], DEBUG_BOX_COLOR);
-	drawDebugLine(batch, corners[2], corners[3], DEBUG_BOX_COLOR);
-	drawDebugLine(batch, corners[3], corners[0], DEBUG_BOX_COLOR);
-	drawDebugLine(batch, corners[4], corners[5], DEBUG_BOX_COLOR);
-	drawDebugLine(batch, corners[5], corners[6], DEBUG_BOX_COLOR);
-	drawDebugLine(batch, corners[6], corners[7], DEBUG_BOX_COLOR);
-	drawDebugLine(batch, corners[7], corners[4], DEBUG_BOX_COLOR);
-	drawDebugLine(batch, corners[0], corners[7], DEBUG_BOX_COLOR);
-	drawDebugLine(batch, corners[1], corners[6], DEBUG_BOX_COLOR);
-	drawDebugLine(batch, corners[2], corners[5], DEBUG_BOX_COLOR);
-	drawDebugLine(batch, corners[3], corners[4], DEBUG_BOX_COLOR);
+    // Draw box lines
+    drawDebugLine(batch, corners[0], corners[1], DEBUG_BOX_COLOR);
+    drawDebugLine(batch, corners[1], corners[2], DEBUG_BOX_COLOR);
+    drawDebugLine(batch, corners[2], corners[3], DEBUG_BOX_COLOR);
+    drawDebugLine(batch, corners[3], corners[0], DEBUG_BOX_COLOR);
+    drawDebugLine(batch, corners[4], corners[5], DEBUG_BOX_COLOR);
+    drawDebugLine(batch, corners[5], corners[6], DEBUG_BOX_COLOR);
+    drawDebugLine(batch, corners[6], corners[7], DEBUG_BOX_COLOR);
+    drawDebugLine(batch, corners[7], corners[4], DEBUG_BOX_COLOR);
+    drawDebugLine(batch, corners[0], corners[7], DEBUG_BOX_COLOR);
+    drawDebugLine(batch, corners[1], corners[6], DEBUG_BOX_COLOR);
+    drawDebugLine(batch, corners[2], corners[5], DEBUG_BOX_COLOR);
+    drawDebugLine(batch, corners[3], corners[4], DEBUG_BOX_COLOR);
 }
 
 void drawDebugSphere(MeshBatch* batch, const BoundingSphere& sphere)
 {
-	// Draw three rings for the sphere (one for the x, y and z axes)
-	Vector3 pos1, pos2;
-	float step = MATH_PI * 0.2f;
-	float max = MATH_PIX2 + step;
-
-	// X ring
-	for (float r = 0.0f; r < max; r += step)
-	{
-		pos2.x = sphere.center.x;
-		pos2.y = sphere.center.y + std::cos(r) * sphere.radius;
-		pos2.z = sphere.center.z + std::sin(r) * sphere.radius;
-
-		if (r > 0)
-			drawDebugLine(batch, pos1, pos2, DEBUG_SPHERE_COLOR);
-
-		pos1 = pos2;
-	}
-
-	// Y ring
-	for (float r = 0.0f; r < max; r += step)
-	{
-		pos2.x = sphere.center.x + std::cos(r) * sphere.radius;
-		pos2.y = sphere.center.y;
-		pos2.z = sphere.center.z + std::sin(r) * sphere.radius;
-
-		if (r > 0)
-			drawDebugLine(batch, pos1, pos2, DEBUG_SPHERE_COLOR);
-
-		pos1 = pos2;
-	}
-
-	// Z ring
-	for (float r = 0.0f; r < max; r += step)
-	{
-		pos2.x = sphere.center.x + std::cos(r) * sphere.radius;
-		pos2.y = sphere.center.y + std::sin(r) * sphere.radius;
-		pos2.z = sphere.center.z;
-
-		if (r > 0)
-			drawDebugLine(batch, pos1, pos2, DEBUG_SPHERE_COLOR);
-
-		pos1 = pos2;
-	}
+    // Draw three rings for the sphere (one for the x, y and z axes)
+    Vector3 pos1, pos2;
+    float step = MATH_PI * 0.2f;
+    float max = MATH_PIX2 + step;
+
+    // X ring
+    for (float r = 0.0f; r < max; r += step)
+    {
+        pos2.x = sphere.center.x;
+        pos2.y = sphere.center.y + std::cos(r) * sphere.radius;
+        pos2.z = sphere.center.z + std::sin(r) * sphere.radius;
+
+        if (r > 0)
+            drawDebugLine(batch, pos1, pos2, DEBUG_SPHERE_COLOR);
+
+        pos1 = pos2;
+    }
+
+    // Y ring
+    for (float r = 0.0f; r < max; r += step)
+    {
+        pos2.x = sphere.center.x + std::cos(r) * sphere.radius;
+        pos2.y = sphere.center.y;
+        pos2.z = sphere.center.z + std::sin(r) * sphere.radius;
+
+        if (r > 0)
+            drawDebugLine(batch, pos1, pos2, DEBUG_SPHERE_COLOR);
+
+        pos1 = pos2;
+    }
+
+    // Z ring
+    for (float r = 0.0f; r < max; r += step)
+    {
+        pos2.x = sphere.center.x + std::cos(r) * sphere.radius;
+        pos2.y = sphere.center.y + std::sin(r) * sphere.radius;
+        pos2.z = sphere.center.z;
+
+        if (r > 0)
+            drawDebugLine(batch, pos1, pos2, DEBUG_SPHERE_COLOR);
+
+        pos1 = pos2;
+    }
 }
 
 void drawDebugNode(MeshBatch* batch, Node* node, unsigned int debugFlags)
 {
-	Model* model = node->getModel();
-
-	if ((debugFlags & Scene::DEBUG_BOXES) && model)
-	{
-		MeshSkin* skin = model->getSkin();
-		if (skin && skin->getRootJoint()->getParent())
-		{
-			// For skinned meshes that have a parent node to the skin's root joint,
-			// we need to transform the bounding volume by that parent node's transform
-			// as well to get the full skinned bounding volume.
-			drawDebugBox(batch, model->getMesh()->getBoundingBox(), node->getWorldMatrix() * skin->getRootJoint()->getParent()->getWorldMatrix());
-		}
-		else
-		{
-			drawDebugBox(batch, model->getMesh()->getBoundingBox(), node->getWorldMatrix());
-		}
-	}
-
-	if ((debugFlags & Scene::DEBUG_SPHERES) && model)
-	{
-		drawDebugSphere(batch, node->getBoundingSphere());
-	}
-
-	Node* child = node->getFirstChild();
-	while (child)
-	{
-		drawDebugNode(batch, child, debugFlags);
-		child = child->getNextSibling();
-	}
+    Model* model = node->getModel();
+
+    if ((debugFlags & Scene::DEBUG_BOXES) && model)
+    {
+        MeshSkin* skin = model->getSkin();
+        if (skin && skin->getRootJoint()->getParent())
+        {
+            // For skinned meshes that have a parent node to the skin's root joint,
+            // we need to transform the bounding volume by that parent node's transform
+            // as well to get the full skinned bounding volume.
+            drawDebugBox(batch, model->getMesh()->getBoundingBox(), node->getWorldMatrix() * skin->getRootJoint()->getParent()->getWorldMatrix());
+        }
+        else
+        {
+            drawDebugBox(batch, model->getMesh()->getBoundingBox(), node->getWorldMatrix());
+        }
+    }
+
+    if ((debugFlags & Scene::DEBUG_SPHERES) && model)
+    {
+        drawDebugSphere(batch, node->getBoundingSphere());
+    }
+
+    Node* child = node->getFirstChild();
+    while (child)
+    {
+        drawDebugNode(batch, child, debugFlags);
+        child = child->getNextSibling();
+    }
 }
 
 void Scene::drawDebug(unsigned int debugFlags)
 {
-	if (_debugBatch == NULL)
-	{
-		Material* material = createDebugMaterial();
+    if (_debugBatch == NULL)
+    {
+        Material* material = createDebugMaterial();
 
-		VertexFormat::Element elements[] =
-		{
-			VertexFormat::Element(VertexFormat::POSITION, 3),
-			VertexFormat::Element(VertexFormat::COLOR, 4)
-		};
+        VertexFormat::Element elements[] =
+        {
+            VertexFormat::Element(VertexFormat::POSITION, 3),
+            VertexFormat::Element(VertexFormat::COLOR, 4)
+        };
 
-		_debugBatch = MeshBatch::create(VertexFormat(elements, 2), Mesh::LINES, material, false);
+        _debugBatch = MeshBatch::create(VertexFormat(elements, 2), Mesh::LINES, material, false);
 
-		SAFE_RELEASE(material);
-	}
+        SAFE_RELEASE(material);
+    }
 
-	_debugBatch->begin();
+    _debugBatch->begin();
 
-	Node* node = _firstNode;
-	while (node)
-	{
-		drawDebugNode(_debugBatch, node, debugFlags);
-		node = node->_nextSibling;
-	}
+    Node* node = _firstNode;
+    while (node)
+    {
+        drawDebugNode(_debugBatch, node, debugFlags);
+        node = node->_nextSibling;
+    }
 
-	_debugBatch->end();
+    _debugBatch->end();
 
-	if (_activeCamera)
-		_debugBatch->getMaterial()->getParameter("u_viewProjectionMatrix")->setValue(_activeCamera->getViewProjectionMatrix());
+    if (_activeCamera)
+        _debugBatch->getMaterial()->getParameter("u_viewProjectionMatrix")->setValue(_activeCamera->getViewProjectionMatrix());
 
-	_debugBatch->draw();
+    _debugBatch->draw();
 }
 
 }

+ 16 - 31
gameplay/src/Scene.h

@@ -14,14 +14,14 @@ class Scene : public Ref
 {
 public:
 
-	/**
-	 * Enumeration of supported scene debug flags for debug drawing.
-	 */
-	enum DebugFlags
-	{
-		DEBUG_BOXES = 1,
-		DEBUG_SPHERES = 2
-	};
+    /**
+     * Enumeration of supported scene debug flags for debug drawing.
+     */
+    enum DebugFlags
+    {
+        DEBUG_BOXES = 1,
+        DEBUG_SPHERES = 2
+    };
 
     /**
      * Creates a new empty scene.
@@ -142,20 +142,6 @@ public:
      */
     void bindAudioListenerToCamera(bool bind);
 
-    /**
-     * Gets the viewport for the scene.
-     *
-     * @return The scene's viewport.
-     */
-    const Viewport& getViewport() const;
-
-    /**
-     * Sets the scene's viewport.
-     *
-     * @param viewport The viewport to be set for this scene.
-     */
-    void setViewport(const Viewport& viewport);
-
     /**
      * Returns the ambient color of the scene. Black is the default color.
      * 
@@ -190,13 +176,13 @@ public:
     template <class T>
     void visit(T* instance, bool (T::*visitMethod)(Node*,void*), void* cookie = 0);
 
-	/**
-	 * Draws debugging information (bounding volumes, etc.) for the scene.
-	 *
-	 * @param debugFlags Bitwise combination of debug flags from mthe DebugFlags 
-	 *		enumeration, specifying which debugging information to draw.
-	 */
-	void drawDebug(unsigned int debugFlags);
+    /**
+     * Draws debugging information (bounding volumes, etc.) for the scene.
+     *
+     * @param debugFlags Bitwise combination of debug flags from mthe DebugFlags 
+     *        enumeration, specifying which debugging information to draw.
+     */
+    void drawDebug(unsigned int debugFlags);
 
 private:
 
@@ -223,13 +209,12 @@ private:
 
     std::string _id;
     Camera* _activeCamera;
-    Viewport _viewport;
     Node* _firstNode;
     Node* _lastNode;
     unsigned int _nodeCount;
     Vector3 _ambientColor;
     bool _bindAudioListenerToCamera;
-	MeshBatch* _debugBatch;
+    MeshBatch* _debugBatch;
 };
 
 template <class T>

+ 21 - 11
gameplay/src/SceneLoader.cpp

@@ -61,7 +61,8 @@ Scene* SceneLoader::load(const char* filePath)
         SceneNodeProperty::PARTICLE |
         SceneNodeProperty::ROTATE |
         SceneNodeProperty::SCALE |
-        SceneNodeProperty::TRANSLATE);
+        SceneNodeProperty::TRANSLATE | 
+        SceneNodeProperty::TRANSPARENT);
     applyNodeProperties(scene, sceneProperties, SceneNodeProperty::CHARACTER | SceneNodeProperty::GHOST | SceneNodeProperty::RIGIDBODY);
     createAnimations(scene);
 
@@ -311,22 +312,22 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
                             Model* model = node->getModel();
                         
                             // Up ref count to prevent node from releasing the model when we swap it.
-						    model->addRef(); 
+                            model->addRef(); 
                         
-						    // Create collision object with new rigidbodymodel set.
+                            // Create collision object with new rigidbodymodel set.
                             node->setModel(modelNode->getModel());
-						    node->setCollisionObject(p);
+                            node->setCollisionObject(p);
 
-						    // Restore original model.
+                            // Restore original model.
                             node->setModel(model);
-						
+                        
                             // Decrement temporarily added reference.
                             model->release();
                         }
                     }
                 }
                 else
-				    node->setCollisionObject(p);
+                    node->setCollisionObject(p);
             }
             break;
         }
@@ -364,6 +365,11 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
                 node->setScale(s);
             break;
         }
+        case SceneNodeProperty::TRANSPARENT:
+        {
+            node->setTransparent(true);
+            break;
+        }
         default:
             WARN_VARG("Unsupported node property type: %d.", snp._type);
             break;
@@ -572,6 +578,10 @@ void SceneLoader::buildReferenceTables(Properties* sceneProperties)
                 {
                     addSceneNodeProperty(sceneNode, SceneNodeProperty::SCALE);
                 }
+                else if (strcmp(name, "transparent") == 0)
+                {
+                    addSceneNodeProperty(sceneNode, SceneNodeProperty::TRANSPARENT);
+                }
                 else
                 {
                     WARN_VARG("Unsupported node property: %s = %s", name, ns->getString());
@@ -804,12 +814,12 @@ void SceneLoader::loadPhysics(Properties* physics, Scene* scene)
                 WARN_VARG("Node '%s' to be used as 'rigidBodyA' for constraint %s cannot be found.", name, constraint->getId());
                 continue;
             }
-			if (!rbANode->getCollisionObject() || rbANode->getCollisionObject()->getType() != PhysicsCollisionObject::RIGID_BODY)
+            if (!rbANode->getCollisionObject() || rbANode->getCollisionObject()->getType() != PhysicsCollisionObject::RIGID_BODY)
             {
                 WARN_VARG("Node '%s' to be used as 'rigidBodyA' does not have a rigid body.", name);
                 continue;
             }
-			PhysicsRigidBody* rbA = static_cast<PhysicsRigidBody*>(rbANode->getCollisionObject());
+            PhysicsRigidBody* rbA = static_cast<PhysicsRigidBody*>(rbANode->getCollisionObject());
 
             // Attempt to load the second rigid body. If the second rigid body is not
             // specified, that is usually okay (only spring constraints require both and
@@ -825,12 +835,12 @@ void SceneLoader::loadPhysics(Properties* physics, Scene* scene)
                     WARN_VARG("Node '%s' to be used as 'rigidBodyB' for constraint %s cannot be found.", name, constraint->getId());
                     continue;
                 }
-				if (!rbBNode->getCollisionObject() || rbBNode->getCollisionObject()->getType() != PhysicsCollisionObject::RIGID_BODY)
+                if (!rbBNode->getCollisionObject() || rbBNode->getCollisionObject()->getType() != PhysicsCollisionObject::RIGID_BODY)
                 {
                     WARN_VARG("Node '%s' to be used as 'rigidBodyB' does not have a rigid body.", name);
                     continue;
                 }
-				rbB = static_cast<PhysicsRigidBody*>(rbBNode->getCollisionObject());
+                rbB = static_cast<PhysicsRigidBody*>(rbBNode->getCollisionObject());
             }
 
             PhysicsConstraint* physicsConstraint = NULL;

+ 4 - 3
gameplay/src/SceneLoader.h

@@ -16,8 +16,8 @@ namespace gameplay
  * @todo Add support for loading ghost objects and characters for nodes.
  * @todo Add support for explicitly specifying collision shapes for rigid bodies/ghost objects/characters.
  * @todo Consider supporting 'rigidbodymodel' on models/meshes that are not part of the scene to allow
- *		mesh data to be exported from a modelling tool for the sole purpose of representing a physics
- *		rigid body, but not have it get loaded into the scene and rendering context.
+ *        mesh data to be exported from a modelling tool for the sole purpose of representing a physics
+ *        rigid body, but not have it get loaded into the scene and rendering context.
  */
 class SceneLoader
 {
@@ -55,7 +55,8 @@ private:
             TRANSLATE = 64,
             ROTATE = 128,
             SCALE = 256,
-            URL = 512
+            URL = 512,
+            TRANSPARENT = 1024
         };
 
         SceneNodeProperty(Type type, std::string file, std::string id, int index) : _type(type), _file(file), _id(id), _index(index) { }

+ 69 - 0
gameplay/src/ScreenDisplayer.h

@@ -0,0 +1,69 @@
+#ifndef SCREENDISPLAYER_H_
+#define SCREENDISPLAYER_H_
+
+#include "Game.h"
+#include "Platform.h"
+
+namespace gameplay
+{
+
+/**
+ * Used for displaying screens (i.e. splash or level loading screens).
+ */
+class ScreenDisplayer
+{
+public:
+
+    /**
+     * Displays a screen using the {@link Game#renderOnce} mechanism for at least the given amount of time.
+     * 
+     * @param instance See {@link Game#renderOnce}.
+     * @param method See {@link Game#renderOnce}.
+     * @param cookie See {@link Game#renderOnce}.
+     * @param time The minimum amount of time to display the screen (in milliseconds).
+     */
+    template <typename T> void run(T* instance, void (T::*method) (void*), void* cookie, long time);
+
+    /**
+     * Destructor.
+     */
+    ~ScreenDisplayer();
+
+private:
+
+    long _time;
+    long _startTime;
+};
+
+template <typename T> void ScreenDisplayer::run(T* instance, void (T::*method) (void*), void* cookie, long time)
+{
+    _time = time;
+    Game::getInstance()->renderOnce(instance, method, cookie);
+    _startTime = Game::getInstance()->getGameTime();
+}
+
+inline ScreenDisplayer::~ScreenDisplayer()
+{
+    long elapsedTime = Game::getInstance()->getGameTime() - _startTime;
+    if (elapsedTime < _time)
+        Platform::sleep(_time - (Game::getInstance()->getGameTime() - _startTime));
+}
+
+/**
+ * Displays a screen using the {@link Game#renderOnce} mechanism for at least the given amount
+ * of time. This function is intended to be called at the beginning of a block of code that is be 
+ * executed while the screen is displayed (i.e. Game#initialize). This function will block 
+ * at the end of the block of code in which it is called for the amount of time that has not yet elapsed.
+ * 
+ * @param instance See {@link Game#renderOnce}.
+ * @param method See {@link Game#renderOnce}.
+ * @param cookie See {@link Game#renderOnce}.
+ * @param time The minimum amount of time to display the screen (in milliseconds).
+ */
+#define displayScreen(instance, method, cookie, time) \
+    ScreenDisplayer __##instance##ScreenDisplayer; \
+    __##instance##ScreenDisplayer.run(instance, method, cookie, time)
+
+}
+
+#endif

+ 127 - 127
gameplay/src/Texture.cpp

@@ -73,15 +73,15 @@ Texture* Texture::create(const char* path, bool generateMipmaps)
                     texture = create(image, generateMipmaps);
                 SAFE_RELEASE(image);
             }
-			else if (tolower(ext[1]) == 'p' && tolower(ext[2]) == 'v' && tolower(ext[3]) == 'r')
-			{
+            else if (tolower(ext[1]) == 'p' && tolower(ext[2]) == 'v' && tolower(ext[3]) == 'r')
+            {
 #ifdef OPENGL_ES_PVR
-            	// PowerVR Compressed RGBA
-				texture = createCompressedPVR(path);
+                // PowerVR Compressed RGBA
+                texture = createCompressedPVR(path);
 #else
                 texture = NULL; // Cannot handle PVR if not supported on platform
 #endif
-			}
+            }
             break;
         }
     }
@@ -150,134 +150,134 @@ Texture* Texture::create(Format format, unsigned int width, unsigned int height,
 #ifdef OPENGL_ES_PVR
 Texture* Texture::createCompressedPVR(const char* path)
 {
-	char PVRTexIdentifier[] = "PVR!";
-
-	enum
-	{
-	    PVRTextureFlagTypePVRTC_2 = 24,
-	    PVRTextureFlagTypePVRTC_4
-	};
-
-	struct pvr_file_header
-	{
-		unsigned int size;          		// size of the structure
-		unsigned int height;              	// height of surface to be created
-		unsigned int width;               	// width of input surface
-		unsigned int mipmapCount;         	// number of mip-map levels requested
-		unsigned int formatflags;           // pixel format flags
-		unsigned int dataSize;     			// total size in bytes
-		unsigned int bpp;            		// number of bits per pixel
-		unsigned int redBitMask;            // mask for red bit
-		unsigned int greenBitMask;          // mask for green bits
-		unsigned int blueBitMask;           // mask for blue bits
-		unsigned int alphaBitMask;        	// mask for alpha channel
-		unsigned int pvrTag;                // magic number identifying pvr file
-		unsigned int surfaceCount;          // number of surfaces present in the pvr
-	} ;
-
-	FILE* file = FileSystem::openFile(path, "rb");
-	if (file == NULL)
-	{
-		LOG_ERROR_VARG("Failed to load file: %s", path);
-		return NULL;
-	}
-
-	// Read the file header
-	unsigned int size = sizeof(pvr_file_header);
-	pvr_file_header header;
-	unsigned int read = (int)fread(&header, 1, size, file);
-	assert(read == size);
-	if (read != size)
-	{
-		LOG_ERROR_VARG("Read file header error for pvr file: %s (%d < %d)", path, (int)read, (int)size);
-		fclose(file);
-		return NULL;
-	}
-
-	// Proper file header identifier
-	if (PVRTexIdentifier[0] != (char)((header.pvrTag >>  0) & 0xff) ||
-		PVRTexIdentifier[1] != (char)((header.pvrTag >>  8) & 0xff) ||
-	    PVRTexIdentifier[2] != (char)((header.pvrTag >> 16) & 0xff) ||
-	    PVRTexIdentifier[3] != (char)((header.pvrTag >> 24) & 0xff))
-	 {
-		LOG_ERROR_VARG("Invalid PVR texture file: %s", path);
-		fclose(file);
-	    return NULL;
-	}
-
-	// Format flags for GLenum format
-	GLenum format;
-	unsigned int formatFlags = header.formatflags & 0xff;
-	if (formatFlags == PVRTextureFlagTypePVRTC_4)
-	{
-		format = header.alphaBitMask ? COMPRESSED_RGBA_PVRTC_4BPP : COMPRESSED_RGB_PVRTC_4BPP;
-	}
-	else if (formatFlags == PVRTextureFlagTypePVRTC_2)
-	{
-		format = header.alphaBitMask ? COMPRESSED_RGBA_PVRTC_2BPP : COMPRESSED_RGB_PVRTC_2BPP;
-	}
-	else
-	{
-		LOG_ERROR_VARG("Invalid PVR texture format flags for file: %s", path);
-		fclose(file);
-		return NULL;
-	}
-
-	unsigned char* data = new unsigned char[header.dataSize];
-	read = (int)fread(data, 1, header.dataSize, file);
-	assert(read == header.dataSize);
-	if (read != header.dataSize)
-	{
-		LOG_ERROR_VARG("Read file data error for pvr file: %s (%d < %d)", path, (int)read, (int)header.dataSize);
-		SAFE_DELETE_ARRAY(data);
-		fclose(file);
-		return NULL;
-	}
-	// Close file
-	fclose(file);
-
-	// Load our texture.
-	GLuint textureId;
-	GL_ASSERT( glGenTextures(1, &textureId) );
-	GL_ASSERT( glBindTexture(GL_TEXTURE_2D, textureId) );
-	GL_ASSERT( glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, header.mipmapCount > 0 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR ) );
+    char PVRTexIdentifier[] = "PVR!";
+
+    enum
+    {
+        PVRTextureFlagTypePVRTC_2 = 24,
+        PVRTextureFlagTypePVRTC_4
+    };
+
+    struct pvr_file_header
+    {
+        unsigned int size;                  // size of the structure
+        unsigned int height;                  // height of surface to be created
+        unsigned int width;                   // width of input surface
+        unsigned int mipmapCount;             // number of mip-map levels requested
+        unsigned int formatflags;           // pixel format flags
+        unsigned int dataSize;                 // total size in bytes
+        unsigned int bpp;                    // number of bits per pixel
+        unsigned int redBitMask;            // mask for red bit
+        unsigned int greenBitMask;          // mask for green bits
+        unsigned int blueBitMask;           // mask for blue bits
+        unsigned int alphaBitMask;            // mask for alpha channel
+        unsigned int pvrTag;                // magic number identifying pvr file
+        unsigned int surfaceCount;          // number of surfaces present in the pvr
+    } ;
+
+    FILE* file = FileSystem::openFile(path, "rb");
+    if (file == NULL)
+    {
+        LOG_ERROR_VARG("Failed to load file: %s", path);
+        return NULL;
+    }
+
+    // Read the file header
+    unsigned int size = sizeof(pvr_file_header);
+    pvr_file_header header;
+    unsigned int read = (int)fread(&header, 1, size, file);
+    assert(read == size);
+    if (read != size)
+    {
+        LOG_ERROR_VARG("Read file header error for pvr file: %s (%d < %d)", path, (int)read, (int)size);
+        fclose(file);
+        return NULL;
+    }
+
+    // Proper file header identifier
+    if (PVRTexIdentifier[0] != (char)((header.pvrTag >>  0) & 0xff) ||
+        PVRTexIdentifier[1] != (char)((header.pvrTag >>  8) & 0xff) ||
+        PVRTexIdentifier[2] != (char)((header.pvrTag >> 16) & 0xff) ||
+        PVRTexIdentifier[3] != (char)((header.pvrTag >> 24) & 0xff))
+     {
+        LOG_ERROR_VARG("Invalid PVR texture file: %s", path);
+        fclose(file);
+        return NULL;
+    }
+
+    // Format flags for GLenum format
+    GLenum format;
+    unsigned int formatFlags = header.formatflags & 0xff;
+    if (formatFlags == PVRTextureFlagTypePVRTC_4)
+    {
+        format = header.alphaBitMask ? COMPRESSED_RGBA_PVRTC_4BPP : COMPRESSED_RGB_PVRTC_4BPP;
+    }
+    else if (formatFlags == PVRTextureFlagTypePVRTC_2)
+    {
+        format = header.alphaBitMask ? COMPRESSED_RGBA_PVRTC_2BPP : COMPRESSED_RGB_PVRTC_2BPP;
+    }
+    else
+    {
+        LOG_ERROR_VARG("Invalid PVR texture format flags for file: %s", path);
+        fclose(file);
+        return NULL;
+    }
+
+    unsigned char* data = new unsigned char[header.dataSize];
+    read = (int)fread(data, 1, header.dataSize, file);
+    assert(read == header.dataSize);
+    if (read != header.dataSize)
+    {
+        LOG_ERROR_VARG("Read file data error for pvr file: %s (%d < %d)", path, (int)read, (int)header.dataSize);
+        SAFE_DELETE_ARRAY(data);
+        fclose(file);
+        return NULL;
+    }
+    // Close file
+    fclose(file);
+
+    // Load our texture.
+    GLuint textureId;
+    GL_ASSERT( glGenTextures(1, &textureId) );
+    GL_ASSERT( glBindTexture(GL_TEXTURE_2D, textureId) );
+    GL_ASSERT( glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, header.mipmapCount > 0 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR ) );
 
     Texture* texture = new Texture();
     texture->_handle = textureId;
     texture->_width = header.width;
     texture->_height = header.height;
 
-	// Load the data for each level
-	unsigned int width = header.width;
-	unsigned int height = header.height;
-	unsigned int blockSize = 0;
-	unsigned int widthBlocks = 0;
-	unsigned int heightBlocks = 0;
-	unsigned int bpp = 0;
-	unsigned int dataSize = 0;
-	unsigned char* dataOffset = data;
-
-	for (unsigned int level = 0; level <= header.mipmapCount; level++)
-	{
-		if (formatFlags == PVRTextureFlagTypePVRTC_4)
-		{
-			dataSize = ( max((int)width, 8) * max((int)height, 8) * 4 + 7) / 8;
-		}
-		else
-		{
-			dataSize = ( max((int)width, 16) * max((int)height, 8) * 2 + 7) / 8;
-		}
-
-		GL_ASSERT( glCompressedTexImage2D(GL_TEXTURE_2D, level, (GLenum)format, width, height, 0, dataSize, dataOffset) );
-
-		dataOffset += dataSize;
-		width = max((int)width >> 1, 1);
-		height = max((int)height >> 1, 1);
-	}
-
-	SAFE_DELETE_ARRAY(data);
-
-	return texture;
+    // Load the data for each level
+    unsigned int width = header.width;
+    unsigned int height = header.height;
+    unsigned int blockSize = 0;
+    unsigned int widthBlocks = 0;
+    unsigned int heightBlocks = 0;
+    unsigned int bpp = 0;
+    unsigned int dataSize = 0;
+    unsigned char* dataOffset = data;
+
+    for (unsigned int level = 0; level <= header.mipmapCount; level++)
+    {
+        if (formatFlags == PVRTextureFlagTypePVRTC_4)
+        {
+            dataSize = ( max((int)width, 8) * max((int)height, 8) * 4 + 7) / 8;
+        }
+        else
+        {
+            dataSize = ( max((int)width, 16) * max((int)height, 8) * 2 + 7) / 8;
+        }
+
+        GL_ASSERT( glCompressedTexImage2D(GL_TEXTURE_2D, level, (GLenum)format, width, height, 0, dataSize, dataOffset) );
+
+        dataOffset += dataSize;
+        width = max((int)width >> 1, 1);
+        height = max((int)height >> 1, 1);
+    }
+
+    SAFE_DELETE_ARRAY(data);
+
+    return texture;
 }
 #endif
     

+ 4 - 4
gameplay/src/Texture.h

@@ -32,9 +32,9 @@ public:
         DEPTH   = GL_DEPTH_COMPONENT,
 #ifdef OPENGL_ES_PVR
         COMPRESSED_RGB_PVRTC_4BPP = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG,
-		COMPRESSED_RGBA_PVRTC_4BPP = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG,
-		COMPRESSED_RGB_PVRTC_2BPP = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG,
-		COMPRESSED_RGBA_PVRTC_2BPP = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG
+        COMPRESSED_RGBA_PVRTC_4BPP = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG,
+        COMPRESSED_RGB_PVRTC_2BPP = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG,
+        COMPRESSED_RGBA_PVRTC_2BPP = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG
 #endif
     };
 
@@ -214,7 +214,7 @@ private:
     virtual ~Texture();
 
 #ifdef OPENGL_ES_PVR
-	static Texture* createCompressedPVR(const char* path);
+    static Texture* createCompressedPVR(const char* path);
 #endif
     
     std::string _path;

+ 2 - 2
gameplay/src/Theme.cpp

@@ -44,7 +44,7 @@ namespace gameplay
         SAFE_RELEASE(_texture);
 
         // Remove ourself from the theme cache.
-        std::vector<Theme*>::iterator itr = find(__themeCache.begin(), __themeCache.end(), this);
+        std::vector<Theme*>::iterator itr = std::find(__themeCache.begin(), __themeCache.end(), this);
         if (itr != __themeCache.end())
         {
             __themeCache.erase(itr);
@@ -1061,7 +1061,7 @@ namespace gameplay
         _cursor->_color.set(color);
     }
 
-    const Theme::UVs Theme::Style::Overlay::getCursorUVs() const
+    const Theme::UVs& Theme::Style::Overlay::getCursorUVs() const
     {
         if (_cursor)
         {

+ 1 - 1
gameplay/src/Theme.h

@@ -422,7 +422,7 @@ public:
             const Vector4& getCursorColor() const;
             void setCursorColor(const Vector4& color);
 
-            const Theme::UVs getCursorUVs() const;
+            const Theme::UVs& getCursorUVs() const;
 
             /**
              * @see AnimationTarget#getAnimationPropertyComponentCount

+ 0 - 86
gameplay/src/Viewport.cpp

@@ -1,86 +0,0 @@
-#include "Base.h"
-#include "Viewport.h"
-
-namespace gameplay
-{
-
-Viewport::Viewport()
-{
-}
-
-Viewport::Viewport(int x, int y, int width, int height)
-{
-    set(x, y, width, height);
-}
-
-Viewport::Viewport(const Viewport& viewport)
-{
-    set(viewport);
-}
-
-Viewport::~Viewport()
-{
-}
-
-void Viewport::set(int x, int y, int width, int height)
-{
-    _x = x;
-    _y = y;
-    _width = width;
-    _height = height;
-}
-
-void Viewport::set(const Viewport& viewport)
-{
-    _x = viewport._x;
-    _y = viewport._y;
-    _width = viewport._width;
-    _height = viewport._height;
-}
-
-int Viewport::getX() const
-{
-    return _x;
-}
-
-void Viewport::setX(int x)
-{
-    _x = x;
-}
-
-int Viewport::getY() const
-{
-    return _y;
-}
-
-void Viewport::setY(int y)
-{
-    _y = y;
-}
-
-int Viewport::getWidth() const
-{
-    return _width;
-}
-
-void Viewport::setWidth(int width)
-{
-    _width = width;
-}
-
-int Viewport::getHeight() const
-{
-    return _height;
-}
-
-void Viewport::setHeight(int height)
-{
-    _height = height;
-}
-
-void Viewport::bind()
-{
-    GL_ASSERT( glViewport(_x, _y, _width, _height) );
-}
-
-}

+ 0 - 132
gameplay/src/Viewport.h

@@ -1,132 +0,0 @@
-#ifndef VIEWPORT_H_
-#define VIEWPORT_H_
-
-namespace gameplay
-{
-
-class Camera;
-
-/**
- * Defines a rectangular viewing region used by camera the project into
- * and used by the GraphicsDevice to control the rendering region.
- */
-class Viewport
-{
-public:
-
-    /**
-     * Constructs a new viewport with all zeros.
-     */
-    Viewport();
-
-    /**
-     * Constructs a new viewport with the specified dimensions.
-     *
-     * @param x The x-coordinate of the viewport.
-     * @param y The y-coordinate of the viewport.
-     * @param width The width of the viewport.
-     * @param height The height of the viewport.
-     */
-    Viewport(int x, int y, int width, int height);
-
-    /**
-     * Constructs a new viewport from a copy.
-     *
-     * @param copy The viewport to copy.
-     */
-    Viewport(const Viewport& copy);
-
-    /**
-     * Destructor.
-     */
-    ~Viewport();
-
-    /**
-     * Sets the viewport to the specified dimensions.
-     *
-     * @param x The x-coordinate of the viewport.
-     * @param y The y-coordinate of the viewport.
-     * @param width The width of the viewport.
-     * @param height The height of the viewport.
-     */
-    void set(int x, int y, int width, int height);
-
-    /**
-     * Sets the viewport to the specified viewport copy.
-     *
-     * @param viewport The viewport to copy.
-     */
-    void set(const Viewport& viewport);
-
-    /**
-     * Gets the x-coordinate of the viewport.
-     *
-     * @return The x-coordinate of the viewport.
-     */
-    int getX() const;
-
-    /**
-     * Sets the x-coordinate of the viewport.
-     *
-     * @param x The x-coordinate of the viewport.
-     */
-    void setX(int x);
-
-    /**
-     * Gets the y-coordinate of the viewport.
-     *
-     * @return The y-coordinate of the viewport.
-     */
-    int getY() const;
-
-    /**
-     * Sets the y-coordinate of the viewport.
-     *
-     * @param y The y-coordinate of the viewport.
-     */
-    void setY(int y);
-
-    /**
-     * Gets the width of the viewport.
-     *
-     * @return The width of the viewport.
-     */
-    int getWidth() const;
-
-    /**
-     * Sets the width of the viewport.
-     *
-     * @param width The width of the viewport.
-     */
-    void setWidth(int width);
-
-    /**
-     * Gets the height of the viewport.
-     *
-     * @return The height of the viewport.
-     */
-    int getHeight() const;
-
-    /**
-     * Sets the height of the viewport.
-     *
-     * @param height The height of the viewport.
-     */
-    void setHeight(int height);
-
-    /**
-     * Makes this the active viewport for rendering.
-     */
-    void bind();
-
-private:
-
-    int _x;
-    int _y;
-    int _width;
-    int _height;
-};
-
-}
-
-#endif

+ 3 - 0
gameplay/src/gameplay.h

@@ -7,6 +7,7 @@
 #include "Mouse.h"
 #include "FileSystem.h"
 #include "Package.h"
+#include "ScreenDisplayer.h"
 
 // Math
 #include "Rectangle.h"
@@ -69,6 +70,8 @@
 #include "PhysicsCollisionObject.h"
 #include "PhysicsRigidBody.h"
 #include "PhysicsCharacter.h"
+#include "PhysicsCollisionShape.h"
+#include "PhysicsGhostObject.h"
 
 // UI
 #include "Theme.h"