Procházet zdrojové kódy

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

Adam Blake před 13 roky
rodič
revize
066e114f3e

+ 55 - 10
gameplay-encoder/src/FBXSceneEncoder.cpp

@@ -249,13 +249,13 @@ void FBXSceneEncoder::loadScene(KFbxScene* fbxScene)
     // Find the ambient light of the scene
     KFbxColor ambientColor = fbxScene->GetGlobalSettings().GetAmbientColor();
     scene->setAmbientColor((float)ambientColor.mRed, (float)ambientColor.mGreen, (float)ambientColor.mBlue);
-
-	// Assign the first camera node (if there is one) in the scene as the active camera
-	// This ensures that if there's a camera in the scene that it is assigned as the 
-	// active camera.
-	// TODO: add logic to find the "active" camera node in the fbxScene
-	scene->setActiveCameraNode(scene->getFirstCameraNode());
-
+    
+    // Assign the first camera node (if there is one) in the scene as the active camera
+    // This ensures that if there's a camera in the scene that it is assigned as the 
+    // active camera.
+    // TODO: add logic to find the "active" camera node in the fbxScene
+    scene->setActiveCameraNode(scene->getFirstCameraNode());
+    
     _gamePlayFile.addScene(scene);
 }
 
@@ -652,20 +652,65 @@ void FBXSceneEncoder::loadLight(KFbxNode* fbxNode, Node* node)
     switch (fbxLight->LightType.Get())
     {
     case KFbxLight::ePOINT:
-        light->setPointLight();
-        // TODO: range
+    {
+        KFbxLight::EDecayType decayType = fbxLight->DecayType.Get();
+        switch (decayType)
+        {
+        case KFbxLight::eNONE:
+            // No decay. Can assume we have an ambient light, because ambient lights in the scene are 
+            // converted to point lights with no decay when exporting to FBX.
+            light->setAmbientLight();
+            break;
+        case KFbxLight::eLINEAR:
+            light->setPointLight();
+            light->setLinearAttenuation((float)fbxLight->DecayStart.Get());
+            break;
+        case KFbxLight::eQUADRATIC:
+            light->setPointLight();
+            light->setQuadraticAttenuation((float)fbxLight->DecayStart.Get());
+            break;
+        case KFbxLight::eCUBIC:
+        default:
+            // Not supported..
+            break;
+        }
         break;
+    }
     case KFbxLight::eDIRECTIONAL:
+    {
         light->setDirectionalLight();
         break;
+    }
     case KFbxLight::eSPOT:
+    {
         light->setSpotLight();
-        // TODO: range and angles
+
+        KFbxLight::EDecayType decayType = fbxLight->DecayType.Get();
+        switch (decayType)
+        {
+        case KFbxLight::eNONE:
+            // No decay.
+            break;
+        case KFbxLight::eLINEAR:
+            light->setLinearAttenuation((float)fbxLight->DecayStart.Get());
+            break;  
+        case KFbxLight::eQUADRATIC:
+            light->setQuadraticAttenuation((float)fbxLight->DecayStart.Get());
+            break;
+        case KFbxLight::eCUBIC:
+            // Not supported..
+            break;
+        }
+
+        light->setFalloffAngle(MATH_DEG_TO_RAD((float)fbxLight->ConeAngle.Get())); // fall off angle
         break;
+    }
     default:
+    {
         warning("Unknown light type in node.");
         return;
     }
+    }
 
     _gamePlayFile.addLight(light);
     node->setLight(light);

+ 0 - 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" />
@@ -192,7 +191,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" />

+ 0 - 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>

+ 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

+ 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.

+ 6 - 3
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();
+    
+	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;

+ 18 - 0
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.

+ 5 - 0
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;

+ 32 - 5
gameplay/src/Node.cpp

@@ -850,20 +850,47 @@ PhysicsCollisionObject* Node::setCollisionObject(PhysicsCollisionObject::Type ty
 
 PhysicsCollisionObject* Node::setCollisionObject(const char* filePath)
 {
-    SAFE_DELETE(_collisionObject);
+    // Load the collision object properties from file.
+    Properties* properties = Properties::create(filePath);
+    assert(properties);
+    if (properties == NULL)
+    {
+        WARN_VARG("Failed to load collision object file: %s", filePath);
+        return NULL;
+    }
 
-	// TODO: Support other collision object types from file
-    _collisionObject = PhysicsRigidBody::create(this, filePath);
+    PhysicsCollisionObject* collisionObject = setCollisionObject(properties->getNextNamespace());
+    SAFE_DELETE(properties);
 
-	return _collisionObject;
+    return collisionObject;
 }
 
 PhysicsCollisionObject* Node::setCollisionObject(Properties* properties)
 {
     SAFE_DELETE(_collisionObject);
 
-    _collisionObject = PhysicsRigidBody::create(this, properties);
+    // Check if the properties is valid.
+    if (!properties || 
+        !(strcmp(properties->getNamespace(), "character") == 0 || 
+        strcmp(properties->getNamespace(), "ghost") == 0 || 
+        strcmp(properties->getNamespace(), "rigidbody") == 0))
+    {
+        WARN("Failed to load collision object from properties object: must be non-null object and have namespace equal to \'character\', \'ghost\', or \'rigidbody\'.");
+        return NULL;
+    }
 
+    if (strcmp(properties->getNamespace(), "character") == 0)
+    {
+        _collisionObject = PhysicsCharacter::create(this, properties);
+    }
+    else if (strcmp(properties->getNamespace(), "ghost") == 0)
+    {
+        _collisionObject = PhysicsGhostObject::create(this, properties);
+    }
+    else if (strcmp(properties->getNamespace(), "rigidbody") == 0)
+    {
+        _collisionObject = PhysicsRigidBody::create(this, properties);
+    }
 	return _collisionObject;
 }
 

+ 25 - 0
gameplay/src/PhysicsCharacter.cpp

@@ -84,6 +84,31 @@ PhysicsCharacter::~PhysicsCharacter()
     Game::getInstance()->getPhysicsController()->_world->removeAction(this);
 }
 
+PhysicsCharacter* PhysicsCharacter::create(Node* node, Properties* properties)
+{
+    // Check if the properties is valid and has a valid namespace.
+    assert(properties);
+    if (!properties || !(strcmp(properties->getNamespace(), "character") == 0))
+    {
+        WARN("Failed to load physics character from properties object: must be non-null object and have namespace equal to \'character\'.");
+        return NULL;
+    }
+
+    // Load the physics collision shape definition.
+    PhysicsCollisionShape::Definition* shape = PhysicsCollisionShape::Definition::create(node, properties);
+    if (shape == NULL)
+    {
+        WARN("Failed to create collision shape during physics character creation.");
+        return NULL;
+    }
+
+    // Create the physics character.
+    PhysicsCharacter* character = new PhysicsCharacter(node, *shape);
+    SAFE_DELETE(shape);
+
+    return character;
+}
+
 PhysicsCollisionObject::Type PhysicsCharacter::getType() const
 {
     return PhysicsCollisionObject::CHARACTER;

+ 12 - 0
gameplay/src/PhysicsCharacter.h

@@ -1,7 +1,9 @@
 #ifndef PHYSICSCHARACTER_H_
 #define PHYSICSCHARACTER_H_
 
+#include "Node.h"
 #include "PhysicsGhostObject.h"
+#include "Properties.h"
 
 namespace gameplay
 {
@@ -296,6 +298,16 @@ private:
      */
     virtual ~PhysicsCharacter();
 
+    /**
+     * Creates a physics character from the specified properties object.
+     * 
+     * @param node The node to create a physics character for; note that the node must have
+     *      a model attached to it prior to creating a physics character for it.
+     * @param properties The properties object defining the physics character (must have namespace equal to 'character').
+     * @return The newly created physics character, or <code>NULL</code> if the physics character failed to load.
+     */
+    static PhysicsCharacter* create(Node* node, Properties* properties);
+
     void updateCurrentVelocity();
 
     void play(CharacterAnimation* animation, unsigned int layer);

+ 408 - 160
gameplay/src/PhysicsCollisionShape.cpp

@@ -1,160 +1,408 @@
-#include "Base.h"
-#include "PhysicsCollisionShape.h"
-
-namespace gameplay
-{
-
-PhysicsCollisionShape::PhysicsCollisionShape(Type type, btCollisionShape* shape)
-	: _type(type), _shape(shape)
-{
-	memset(&_shapeData, 0, sizeof(_shapeData));
-}
-
-PhysicsCollisionShape::PhysicsCollisionShape(const PhysicsCollisionShape& copy)
-{
-	// hidden
-}
-
-PhysicsCollisionShape::~PhysicsCollisionShape()
-{
-	if (_shape)
-	{
-		// Cleanup shape-specific cached data
-		switch (_type)
-		{
-		case SHAPE_MESH:
-			if (_shapeData.meshData)
-			{
-				SAFE_DELETE_ARRAY(_shapeData.meshData->vertexData);
-				for (unsigned int i = 0; i < _shapeData.meshData->indexData.size(); i++)
-				{
-					SAFE_DELETE_ARRAY(_shapeData.meshData->indexData[i]);
-				}
-				SAFE_DELETE(_shapeData.meshData);
-			}
-			break;
-		case SHAPE_HEIGHTFIELD:
-			if (_shapeData.heightfieldData)
-			{
-				SAFE_DELETE_ARRAY(_shapeData.heightfieldData->heightData);
-				SAFE_DELETE(_shapeData.heightfieldData);
-			}
-			break;
-		}
-
-		// Free the bullet shape
-		SAFE_DELETE(_shape);
-	}
-}
-
-PhysicsCollisionShape::Type PhysicsCollisionShape::getType() const
-{
-	return _type;
-}
-
-PhysicsCollisionShape::Definition::Definition()
-	: isExplicit(false), centerAbsolute(false)
-{
-	memset(&data, 0, sizeof(data));
-}
-
-PhysicsCollisionShape::Definition::~Definition()
-{
-	switch (type)
-	{
-	case PhysicsCollisionShape::SHAPE_HEIGHTFIELD:
-		SAFE_RELEASE(data.heightfield);
-		break;
-
-	case PhysicsCollisionShape::SHAPE_MESH:
-		SAFE_RELEASE(data.mesh);
-		break;
-	}
-}
-
-PhysicsCollisionShape::Definition PhysicsCollisionShape::box()
-{
-	Definition d;
-	d.type = SHAPE_BOX;
-	d.isExplicit = false;
-	d.centerAbsolute = false;
-	return d;
-}
-
-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;
-}
-
-PhysicsCollisionShape::Definition PhysicsCollisionShape::sphere()
-{
-	Definition d;
-	d.type = SHAPE_SPHERE;
-	d.isExplicit = false;
-	d.centerAbsolute = false;
-	return d;
-}
-
-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;
-}
-
-PhysicsCollisionShape::Definition PhysicsCollisionShape::capsule()
-{
-	Definition d;
-	d.type = SHAPE_CAPSULE;
-	d.isExplicit = false;
-	d.centerAbsolute = false;
-	return d;
-}
-
-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;
-}
-
-PhysicsCollisionShape::Definition PhysicsCollisionShape::heightfield(Image* image)
-{
-	image->addRef();
-
-	Definition d;
-	d.type = SHAPE_HEIGHTFIELD;
-	d.data.heightfield = image;
-	d.isExplicit = true;
-	d.centerAbsolute = false;
-	return d;
-}
-
-PhysicsCollisionShape::Definition PhysicsCollisionShape::mesh(Mesh* mesh)
-{
-	mesh->addRef();
-
-	Definition d;
-	d.type = SHAPE_MESH;
-	d.data.mesh = mesh;
-	d.isExplicit = true;
-	d.centerAbsolute = false;
-	return d;
-}
-
-}
+#include "Base.h"
+#include "PhysicsCollisionShape.h"
+#include "Node.h"
+#include "Properties.h"
+
+namespace gameplay
+{
+
+PhysicsCollisionShape::PhysicsCollisionShape(Type type, btCollisionShape* shape)
+    : _type(type), _shape(shape)
+{
+    memset(&_shapeData, 0, sizeof(_shapeData));
+}
+
+PhysicsCollisionShape::PhysicsCollisionShape(const PhysicsCollisionShape& copy)
+{
+	// hidden
+}
+
+PhysicsCollisionShape::~PhysicsCollisionShape()
+{
+    if (_shape)
+    {
+        // Cleanup shape-specific cached data
+        switch (_type)
+        {
+        case SHAPE_MESH:
+            if (_shapeData.meshData)
+            {
+                SAFE_DELETE_ARRAY(_shapeData.meshData->vertexData);
+                for (unsigned int i = 0; i < _shapeData.meshData->indexData.size(); i++)
+                {
+                    SAFE_DELETE_ARRAY(_shapeData.meshData->indexData[i]);
+                }
+                SAFE_DELETE(_shapeData.meshData);
+            }
+            break;
+        case SHAPE_HEIGHTFIELD:
+            if (_shapeData.heightfieldData)
+            {
+                SAFE_DELETE_ARRAY(_shapeData.heightfieldData->heightData);
+                SAFE_DELETE(_shapeData.heightfieldData);
+            }
+            break;
+        }
+
+        // Free the bullet shape
+        SAFE_DELETE(_shape);
+    }
+}
+
+PhysicsCollisionShape::Type PhysicsCollisionShape::getType() const
+{
+    return _type;
+}
+
+PhysicsCollisionShape::Definition::Definition()
+    : isExplicit(false), centerAbsolute(false)
+{
+    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)
+    {
+    case PhysicsCollisionShape::SHAPE_HEIGHTFIELD:
+        SAFE_RELEASE(data.heightfield);
+        break;
+
+    case PhysicsCollisionShape::SHAPE_MESH:
+        SAFE_RELEASE(data.mesh);
+        break;
+    }
+}
+
+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.
+    assert(properties);
+    if (!properties || 
+        !(strcmp(properties->getNamespace(), "character") == 0 || 
+        strcmp(properties->getNamespace(), "ghost") == 0 || 
+        strcmp(properties->getNamespace(), "rigidbody") == 0))
+    {
+        WARN("Failed to load physics collision shape from properties object: must be non-null object and have namespace equal to \'character\', \'ghost\', or \'rigidbody\'.");
+        return NULL;
+    }
+
+    // Set values to their defaults.
+    PhysicsCollisionShape::Type type = PhysicsCollisionShape::SHAPE_BOX;
+    Vector3* extents = NULL;
+    Vector3* center = NULL;
+    float radius = -1.0f;
+    float height = -1.0f;
+    bool centerIsAbsolute = false;
+    const char* imagePath = NULL;
+    bool typeSpecified = false;
+
+    // Load the defined properties.
+    properties->rewind();
+    const char* name;
+    while (name = properties->getNextProperty())
+    {
+        if (strcmp(name, "type") == 0)
+        {
+            std::string typeStr = properties->getString();
+            if (typeStr == "BOX")
+                type = SHAPE_BOX;
+            else if (typeStr == "SPHERE")
+                type = SHAPE_SPHERE;
+            else if (typeStr == "MESH")
+                type = SHAPE_MESH;
+            else if (typeStr == "HEIGHTFIELD")
+                type = SHAPE_HEIGHTFIELD;
+            else if (typeStr == "CAPSULE")
+                type = SHAPE_CAPSULE;
+            else
+            {
+                WARN_VARG("Could not create physics collision shape; unsupported value for collision shape type: '%s'.", typeStr.c_str());
+                return NULL;
+            }
+
+            typeSpecified = true;
+        }
+        else if (strcmp(name, "image") == 0)
+        {
+            imagePath = properties->getString();
+        }
+        else if (strcmp(name, "radius") == 0)
+        {
+            radius = properties->getFloat();
+        }
+        else if (strcmp(name, "height") == 0)
+        {
+            height = properties->getFloat();
+        }
+        else if (strcmp(name, "extents") == 0)
+        {
+            extents = new Vector3();
+            properties->getVector3("extents", extents);
+        }
+        else if (strcmp(name, "center") == 0)
+        {
+            center = new Vector3();
+            properties->getVector3("center", center);
+        }
+        else if (strcmp(name, "center-absolute") == 0)
+        {
+            centerIsAbsolute = properties->getBool();
+        }
+    }
+
+    if (!typeSpecified)
+    {
+        WARN("Missing 'type' specifier for collision shape definition.");
+        return NULL;
+    }
+
+    // Create the collision shape.
+    PhysicsCollisionShape::Definition* shape = new PhysicsCollisionShape::Definition();
+    switch (type)
+    {
+        case SHAPE_BOX:
+            if (extents)
+            {
+                if (center)
+                {
+                    *shape = box(*extents, *center, centerIsAbsolute);
+                }
+                else
+                {
+                    *shape = box(*extents);
+                }
+            }
+            else
+            {
+                *shape = box();
+            }
+            break;
+        case SHAPE_SPHERE:
+            if (radius != -1.0f)
+            {
+                if (center)
+                {
+                    *shape = sphere(radius, *center, centerIsAbsolute);
+                }
+                else
+                {
+                    *shape = sphere(radius);
+                }
+            }
+            else
+            {
+                *shape = sphere();
+            }
+            break;
+        case SHAPE_CAPSULE:
+            if (radius != -1.0f && height != -1.0f)
+            {
+                if (center)
+                {
+                    *shape = capsule(radius, height, *center, centerIsAbsolute);
+                }
+                else
+                {
+                    *shape = capsule(radius, height);
+                }
+            }
+            else
+            {
+                *shape = capsule();
+            }
+            break;
+        case SHAPE_MESH:
+        {
+            // Mesh is required on node
+            Mesh* nodeMesh = node->getModel() ? node->getModel()->getMesh() : NULL;
+            if (nodeMesh == NULL)
+            {
+                WARN("Cannot create mesh rigid body for node without mode/mesh.");
+                return NULL;
+            }
+
+            // Check that the node's mesh's primitive type is supported.
+            switch (nodeMesh->getPrimitiveType())
+            {
+                case Mesh::TRIANGLES:
+                {
+                    *shape = mesh(nodeMesh);
+                    break;
+                }
+                case Mesh::LINES:
+                case Mesh::LINE_STRIP:
+                case Mesh::POINTS:
+                case Mesh::TRIANGLE_STRIP:
+                    WARN("Mesh rigid bodies are currently only supported on meshes with primitive type equal to TRIANGLES.");
+                    SAFE_DELETE(shape);
+                    break;
+            }
+
+            break;
+        }
+        case SHAPE_HEIGHTFIELD:
+            if (imagePath == NULL)
+            {
+                WARN("Heightfield rigid body requires an image path.");
+            }
+            else
+            {
+                // Load the image data from the given file path.
+                Image* image = Image::create(imagePath);
+                if (!image)
+                    return NULL;
+
+                // Ensure that the image's pixel format is supported.
+                switch (image->getFormat())
+                {
+                    case Image::RGB:
+                    case Image::RGBA:
+                        break;
+                    default:
+                        WARN_VARG("Heightmap: pixel format is not supported: %d", image->getFormat());
+                        return NULL;
+                }
+
+                *shape = PhysicsCollisionShape::heightfield(image);
+                SAFE_RELEASE(image);
+            }
+            break;
+        default:
+            WARN("Unsupported value for physics collision shape type.");
+            break;
+    }
+
+    SAFE_DELETE(extents);
+    SAFE_DELETE(center);
+
+    return shape;
+}
+
+PhysicsCollisionShape::Definition PhysicsCollisionShape::box()
+{
+    Definition d;
+    d.type = SHAPE_BOX;
+    d.isExplicit = false;
+    d.centerAbsolute = false;
+    return d;
+}
+
+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;
+}
+
+PhysicsCollisionShape::Definition PhysicsCollisionShape::sphere()
+{
+    Definition d;
+    d.type = SHAPE_SPHERE;
+    d.isExplicit = false;
+    d.centerAbsolute = false;
+    return d;
+}
+
+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;
+}
+
+PhysicsCollisionShape::Definition PhysicsCollisionShape::capsule()
+{
+    Definition d;
+    d.type = SHAPE_CAPSULE;
+    d.isExplicit = false;
+    d.centerAbsolute = false;
+    return d;
+}
+
+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;
+}
+
+PhysicsCollisionShape::Definition PhysicsCollisionShape::heightfield(Image* image)
+{
+    image->addRef();
+
+    Definition d;
+    d.type = SHAPE_HEIGHTFIELD;
+    d.data.heightfield = image;
+    d.isExplicit = true;
+    d.centerAbsolute = false;
+    return d;
+}
+
+PhysicsCollisionShape::Definition PhysicsCollisionShape::mesh(Mesh* mesh)
+{
+    mesh->addRef();
+
+    Definition d;
+    d.type = SHAPE_MESH;
+    d.data.mesh = mesh;
+    d.isExplicit = true;
+    d.centerAbsolute = false;
+    return d;
+}
+
+}

+ 235 - 219
gameplay/src/PhysicsCollisionShape.h

@@ -1,219 +1,235 @@
-#ifndef PHYSICSCOLLISIONSHAPE_H_
-#define PHYSICSCOLLISIONSHAPE_H_
-
-#include "Vector3.h"
-#include "Image.h"
-#include "Mesh.h"
-
-namespace gameplay
-{
-
-/**
- * Base physics collision shape class that all supported shapes derive from.
- */
-class PhysicsCollisionShape : public Ref
-{
-	friend class PhysicsController;
-	friend class PhysicsRigidBody;
-
-public:
-
-	/**
-	 * Defines the supported collision shape types.
-	 */
-	enum Type
-	{
-		SHAPE_BOX,
-		SHAPE_SPHERE,
-		SHAPE_CAPSULE,
-		SHAPE_MESH,
-		SHAPE_HEIGHTFIELD
-	};
-
-	/**
-	 * Structure representing the definition of a collision shape, which is used
-	 * during collision shape construction time.
-	 *
-	 * Use the static methods on the PhysicsCollisionShape class to return
-	 * 
-	 */
-	struct Definition
-	{
-		friend class PhysicsCollisionShape;
-		friend class PhysicsController;
-		friend class PhysicsRigidBody;
-
-	public:
-
-		~Definition();
-
-	private:
-
-		Definition();
-
-		// 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; };
-
-		union
-		{
-			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;
-
-		// Whether the center position is absolute or relative to the node position.
-		bool centerAbsolute;
-	};
-
-	/**
-	 * Returns the type of this collision shape.
-	 *
-	 * @return The collision shape type.
-	 */
-	PhysicsCollisionShape::Type getType() const;
-
-	/**
-	 * 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.
-	 *
-	 * @return Definition of a box shape.
-	 */
-	static PhysicsCollisionShape::Definition box();
-
-	/**
-	 * Defines a box shape, using the specified shape information and center.
-	 *
-	 * @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.
-	 *
-	 * @return Definition of a box shape.
-	 */
-	static PhysicsCollisionShape::Definition box(const Vector3& extents, const Vector3& center = Vector3::zero(), bool absolute = false);
-
-	/**
-	 * Defines a sphere shape, using the bounding volume of the node it is attached to.
-	 *
-	 * @return Definition of a sphere shape.
-	 */
-	static PhysicsCollisionShape::Definition sphere();
-
-	/**
-	 * Defines a sphere shape, using the specified shape information and center.
-	 *
-	 * @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.
-	 *
-	 * @return Definition of a sphere shape.
-	 */
-	static PhysicsCollisionShape::Definition sphere(float radius, const Vector3& center = Vector3::zero(), bool absolute = false);
-
-	/**
-	 * Defines a capsule shape, using the bounding volume of the node it is attached to.
-	 *
-	 * @return Definition of a capsule shape.
-	 */
-	static PhysicsCollisionShape::Definition capsule();
-
-	/**
-	 * Defines a capsule shape, using the specified shape information and center.
-	 *
-	 * @param radius Radius of the capsule.
-	 * @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.
-	 *
-	 * @return Definition of a capsule shape.
-	 */
-	static PhysicsCollisionShape::Definition capsule(float radius, float height, const Vector3& center = Vector3::zero(), bool absolute = false);
-
-	/**
-	 * Defines a heightfield shape using the specified heightfield image.
-	 *
-	 * @return Definition of a heightfield shape.
-	 */
-	static PhysicsCollisionShape::Definition heightfield(Image* image);
-
-	/**
-	 * Defines a mesh shape using the specified mehs.
-	 *
-	 * @return Definition of a mesh shape.
-	 */
-	static PhysicsCollisionShape::Definition mesh(Mesh* mesh);
-
-private:
-
-	struct MeshData
-	{
-		float* vertexData;
-		std::vector<unsigned char*> indexData;
-	};
-
-	struct HeightfieldData
-	{
-		float* heightData;
-		unsigned int width;
-		unsigned int height;
-		mutable Matrix inverse;
-		mutable bool inverseIsDirty;
-	};
-
-	/**
-	 * Constructor.
-	 */
-	PhysicsCollisionShape(Type type, btCollisionShape* shape);
-
-	/** 
-	 * Hidden copy constructor.
-	 */
-	PhysicsCollisionShape(const PhysicsCollisionShape& copy);
-
-	/**
-	 * Destructor.
-	 */
-	~PhysicsCollisionShape();
-
-	// Shape type
-	Type _type;
-
-	// Bullet shape object
-	btCollisionShape* _shape;
-
-	// Shape specific cached data
-	union
-	{
-		MeshData* meshData;
-		HeightfieldData* heightfieldData;
-	} _shapeData;
-
-};
-
-}
-
-#endif
+#ifndef PHYSICSCOLLISIONSHAPE_H_
+#define PHYSICSCOLLISIONSHAPE_H_
+
+#include "Vector3.h"
+#include "Image.h"
+#include "Mesh.h"
+
+namespace gameplay
+{
+    class Node;
+    class Properties;
+
+/**
+ * Base physics collision shape class that all supported shapes derive from.
+ */
+class PhysicsCollisionShape : public Ref
+{
+    friend class PhysicsController;
+    friend class PhysicsRigidBody;
+
+public:
+
+    /**
+     * Defines the supported collision shape types.
+     */
+    enum Type
+    {
+        SHAPE_BOX,
+        SHAPE_SPHERE,
+        SHAPE_CAPSULE,
+        SHAPE_MESH,
+        SHAPE_HEIGHTFIELD
+    };
+
+    /**
+     * Structure representing the definition of a collision shape, which is used
+     * during collision shape construction time.
+     *
+     * Use the static methods on the PhysicsCollisionShape class to return
+     * 
+     */
+    struct Definition
+    {
+        friend class PhysicsCollisionShape;
+        friend class PhysicsController;
+        friend class PhysicsRigidBody;
+        friend class PhysicsCharacter;
+        friend class PhysicsGhostObject;
+
+    public:
+
+        ~Definition();
+
+    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).
+         * 
+         * @param node The node to create the PhysicsCollisionShape::Definition object for.
+         * @param properties The properties object to create the PhysicsCollisionShape#Definition object from.
+         * @return A PhysicsCollisionShape#Definition object.
+         */
+        static Definition* create(Node* node, Properties* properties);
+
+        // 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; };
+
+        union
+        {
+			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;
+
+        // Whether the center position is absolute or relative to the node position.
+        bool centerAbsolute;
+    };
+
+    /**
+     * Returns the type of this collision shape.
+     *
+     * @return The collision shape type.
+     */
+    PhysicsCollisionShape::Type getType() const;
+
+	/**
+	 * 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.
+     *
+     * @return Definition of a box shape.
+     */
+    static PhysicsCollisionShape::Definition box();
+
+    /**
+     * Defines a box shape, using the specified shape information and center.
+     *
+     * @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.
+     *
+     * @return Definition of a box shape.
+     */
+    static PhysicsCollisionShape::Definition box(const Vector3& extents, const Vector3& center = Vector3::zero(), bool absolute = false);
+
+    /**
+     * Defines a sphere shape, using the bounding volume of the node it is attached to.
+     *
+     * @return Definition of a sphere shape.
+     */
+    static PhysicsCollisionShape::Definition sphere();
+
+    /**
+     * Defines a sphere shape, using the specified shape information and center.
+     *
+     * @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.
+     *
+     * @return Definition of a sphere shape.
+     */
+    static PhysicsCollisionShape::Definition sphere(float radius, const Vector3& center = Vector3::zero(), bool absolute = false);
+
+    /**
+     * Defines a capsule shape, using the bounding volume of the node it is attached to.
+     *
+     * @return Definition of a capsule shape.
+     */
+    static PhysicsCollisionShape::Definition capsule();
+
+    /**
+     * Defines a capsule shape, using the specified shape information and center.
+     *
+     * @param radius Radius of the capsule.
+     * @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.
+     *
+     * @return Definition of a capsule shape.
+     */
+    static PhysicsCollisionShape::Definition capsule(float radius, float height, const Vector3& center = Vector3::zero(), bool absolute = false);
+
+    /**
+     * Defines a heightfield shape using the specified heightfield image.
+     *
+     * @return Definition of a heightfield shape.
+     */
+    static PhysicsCollisionShape::Definition heightfield(Image* image);
+
+    /**
+     * Defines a mesh shape using the specified mehs.
+     *
+     * @return Definition of a mesh shape.
+     */
+    static PhysicsCollisionShape::Definition mesh(Mesh* mesh);
+
+private:
+
+    struct MeshData
+    {
+        float* vertexData;
+        std::vector<unsigned char*> indexData;
+    };
+
+    struct HeightfieldData
+    {
+        float* heightData;
+        unsigned int width;
+        unsigned int height;
+        mutable Matrix inverse;
+        mutable bool inverseIsDirty;
+    };
+
+    /**
+     * Constructor.
+     */
+    PhysicsCollisionShape(Type type, btCollisionShape* shape);
+
+	/** 
+	 * Hidden copy constructor.
+	 */
+	PhysicsCollisionShape(const PhysicsCollisionShape& copy);
+
+	/**
+	 * Destructor.
+	 */
+	~PhysicsCollisionShape();
+
+
+    // Shape type
+    Type _type;
+
+    // Bullet shape object
+    btCollisionShape* _shape;
+
+    // Shape specific cached data
+    union
+    {
+        MeshData* meshData;
+        HeightfieldData* heightfieldData;
+    } _shapeData;
+
+};
+
+}
+
+#endif

+ 31 - 6
gameplay/src/PhysicsGhostObject.cpp

@@ -9,35 +9,60 @@ namespace gameplay
 PhysicsGhostObject::PhysicsGhostObject(Node* node, const PhysicsCollisionShape::Definition& shape)
     : PhysicsCollisionObject(node), _ghostObject(NULL)
 {
-	Vector3 centerOfMassOffset;
+    Vector3 centerOfMassOffset;
     PhysicsController* physicsController = Game::getInstance()->getPhysicsController();
 
     // Create and set the collision shape for the ghost object.
-	_collisionShape = physicsController->createShape(node, shape, &centerOfMassOffset);
+    _collisionShape = physicsController->createShape(node, shape, &centerOfMassOffset);
 
-	// Create the ghost object.
+    // Create the ghost object.
     _ghostObject = bullet_new<btPairCachingGhostObject>();
 	_ghostObject->setCollisionShape(_collisionShape->getShape());
 
     // Initialize a physics motion state object for syncing the transform.
-	_motionState = new PhysicsMotionState(_node, &centerOfMassOffset);
+    _motionState = new PhysicsMotionState(_node, &centerOfMassOffset);
     _motionState->getWorldTransform(_ghostObject->getWorldTransform());
 
     // Add the ghost object to the physics world.
     physicsController->addCollisionObject(this);
 
-	_node->addListener(this);
+    _node->addListener(this);
 }
 
 PhysicsGhostObject::~PhysicsGhostObject()
 {
-	_node->removeListener(this);
+    _node->removeListener(this);
 
     Game::getInstance()->getPhysicsController()->removeCollisionObject(this);
 
     SAFE_DELETE(_ghostObject);
 }
 
+PhysicsGhostObject* PhysicsGhostObject::create(Node* node, Properties* properties)
+{
+    // Check if the properties is valid and has a valid namespace.
+    assert(properties);
+    if (!properties || !(strcmp(properties->getNamespace(), "ghost") == 0))
+    {
+        WARN("Failed to load ghost object from properties object: must be non-null object and have namespace equal to \'ghost\'.");
+        return NULL;
+    }
+
+    // Load the physics collision shape definition.
+    PhysicsCollisionShape::Definition* shape = PhysicsCollisionShape::Definition::create(node, properties);
+    if (shape == NULL)
+    {
+        WARN("Failed to create collision shape during ghost object creation.");
+        return NULL;
+    }
+
+    // Create the ghost object.
+    PhysicsGhostObject* ghost = new PhysicsGhostObject(node, *shape);
+    SAFE_DELETE(shape);
+
+    return ghost;
+}
+
 PhysicsCollisionObject::Type PhysicsGhostObject::getType() const
 {
     return GHOST_OBJECT;

+ 12 - 2
gameplay/src/PhysicsGhostObject.h

@@ -24,7 +24,7 @@ public:
      */
     PhysicsCollisionObject::Type getType() const;
 
-	/**
+    /**
      * Used to synchronize the transform between GamePlay and Bullet.
      */
     void transformChanged(Transform* transform, long cookie);
@@ -44,13 +44,23 @@ protected:
      * @param node The node to attach the ghost object to.
      * @param shape The collision shape definition for the ghost object.
      */
-	PhysicsGhostObject(Node* node, const PhysicsCollisionShape::Definition& shape);
+    PhysicsGhostObject(Node* node, const PhysicsCollisionShape::Definition& shape);
 
     /**
      * Destructor.
      */
     virtual ~PhysicsGhostObject();
 
+    /**
+     * Creates a ghost object from the specified properties object.
+     * 
+     * @param node The node to create a ghost object for; note that the node must have
+     *      a model attached to it prior to creating a ghost object for it.
+     * @param properties The properties object defining the ghost object (must have namespace equal to 'ghost').
+     * @return The newly created ghost object, or <code>NULL</code> if the ghost object failed to load.
+     */
+    static PhysicsGhostObject* create(Node* node, Properties* properties);
+
     btPairCachingGhostObject* _ghostObject;
 };
 

+ 73 - 235
gameplay/src/PhysicsRigidBody.cpp

@@ -13,12 +13,12 @@ namespace gameplay
 PhysicsRigidBody::PhysicsRigidBody(Node* node, const PhysicsCollisionShape::Definition& shape, const Parameters& parameters)
         : PhysicsCollisionObject(node), _body(NULL), _mass(parameters.mass), _constraints(NULL)
 {
-	// Create our collision sh ape
-	Vector3 centerOfMassOffset;
-	_collisionShape = Game::getInstance()->getPhysicsController()->createShape(node, shape, &centerOfMassOffset);
+    // Create our collision shape
+    Vector3 centerOfMassOffset;
+    _collisionShape = Game::getInstance()->getPhysicsController()->createShape(node, shape, &centerOfMassOffset);
 
-	// Create motion state object
-	_motionState = new PhysicsMotionState(node, (centerOfMassOffset.lengthSquared() > MATH_EPSILON) ? &centerOfMassOffset : NULL);
+    // Create motion state object
+    _motionState = new PhysicsMotionState(node, (centerOfMassOffset.lengthSquared() > MATH_EPSILON) ? &centerOfMassOffset : NULL);
 
     // If the mass is non-zero, then the object is dynamic so we calculate the local 
     // inertia. However, if the collision shape is a triangle mesh, we don't calculate 
@@ -34,48 +34,48 @@ PhysicsRigidBody::PhysicsRigidBody(Node* node, const PhysicsCollisionShape::Defi
     rbInfo.m_linearDamping = parameters.linearDamping;
     rbInfo.m_angularDamping = parameters.angularDamping;
 
-	// Create + assign the new bullet rigid body object.
-	_body = bullet_new<btRigidBody>(rbInfo);
+    // Create + assign the new bullet rigid body object.
+    _body = bullet_new<btRigidBody>(rbInfo);
 
-	// Set other initially defined properties.
+    // Set other initially defined properties.
     setKinematic(parameters.kinematic);
-	setAnisotropicFriction(parameters.anisotropicFriction);
-	setGravity(parameters.gravity);
+    setAnisotropicFriction(parameters.anisotropicFriction);
+    setGravity(parameters.gravity);
 
     // Add ourself to the physics world.
     Game::getInstance()->getPhysicsController()->addCollisionObject(this);
 
-	if (_collisionShape->getType() == PhysicsCollisionShape::SHAPE_HEIGHTFIELD)
-	{
-		// Add a listener on the node's transform so we can track dirty changes to calculate
-		// an inverse matrix for transforming heightfield points between world and local space.
-		_node->addListener(this);
-	}
+    if (_collisionShape->getType() == PhysicsCollisionShape::SHAPE_HEIGHTFIELD)
+    {
+        // Add a listener on the node's transform so we can track dirty changes to calculate
+        // an inverse matrix for transforming heightfield points between world and local space.
+        _node->addListener(this);
+    }
 }
 
 PhysicsRigidBody::~PhysicsRigidBody()
 {
-	// Clean up all constraints linked to this rigid body.
-	if (_constraints)
-	{
-		for (unsigned int i = 0; i < _constraints->size(); ++i)
-		{
-			SAFE_DELETE((*_constraints)[i]);
-		}
-		SAFE_DELETE(_constraints);
-	}
-
-	// Remove collision object from physics controller
+    // Clean up all constraints linked to this rigid body.
+    if (_constraints)
+    {
+        for (unsigned int i = 0; i < _constraints->size(); ++i)
+        {
+            SAFE_DELETE((*_constraints)[i]);
+        }
+        SAFE_DELETE(_constraints);
+    }
+
+    // Remove collision object from physics controller
     Game::getInstance()->getPhysicsController()->removeCollisionObject(this);
 
     // Clean up the rigid body and its related objects.
-	SAFE_DELETE(_body);
+    SAFE_DELETE(_body);
 
-	// Unregister node listener (only registered for heihgtfield collision shape types)
-	if (_collisionShape->getType() == PhysicsCollisionShape::SHAPE_HEIGHTFIELD)
-	{
-		_node->removeListener(this);
-	}
+    // Unregister node listener (only registered for heihgtfield collision shape types)
+    if (_collisionShape->getType() == PhysicsCollisionShape::SHAPE_HEIGHTFIELD)
+    {
+        _node->removeListener(this);
+    }
 }
 
 PhysicsCollisionObject::Type PhysicsRigidBody::getType() const
@@ -141,25 +141,6 @@ void PhysicsRigidBody::applyTorqueImpulse(const Vector3& torque)
     }
 }
 
-PhysicsRigidBody* PhysicsRigidBody::create(Node* node, const char* filePath)
-{
-    assert(filePath);
-
-    // Load the rigid body properties from file.
-    Properties* properties = Properties::create(filePath);
-    assert(properties);
-    if (properties == NULL)
-    {
-        WARN_VARG("Failed to load rigid body file: %s", filePath);
-        return NULL;
-    }
-
-    PhysicsRigidBody* body = create(node, properties->getNextNamespace());
-    SAFE_DELETE(properties);
-
-    return body;
-}
-
 PhysicsRigidBody* PhysicsRigidBody::create(Node* node, Properties* properties)
 {
     // Check if the properties is valid and has a valid namespace.
@@ -170,41 +151,23 @@ PhysicsRigidBody* PhysicsRigidBody::create(Node* node, Properties* properties)
         return NULL;
     }
 
-    // Set values to their defaults.
-	bool typeSpecified = false;
-	PhysicsCollisionShape::Type type;
-	Parameters parameters;
-    const char* imagePath = NULL;
-    float radius, height;
-	Vector3 center, min, max;
-	int bits = 0;
+    // Load the physics collision shape definition.
+    PhysicsCollisionShape::Definition* shape = PhysicsCollisionShape::Definition::create(node, properties);
+    if (shape == NULL)
+    {
+        WARN("Failed to create collision shape during rigid body creation.");
+        return NULL;
+    }
+
+    // Set the rigid body parameters to their defaults.
+    Parameters parameters;
 
-    // Load the defined properties.
+    // Load the defined rigid body parameters.
     properties->rewind();
     const char* name;
     while ((name = properties->getNextProperty()) != NULL)
     {
-        if (strcmp(name, "type") == 0)
-        {
-            std::string typeStr = properties->getString();
-            if (typeStr == "BOX")
-                type = PhysicsCollisionShape::SHAPE_BOX;
-            else if (typeStr == "SPHERE")
-                type = PhysicsCollisionShape::SHAPE_SPHERE;
-			else if (typeStr == "CAPSULE")
-                type = PhysicsCollisionShape::SHAPE_CAPSULE;
-			else if (typeStr == "HEIGHTFIELD")
-                type = PhysicsCollisionShape::SHAPE_HEIGHTFIELD;
-            else if (typeStr == "MESH")
-                type = PhysicsCollisionShape::SHAPE_MESH;
-            else
-            {
-                WARN_VARG("Could not create rigid body; unsupported value for rigid body type: '%s'.", typeStr.c_str());
-                return NULL;
-            }
-			typeSpecified = true;
-        }
-        else if (strcmp(name, "mass") == 0)
+        if (strcmp(name, "mass") == 0)
         {
             parameters.mass = properties->getFloat();
         }
@@ -236,136 +199,11 @@ PhysicsRigidBody* PhysicsRigidBody::create(Node* node, Properties* properties)
         {
             properties->getVector3(NULL, &parameters.gravity);
         }
-        else if (strcmp(name, "image") == 0)
-        {
-            imagePath = properties->getString();
-        }
-        else if (strcmp(name, "radius") == 0)
-        {
-			radius = properties->getFloat();
-			bits |= 1;
-        }
-        else if (strcmp(name, "height") == 0)
-        {
-            height = properties->getFloat();
-			bits |= 2;
-        }
-		else if (strcmp(name, "center") == 0)
-		{
-			properties->getVector3(NULL, &center);
-			bits |= 4;
-		}
-		else if (strcmp(name, "min") == 0)
-		{
-			properties->getVector3(NULL, &min);
-			bits |= 8;
-		}
-		else if (strcmp(name, "max") == 0)
-		{
-			properties->getVector3(NULL, &max);
-			bits |= 16;
-		}
     }
 
-	if (!typeSpecified)
-	{
-		WARN("Missing 'type' specifier for rigid body definition.");
-		return NULL;
-	}
-
-	PhysicsRigidBody* body = NULL;
-
-	switch (type)
-	{
-	case PhysicsCollisionShape::SHAPE_BOX:
-		if ((bits & 8/*min*/) || (bits & 16/*max*/))
-		{
-			// Explicitly defined box shape
-			body = new PhysicsRigidBody(node, PhysicsCollisionShape::box(min, max), parameters);
-		}
-		else
-		{
-			// Auto box shape
-			body = new PhysicsRigidBody(node, PhysicsCollisionShape::box(), parameters);
-		}
-		break;
-
-	case PhysicsCollisionShape::SHAPE_SPHERE:
-		if ((bits & 4/*center*/) || (bits & 1/*radius*/))
-		{
-			// Explicitly defined sphere shape
-			body = new PhysicsRigidBody(node, PhysicsCollisionShape::sphere(radius, center), parameters);
-		}
-		else
-		{
-			// Auto sphere shape
-			body = new PhysicsRigidBody(node, PhysicsCollisionShape::sphere(), parameters);
-		}
-		break;
-
-    case PhysicsCollisionShape::SHAPE_CAPSULE:
-		if ((bits & 1/*radius*/) || (bits & 2/*height*/))
-		{
-			// Explicitly defined capsule shape
-			body = new PhysicsRigidBody(node, PhysicsCollisionShape::capsule(radius, height, center), parameters);
-		}
-		else
-		{
-			// Auto capsule shape
-			body = new PhysicsRigidBody(node, PhysicsCollisionShape::capsule(), parameters);
-		}
-        break;
-
-    case PhysicsCollisionShape::SHAPE_HEIGHTFIELD:
-		{
-			if (imagePath == NULL)
-			{
-				WARN("Heightfield rigid body requires an image path.");
-				return NULL;
-			}
-
-            // Load the image data from the given file path.
-            Image* image = Image::create(imagePath);
-            if (!image)
-			{
-				WARN_VARG("Failed to load heightmap image: %s", imagePath);
-                return NULL;
-			}
-
-            // Ensure that the image's pixel format is supported.
-            switch (image->getFormat())
-            {
-                case Image::RGB:
-                case Image::RGBA:
-                    break;
-                default:
-                    WARN_VARG("Heightmap: pixel format is not supported: %d", image->getFormat());
-                    return NULL;
-            }
-
-			body = new PhysicsRigidBody(node, PhysicsCollisionShape::heightfield(image), parameters);
-
-			SAFE_RELEASE(image);
-		}
-        break;
-
-	case PhysicsCollisionShape::SHAPE_MESH:
-		{
-			// Mesh is required on node
-			Mesh* mesh = node->getModel() ? node->getModel()->getMesh() : NULL;
-			if (mesh == NULL)
-			{
-				WARN("Cannot create mesh rigid body for node without mode/mesh.");
-				return NULL;
-			}
-
-			body = new PhysicsRigidBody(node, PhysicsCollisionShape::mesh(mesh), parameters);
-		}
-		break;
-
-	default:
-		break;
-	}
+    // Create the rigid body.
+    PhysicsRigidBody* body = new PhysicsRigidBody(node, *shape, parameters);
+    SAFE_DELETE(shape);
 
     return body;
 }
@@ -387,21 +225,21 @@ void PhysicsRigidBody::setKinematic(bool kinematic)
 float PhysicsRigidBody::getHeight(float x, float y) const
 {
     // This function is only supported for heightfield rigid bodies.
-	if (_collisionShape->getType() != PhysicsCollisionShape::SHAPE_HEIGHTFIELD)
+    if (_collisionShape->getType() != PhysicsCollisionShape::SHAPE_HEIGHTFIELD)
     {
         WARN("Attempting to get the height of a non-heightfield rigid body.");
         return 0.0f;
     }
 
     // Calculate the correct x, y position relative to the heightfield data.
-	if (_collisionShape->_shapeData.heightfieldData->inverseIsDirty)
+    if (_collisionShape->_shapeData.heightfieldData->inverseIsDirty)
     {
-		_node->getWorldMatrix().invert(&_collisionShape->_shapeData.heightfieldData->inverse);
-		_collisionShape->_shapeData.heightfieldData->inverseIsDirty = false;
+        _node->getWorldMatrix().invert(&_collisionShape->_shapeData.heightfieldData->inverse);
+        _collisionShape->_shapeData.heightfieldData->inverseIsDirty = false;
     }
 
-	float w = _collisionShape->_shapeData.heightfieldData->width;
-	float h = _collisionShape->_shapeData.heightfieldData->height;
+    float w = _collisionShape->_shapeData.heightfieldData->width;
+    float h = _collisionShape->_shapeData.heightfieldData->height;
 
     Vector3 v = _collisionShape->_shapeData.heightfieldData->inverse * Vector3(x, 0.0f, y);
     x = (v.x + (0.5f * (w - 1))) * w / (w - 1);
@@ -414,43 +252,43 @@ float PhysicsRigidBody::getHeight(float x, float y) const
         return 0.0f;
     }
 
-	return PhysicsController::calculateHeight(_collisionShape->_shapeData.heightfieldData->heightData, w, h, x, y);
+    return PhysicsController::calculateHeight(_collisionShape->_shapeData.heightfieldData->heightData, w, h, x, y);
 }
 
 void PhysicsRigidBody::addConstraint(PhysicsConstraint* constraint)
 {
-	if (_constraints == NULL)
-		_constraints = new std::vector<PhysicsConstraint*>();
+    if (_constraints == NULL)
+        _constraints = new std::vector<PhysicsConstraint*>();
 
     _constraints->push_back(constraint);
 }
 
 void PhysicsRigidBody::removeConstraint(PhysicsConstraint* constraint)
 {
-	if (_constraints)
-	{
-		for (unsigned int i = 0; i < _constraints->size(); ++i)
-		{
-			if ((*_constraints)[i] == constraint)
-			{
-				_constraints->erase(_constraints->begin() + i);
-				break;
-			}
-		}
-	}
+    if (_constraints)
+    {
+        for (unsigned int i = 0; i < _constraints->size(); ++i)
+        {
+            if ((*_constraints)[i] == constraint)
+            {
+                _constraints->erase(_constraints->begin() + i);
+                break;
+            }
+        }
+    }
 }
 
 bool PhysicsRigidBody::supportsConstraints()
 {
-	return (getShapeType() != PhysicsCollisionShape::SHAPE_HEIGHTFIELD && getShapeType() != PhysicsCollisionShape::SHAPE_MESH);
+    return (getShapeType() != PhysicsCollisionShape::SHAPE_HEIGHTFIELD && getShapeType() != PhysicsCollisionShape::SHAPE_MESH);
 }
 
 void PhysicsRigidBody::transformChanged(Transform* transform, long cookie)
 {
-	if (getShapeType() == PhysicsCollisionShape::SHAPE_HEIGHTFIELD)
-	{
-		_collisionShape->_shapeData.heightfieldData->inverseIsDirty = true;
-	}
+    if (getShapeType() == PhysicsCollisionShape::SHAPE_HEIGHTFIELD)
+    {
+        _collisionShape->_shapeData.heightfieldData->inverseIsDirty = true;
+    }
 }
 
 }

+ 0 - 10
gameplay/src/PhysicsRigidBody.h

@@ -289,16 +289,6 @@ private:
      */
     PhysicsRigidBody(const PhysicsRigidBody& body);
 
-    /**
-     * Creates a rigid body from the rigid body file at the given path.
-     * 
-     * @param node The node to create a rigid body for; note that the node must have
-     *      a model attached to it prior to creating a rigid body for it.
-     * @param filePath The path to the rigid body file.
-     * @return The rigid body or <code>NULL</code> if the rigid body could not be loaded.
-     */
-    static PhysicsRigidBody* create(Node* node, const char* filePath);
-
     /**
      * Creates a rigid body from the specified properties object.
      * 

+ 14 - 14
gameplay/src/Rectangle.cpp

@@ -9,12 +9,12 @@ Rectangle::Rectangle()
 {
 }
 
-Rectangle::Rectangle(float width, float height) :
+Rectangle::Rectangle(unsigned int width, unsigned int height) :
     x(0), y(0), width(width), height(height)
 {
 }
 
-Rectangle::Rectangle(float x, float y, float width, float height) :
+Rectangle::Rectangle(float x, float y, unsigned int width, unsigned int height) :
     x(x), y(y), width(width), height(height)
 {
 }
@@ -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, unsigned int width, unsigned int 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
@@ -70,22 +70,22 @@ float Rectangle::top() const
 
 float Rectangle::right() const
 {
-    return x + width;
+    return x + (float)width;
 }
 
 float Rectangle::bottom() const
 {
-    return y + height;
+    return y + (float)height;
 }
 
 bool Rectangle::contains(float x, float y) const
 {
-    return (x >= x && x <= (x + width) && y >= y && y <= (y + height));
+    return (x >= x && x <= (x + (float)width) && y >= y && y <= (y + (float)height));
 }
 
-bool Rectangle::contains(float x, float y, float width, float height) const
+bool Rectangle::contains(float x, float y, unsigned int width, unsigned int height) const
 {
-    return (contains(x, y) && contains(x + width, y + height));
+    return (contains(x, y) && contains(x + (float)width, y + (float)height));
 }
 
 bool Rectangle::contains(const Rectangle& r) const
@@ -93,12 +93,12 @@ bool Rectangle::contains(const Rectangle& r) const
     return contains(r.x, r.y, r.width, r.height);
 }
 
-bool Rectangle::intersects(float x, float y, float width, float height) const
+bool Rectangle::intersects(float x, float y, unsigned int width, unsigned int height) const
 {
     const float left   = max(this->x, x);
     const float top    = max(this->y, y);
-    const float right  = min(x + width, x + width);
-    const float bottom = min(y + height, y + height);
+    const float right  = min(x + (float)width, x + (float)width);
+    const float bottom = min(y + (float)height, y + (float)height);
 
     return (right > left && bottom > top);
 }

+ 14 - 14
gameplay/src/Rectangle.h

@@ -25,12 +25,12 @@ public:
     /**
      * Specifies the width of the rectangle.
      */
-    float width;
+    unsigned int width;
 
     /**
      * Specifies the height of the rectangle.
      */
-    float height;
+    unsigned int height;
 
     /**
      * Constructs a new rectangle initialized to all zeros.
@@ -43,7 +43,7 @@ public:
      * @param width The width of the rectangle.
      * @param height The height of the rectangle.
      */
-    Rectangle(float width, float height);
+    Rectangle(unsigned int width, unsigned int height);
 
     /**
      * Constructs a new rectangle with the specified x, y, width and height.
@@ -53,7 +53,7 @@ public:
      * @param width The width of the rectangle.
      * @param height The height of the rectangle.
      */
-    Rectangle(float x, float y, float width, float height);
+    Rectangle(float x, float y, unsigned int width, unsigned int height);
 
     /**
      * Constructs a new rectangle that is a copy of the specified rectangle.
@@ -89,22 +89,22 @@ public:
      * @param width The width of the rectangle.
      * @param height The height of the rectangle.
      */
-    void set(float x, float y, float width, float height);
+    void set(float x, float y, unsigned int width, unsigned int 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.
@@ -155,7 +155,7 @@ public:
      * @return true if the rectangle contains the specified rectangle, false
      * otherwise.
      */
-    bool contains(float x, float y, float width, float height) const;
+    bool contains(float x, float y, unsigned int width, unsigned int height) const;
 
     /**
      * Determines whether this rectangle contains a specified rectangle.
@@ -177,7 +177,7 @@ public:
      * 
      * @return true if the specified Rectangle intersects with this one, false otherwise.
      */
-    bool intersects(float x, float y, float width, float height) const;
+    bool intersects(float x, float y, unsigned int width, unsigned int height) const;
 
     /**
      * Determines whether a specified rectangle intersects with this rectangle.

+ 0 - 10
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;

+ 0 - 15
gameplay/src/Scene.h

@@ -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.
      * 
@@ -223,7 +209,6 @@ private:
 
     std::string _id;
     Camera* _activeCamera;
-    Viewport _viewport;
     Node* _firstNode;
     Node* _lastNode;
     unsigned int _nodeCount;

+ 58 - 28
gameplay/src/SceneLoader.cpp

@@ -51,9 +51,9 @@ Scene* SceneLoader::load(const char* filePath)
 
     // First apply the node url properties. Following that,
     // apply the normal node properties and create the animations.
-    // We apply rigid body properties after all other node properties
+    // We apply physics properties after all other node properties
     // so that the transform (SRT) properties get applied before
-    // processing rigid bodies.
+    // processing physics collision objects.
     applyNodeUrls(scene);
     applyNodeProperties(scene, sceneProperties, 
         SceneNodeProperty::AUDIO | 
@@ -62,7 +62,7 @@ Scene* SceneLoader::load(const char* filePath)
         SceneNodeProperty::ROTATE |
         SceneNodeProperty::SCALE |
         SceneNodeProperty::TRANSLATE);
-    applyNodeProperties(scene, sceneProperties, SceneNodeProperty::RIGIDBODY);
+    applyNodeProperties(scene, sceneProperties, SceneNodeProperty::CHARACTER | SceneNodeProperty::GHOST | SceneNodeProperty::RIGIDBODY);
     createAnimations(scene);
 
     // Find the physics properties object.
@@ -194,6 +194,8 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
     if (snp._type == SceneNodeProperty::AUDIO ||
         snp._type == SceneNodeProperty::MATERIAL ||
         snp._type == SceneNodeProperty::PARTICLE ||
+        snp._type == SceneNodeProperty::CHARACTER ||
+        snp._type == SceneNodeProperty::GHOST ||
         snp._type == SceneNodeProperty::RIGIDBODY)
     {
         // Check to make sure the referenced properties object was loaded properly.
@@ -247,6 +249,8 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
             SAFE_RELEASE(particleEmitter);
             break;
         }
+        case SceneNodeProperty::CHARACTER:
+        case SceneNodeProperty::GHOST:
         case SceneNodeProperty::RIGIDBODY:
         {
             // Check to make sure the referenced properties object was loaded properly.
@@ -274,38 +278,56 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
                 p = p->getNextNamespace();
             }
 
-            // If the scene file specifies a rigid body model, use it for creating the rigid body.
-            Properties* np = sceneProperties->getNamespace(sceneNode._nodeID);
-            const char* name = NULL;
-            if (np && (name = np->getString("rigidbodymodel")))
+            // Check to make sure the type of the namespace used to load the physics collision object is correct.
+            if (snp._type == SceneNodeProperty::CHARACTER && strcmp(p->getNamespace(), "character") != 0)
             {
-                Node* modelNode = node->getScene()->findNode(name);
-                if (!modelNode)
-                    WARN_VARG("Node '%s' does not exist; attempting to use its model for rigid body creation.", name);
-                else
+                WARN_VARG("Attempting to set a 'character' (physics collision object attribute) on a node using a '%s' definition.", p->getNamespace());
+            }
+            else if (snp._type == SceneNodeProperty::GHOST && strcmp(p->getNamespace(), "ghost") != 0)
+            {
+                WARN_VARG("Attempting to set a 'ghost' (physics collision object attribute) on a node using a '%s' definition.", p->getNamespace());
+            }
+            else if (snp._type == SceneNodeProperty::RIGIDBODY && strcmp(p->getNamespace(), "rigidbody") != 0)
+            {
+                WARN_VARG("Attempting to set a 'rigidbody' (physics collision object attribute) on a node using a '%s' definition.", p->getNamespace());
+            }
+            else
+            {
+                // If the scene file specifies a rigid body model, use it for creating the collision object.
+                Properties* np = sceneProperties->getNamespace(sceneNode._nodeID);
+                const char* name = NULL;
+                if (np && (name = np->getString("rigidbodymodel")))
                 {
-                    if (!modelNode->getModel())
-                        WARN_VARG("Node '%s' does not have a model; attempting to use its model for rigid body creation.", name);
+                    Node* modelNode = node->getScene()->findNode(name);
+                    if (!modelNode)
+                        WARN_VARG("Node '%s' does not exist; attempting to use its model for collision object creation.", name);
                     else
                     {
-                        // Temporarily set rigidbody model on model to it's used during rigid body creation.
-                        Model* model = node->getModel();
-						model->addRef(); // up ref count to prevent node from releasing the model when we swap it
-                        node->setModel(modelNode->getModel());
-
-						// Create collision object with new rigidbodymodel set.
-						node->setCollisionObject(p);
-
-						// Restore original model
-                        node->setModel(model);
-						model->release(); // decrement temporarily added reference
+                        if (!modelNode->getModel())
+                            WARN_VARG("Node '%s' does not have a model; attempting to use its model for collision object creation.", name);
+                        else
+                        {
+                            // Temporarily set rigidbody model on model so it's used during collision object creation.
+                            Model* model = node->getModel();
+                        
+                            // Up ref count to prevent node from releasing the model when we swap it.
+						    model->addRef(); 
+                        
+						    // Create collision object with new rigidbodymodel set.
+                            node->setModel(modelNode->getModel());
+						    node->setCollisionObject(p);
+
+						    // Restore original model.
+                            node->setModel(model);
+						
+                            // Decrement temporarily added reference.
+                            model->release();
+                        }
                     }
                 }
+                else
+				    node->setCollisionObject(p);
             }
-            else if (!node->getModel())
-                WARN_VARG("Attempting to set a rigid body on node '%s', which has no model.", sceneNode._nodeID);
-            else
-				node->setCollisionObject(p);
             break;
         }
         default:
@@ -522,6 +544,14 @@ void SceneLoader::buildReferenceTables(Properties* sceneProperties)
                 {
                     addSceneNodeProperty(sceneNode, SceneNodeProperty::PARTICLE, ns->getString());
                 }
+                else if (strcmp(name, "character") == 0)
+                {
+                    addSceneNodeProperty(sceneNode, SceneNodeProperty::CHARACTER, ns->getString());
+                }
+                else if (strcmp(name, "ghost") == 0)
+                {
+                    addSceneNodeProperty(sceneNode, SceneNodeProperty::GHOST, ns->getString());
+                }
                 else if (strcmp(name, "rigidbody") == 0)
                 {
                     addSceneNodeProperty(sceneNode, SceneNodeProperty::RIGIDBODY, ns->getString());

+ 7 - 5
gameplay/src/SceneLoader.h

@@ -49,11 +49,13 @@ private:
             AUDIO = 1,
             MATERIAL = 2,
             PARTICLE = 4,
-            RIGIDBODY = 8,
-            TRANSLATE = 16,
-            ROTATE = 32,
-            SCALE = 64,
-            URL = 128
+            CHARACTER = 8,
+            GHOST = 16,
+            RIGIDBODY = 32,
+            TRANSLATE = 64,
+            ROTATE = 128,
+            SCALE = 256,
+            URL = 512
         };
 
         SceneNodeProperty(Type type, std::string file, std::string id, int index) : _type(type), _file(file), _id(id), _index(index) { }

+ 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