Просмотр исходного кода

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

Conflicts:
	gameplay-samples/sample03-character/src/CharacterGame.cpp
Kieran Cunney 13 лет назад
Родитель
Сommit
d91badbc1a

+ 7 - 2
CHANGES.md

@@ -3,7 +3,12 @@
 - Pre-built versions gameplay-encoder added to bin folder with TTF, DAE and FBX support built-in.
 - Pre-built versions gameplay-encoder added to bin folder with TTF, DAE and FBX support built-in.
 - Improved modular shader library with support for #include in shaders.
 - Improved modular shader library with support for #include in shaders.
 - Fixes to FrameBuffer, RenderTarget and DepthStencilTarget.
 - Fixes to FrameBuffer, RenderTarget and DepthStencilTarget.
-- TODO
+- Fixes node cloning.
+- Adds the ability to clone the boy in sample03-character by pressing 'c'.
+- Improvements to gameplay-encoder.
+  - Prompts user for font size if not specified.
+  - Fixes output file path when encoding fonts.
+  - Adds "-g" argument for grouping animations.
 
 
 ## v1.3.0
 ## v1.3.0
 
 
@@ -12,7 +17,7 @@
 - User Interface support for scrolling with scrollbars on Container.
 - User Interface support for scrolling with scrollbars on Container.
 - PVRTC, ATC and DXT texture compression support.
 - PVRTC, ATC and DXT texture compression support.
 - Performance improvements in user interface forms and text.
 - Performance improvements in user interface forms and text.
-- Performance improvements in animations on transforms.
+- Performance improvements in animations on transforms.
 - Performance improvements using NEON math for BlackBerry and iOS.
 - Performance improvements using NEON math for BlackBerry and iOS.
 - Fixes for improvements in error handling throughout all systems.
 - Fixes for improvements in error handling throughout all systems.
 - Fixes supporting built-in Maya COLLADA exporter via DAE_FBX export.
 - Fixes supporting built-in Maya COLLADA exporter via DAE_FBX export.

+ 23 - 0
gameplay-encoder/gameplay-encoder.sln

@@ -0,0 +1,23 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gameplay-encoder", "gameplay-encoder.vcxproj", "{9D69B743-4872-4DD1-8E30-0087C64298D7}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		DebugMem|Win32 = DebugMem|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{9D69B743-4872-4DD1-8E30-0087C64298D7}.Debug|Win32.ActiveCfg = Debug|Win32
+		{9D69B743-4872-4DD1-8E30-0087C64298D7}.Debug|Win32.Build.0 = Debug|Win32
+		{9D69B743-4872-4DD1-8E30-0087C64298D7}.DebugMem|Win32.ActiveCfg = Debug|Win32
+		{9D69B743-4872-4DD1-8E30-0087C64298D7}.DebugMem|Win32.Build.0 = Debug|Win32
+		{9D69B743-4872-4DD1-8E30-0087C64298D7}.Release|Win32.ActiveCfg = Release|Win32
+		{9D69B743-4872-4DD1-8E30-0087C64298D7}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 2 - 2
gameplay/gameplay.vcxproj

@@ -206,8 +206,6 @@
     <None Include="res\logo_powered_black.png" />
     <None Include="res\logo_powered_black.png" />
     <None Include="res\logo_powered_white.png" />
     <None Include="res\logo_powered_white.png" />
     <None Include="res\logo_white.png" />
     <None Include="res\logo_white.png" />
-    <None Include="res\shaders\bumped.frag" />
-    <None Include="res\shaders\bumped.vert" />
     <None Include="res\shaders\colored-unlit.frag" />
     <None Include="res\shaders\colored-unlit.frag" />
     <None Include="res\shaders\colored-unlit.vert" />
     <None Include="res\shaders\colored-unlit.vert" />
     <None Include="res\shaders\colored.frag" />
     <None Include="res\shaders\colored.frag" />
@@ -221,6 +219,8 @@
     <None Include="res\shaders\lib\lighting-spot.frag" />
     <None Include="res\shaders\lib\lighting-spot.frag" />
     <None Include="res\shaders\lib\lighting-spot.vert" />
     <None Include="res\shaders\lib\lighting-spot.vert" />
     <None Include="res\shaders\lib\lighting.frag" />
     <None Include="res\shaders\lib\lighting.frag" />
+    <None Include="res\shaders\textured-bumped.frag" />
+    <None Include="res\shaders\textured-bumped.vert" />
     <None Include="res\shaders\textured-unlit.frag" />
     <None Include="res\shaders\textured-unlit.frag" />
     <None Include="res\shaders\textured-unlit.vert" />
     <None Include="res\shaders\textured-unlit.vert" />
     <None Include="res\shaders\textured.frag" />
     <None Include="res\shaders\textured.frag" />

+ 6 - 6
gameplay/gameplay.vcxproj.filters

@@ -637,12 +637,6 @@
     <None Include="res\shaders\colored-unlit.frag">
     <None Include="res\shaders\colored-unlit.frag">
       <Filter>res\shaders</Filter>
       <Filter>res\shaders</Filter>
     </None>
     </None>
-    <None Include="res\shaders\bumped.vert">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\bumped.frag">
-      <Filter>res\shaders</Filter>
-    </None>
     <None Include="res\shaders\lib\lighting.frag">
     <None Include="res\shaders\lib\lighting.frag">
       <Filter>res\shaders\lib</Filter>
       <Filter>res\shaders\lib</Filter>
     </None>
     </None>
@@ -670,6 +664,12 @@
     <None Include="res\shaders\lib\attributes-skinning.vert">
     <None Include="res\shaders\lib\attributes-skinning.vert">
       <Filter>res\shaders\lib</Filter>
       <Filter>res\shaders\lib</Filter>
     </None>
     </None>
+    <None Include="res\shaders\textured-bumped.frag">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\textured-bumped.vert">
+      <Filter>res\shaders</Filter>
+    </None>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <None Include="src\PhysicsFixedConstraint.inl">
     <None Include="src\PhysicsFixedConstraint.inl">

+ 8 - 3
gameplay/res/shaders/colored-unlit.frag

@@ -7,9 +7,11 @@ precision highp float;
 varying vec3 v_color;						// Input Vertex color ( r g b )
 varying vec3 v_color;						// Input Vertex color ( r g b )
 #endif
 #endif
 
 
-uniform vec4 u_diffuseColor;               	// Diffuse color
-
 // Uniforms
 // Uniforms
+uniform vec4 u_diffuseColor;               	// Diffuse color
+#if defined(TEXTURE_LIGHTMAP)
+uniform sampler2D u_lightmapTexture;     	// Lightmap texture
+#endif
 #if defined(MODULATE_COLOR)
 #if defined(MODULATE_COLOR)
 uniform vec4 u_modulateColor;               // Modulation color
 uniform vec4 u_modulateColor;               // Modulation color
 #endif
 #endif
@@ -26,7 +28,10 @@ void main()
 	#else
 	#else
 	gl_FragColor = u_diffuseColor;
 	gl_FragColor = u_diffuseColor;
     #endif
     #endif
-	
+	#if defined(TEXTURE_LIGHTMAP)
+	vec4 lightColor = texture2D(u_lightmapTexture, v_texCoord);
+	gl_FragColor.a *= lightColor.a;
+	#endif
 	// Global color modulation
 	// Global color modulation
 	#if defined(MODULATE_COLOR)
 	#if defined(MODULATE_COLOR)
 	gl_FragColor *= u_modulateColor;
 	gl_FragColor *= u_modulateColor;

+ 0 - 0
gameplay/res/shaders/bumped.frag → gameplay/res/shaders/textured-bumped.frag


+ 0 - 0
gameplay/res/shaders/bumped.vert → gameplay/res/shaders/textured-bumped.vert


+ 3 - 3
gameplay/res/shaders/textured-unlit.frag

@@ -4,7 +4,7 @@ precision highp float;
 
 
 // Uniforms
 // Uniforms
 uniform sampler2D u_diffuseTexture;     	// Diffuse texture
 uniform sampler2D u_diffuseTexture;     	// Diffuse texture
-#if defined(TEXTURE_LIGHT)
+#if defined(TEXTURE_LIGHTMAP)
 uniform sampler2D u_lightmapTexture;     	// Lightmap texture
 uniform sampler2D u_lightmapTexture;     	// Lightmap texture
 #endif
 #endif
 #if defined(MODULATE_COLOR)
 #if defined(MODULATE_COLOR)
@@ -22,8 +22,8 @@ void main()
 {
 {
     // Sample the texture for the color
     // Sample the texture for the color
     gl_FragColor = texture2D(u_diffuseTexture, v_texCoord);
     gl_FragColor = texture2D(u_diffuseTexture, v_texCoord);
-	#if defined(TEXTURE_LIGHT)
-	vec4 lightColor = texture2D(u_lightTexture, v_texCoord);
+	#if defined(TEXTURE_LIGHTMAP)
+	vec4 lightColor = texture2D(u_lightmapTexture, v_texCoord);
 	gl_FragColor.a *= lightColor.a;
 	gl_FragColor.a *= lightColor.a;
 	#endif
 	#endif
 	// Global color modulation
 	// Global color modulation

+ 10 - 0
gameplay/src/Animation.cpp

@@ -450,6 +450,16 @@ Animation* Animation::clone(Channel* channel, AnimationTarget* target)
     // Release the animation because a newly created animation has a ref count of 1 and the channels hold the ref to animation.
     // Release the animation because a newly created animation has a ref count of 1 and the channels hold the ref to animation.
     animation->release();
     animation->release();
     GP_ASSERT(animation->getRefCount() == 1);
     GP_ASSERT(animation->getRefCount() == 1);
+
+    // Clone the clips
+    if (_clips)
+    {
+        for (std::vector<AnimationClip*>::iterator it = _clips->begin(); it != _clips->end(); ++it)
+        {
+            AnimationClip* newClip = (*it)->clone(animation);
+            animation->addClip(newClip);
+        }
+    }
     return animation;
     return animation;
 }
 }
 
 

+ 25 - 0
gameplay/src/AnimationClip.cpp

@@ -550,4 +550,29 @@ void AnimationClip::resetClipStateBit(unsigned char bit)
     _stateBits &= ~bit;
     _stateBits &= ~bit;
 }
 }
 
 
+AnimationClip* AnimationClip::clone(Animation* animation) const
+{
+    // Don't clone the elapsed time, listeners or crossfade information.
+    AnimationClip* newClip = new AnimationClip(getID(), animation, getStartTime(), getEndTime());
+    newClip->setRepeatCount(getRepeatCount());
+    newClip->setSpeed(getSpeed());
+    newClip->setRepeatCount(getRepeatCount());
+    newClip->setBlendWeight(getBlendWeight());
+    
+    size_t size = _values.size();
+    newClip->_values.resize(size, NULL);
+    for (size_t i = 0; i < size; ++i)
+    {
+        if (newClip->_values[i] == NULL)
+        {
+            newClip->_values[i] = new AnimationValue(*_values[i]);
+        }
+        else
+        {
+            *newClip->_values[i] = *_values[i];
+        }
+    }
+    return newClip;
 }
 }
+
+}

+ 9 - 0
gameplay/src/AnimationClip.h

@@ -310,6 +310,15 @@ private:
      */
      */
     void resetClipStateBit(unsigned char bit);
     void resetClipStateBit(unsigned char bit);
 
 
+    /**
+     * Clones the animation clip.
+     * 
+     * @param animation The animation that the new clip belongs to.
+     * 
+     * @return The newly created animation clip.
+     */
+    AnimationClip* clone(Animation* animation) const;
+
     std::string _id;                                    // AnimationClip ID.
     std::string _id;                                    // AnimationClip ID.
     Animation* _animation;                              // The Animation this clip is created from.
     Animation* _animation;                              // The Animation this clip is created from.
     unsigned long _startTime;                           // Start time of the clip.
     unsigned long _startTime;                           // Start time of the clip.

+ 24 - 0
gameplay/src/AnimationValue.cpp

@@ -11,11 +11,35 @@ AnimationValue::AnimationValue(unsigned int componentCount)
     _value = new float[_componentCount];
     _value = new float[_componentCount];
 }
 }
 
 
+AnimationValue::AnimationValue(const AnimationValue& copy)
+{
+    _value = new float[copy._componentCount];
+    _componentSize = copy._componentSize;
+    _componentCount = copy._componentCount;
+    memcpy(_value, copy._value, _componentSize);
+}
+
 AnimationValue::~AnimationValue()
 AnimationValue::~AnimationValue()
 {
 {
     SAFE_DELETE_ARRAY(_value);
     SAFE_DELETE_ARRAY(_value);
 }
 }
 
 
+AnimationValue& AnimationValue::operator=(const AnimationValue& v)
+{
+    if (this != &v)
+    {
+        if (_value == NULL || _componentSize != v._componentSize || _componentCount != v._componentCount)
+        {
+            _componentSize = v._componentSize;
+            _componentCount = v._componentCount;
+            SAFE_DELETE_ARRAY(_value);
+            _value = new float[v._componentCount];
+        }
+        memcpy(_value, v._value, _componentSize);
+    }
+    return *this;
+}
+
 float AnimationValue::getFloat(unsigned int index) const
 float AnimationValue::getFloat(unsigned int index) const
 {
 {
     GP_ASSERT(index < _componentCount);
     GP_ASSERT(index < _componentCount);

+ 5 - 0
gameplay/src/AnimationValue.h

@@ -72,6 +72,11 @@ private:
      */
      */
     ~AnimationValue();
     ~AnimationValue();
 
 
+    /**
+     * Hidden copy assignment operator.
+     */
+    AnimationValue& operator=(const AnimationValue& v);
+
     unsigned int _componentCount;   // The number of float values for the property.
     unsigned int _componentCount;   // The number of float values for the property.
     unsigned int _componentSize;    // The number of bytes of memory the property is.
     unsigned int _componentSize;    // The number of bytes of memory the property is.
     float* _value;                  // The current value of the property.
     float* _value;                  // The current value of the property.

+ 4 - 12
gameplay/src/Container.cpp

@@ -271,7 +271,6 @@ Control* Container::getControl(const char* id) const
             }
             }
         }
         }
     }
     }
-
     return NULL;
     return NULL;
 }
 }
 
 
@@ -381,13 +380,10 @@ void Container::draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needs
     if (needsClear)
     if (needsClear)
     {
     {
         GL_ASSERT( glEnable(GL_SCISSOR_TEST) );
         GL_ASSERT( glEnable(GL_SCISSOR_TEST) );
-        GL_ASSERT( glClearColor(0, 0, 0, 0) );
         float clearY = targetHeight - _clearBounds.y - _clearBounds.height;
         float clearY = targetHeight - _clearBounds.y - _clearBounds.height;
-        GL_ASSERT( glScissor(_clearBounds.x, clearY,
-            _clearBounds.width, _clearBounds.height) );
-        GL_ASSERT( glClear(GL_COLOR_BUFFER_BIT) );
+        GL_ASSERT( glScissor(_clearBounds.x, clearY, _clearBounds.width, _clearBounds.height) );
+        Game::getInstance()->clear(Game::CLEAR_COLOR, Vector4::zero(), 1.0f, 0);
         GL_ASSERT( glDisable(GL_SCISSOR_TEST) );
         GL_ASSERT( glDisable(GL_SCISSOR_TEST) );
-
         needsClear = false;
         needsClear = false;
         cleared = true;
         cleared = true;
     }
     }
@@ -440,9 +436,7 @@ void Container::draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needs
 
 
             clipRegion.width += verticalRegion.width;
             clipRegion.width += verticalRegion.width;
 
 
-            Rectangle bounds(_viewportBounds.x + _viewportBounds.width - verticalRegion.width,
-                             _viewportBounds.y + _scrollBarBounds.y,
-                             topRegion.width, topRegion.height);
+            Rectangle bounds(_viewportBounds.x + _viewportBounds.width - verticalRegion.width, _viewportBounds.y + _scrollBarBounds.y, topRegion.width, topRegion.height);
             spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, topUVs.u1, topUVs.v1, topUVs.u2, topUVs.v2, topColor, clipRegion);
             spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, topUVs.u1, topUVs.v1, topUVs.u2, topUVs.v2, topColor, clipRegion);
 
 
             bounds.y += topRegion.height;
             bounds.y += topRegion.height;
@@ -474,9 +468,7 @@ void Container::draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needs
 
 
             clipRegion.height += horizontalRegion.height;
             clipRegion.height += horizontalRegion.height;
         
         
-            Rectangle bounds(_viewportBounds.x + _scrollBarBounds.x,
-                             _viewportBounds.y + _viewportBounds.height - horizontalRegion.height,
-                             leftRegion.width, leftRegion.height);
+            Rectangle bounds(_viewportBounds.x + _scrollBarBounds.x, _viewportBounds.y + _viewportBounds.height - horizontalRegion.height, leftRegion.width, leftRegion.height);
             spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, leftUVs.u1, leftUVs.v1, leftUVs.u2, leftUVs.v2, leftColor, clipRegion);
             spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, leftUVs.u1, leftUVs.v1, leftUVs.u2, leftUVs.v2, leftColor, clipRegion);
 
 
             bounds.x += leftRegion.width;
             bounds.x += leftRegion.width;

+ 2 - 4
gameplay/src/Control.cpp

@@ -977,10 +977,8 @@ void Control::draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needsCl
     if (needsClear)
     if (needsClear)
     {
     {
         GL_ASSERT( glEnable(GL_SCISSOR_TEST) );
         GL_ASSERT( glEnable(GL_SCISSOR_TEST) );
-        GL_ASSERT( glClearColor(0, 0, 0, 0) );
-        GL_ASSERT( glScissor(_clearBounds.x, targetHeight - _clearBounds.y - _clearBounds.height,
-            _clearBounds.width, _clearBounds.height) );
-        GL_ASSERT( glClear(GL_COLOR_BUFFER_BIT) );
+        GL_ASSERT( glScissor(_clearBounds.x, targetHeight - _clearBounds.y - _clearBounds.height, _clearBounds.width, _clearBounds.height) );
+        Game::getInstance()->clear(Game::CLEAR_COLOR, Vector4::zero(), 1.0f, 0);
         GL_ASSERT( glDisable(GL_SCISSOR_TEST) );
         GL_ASSERT( glDisable(GL_SCISSOR_TEST) );
     }
     }
 
 

+ 5 - 2
gameplay/src/Effect.cpp

@@ -253,7 +253,9 @@ Effect* Effect::createFromSource(const char* vshPath, const char* vshSource, con
         }
         }
 
 
         // Write out the expanded shader file.
         // Write out the expanded shader file.
-        writeShaderToErrorFile(vshPath, shaderSource[2]);
+        if (vshPath)
+            writeShaderToErrorFile(vshPath, shaderSource[2]);
+
         GP_ERROR("Compile failed for vertex shader '%s' with error '%s'.", vshPath == NULL ? "NULL" : vshPath, infoLog == NULL ? "" : infoLog);
         GP_ERROR("Compile failed for vertex shader '%s' with error '%s'.", vshPath == NULL ? "NULL" : vshPath, infoLog == NULL ? "" : infoLog);
         SAFE_DELETE_ARRAY(infoLog);
         SAFE_DELETE_ARRAY(infoLog);
 
 
@@ -290,7 +292,8 @@ Effect* Effect::createFromSource(const char* vshPath, const char* vshSource, con
         }
         }
         
         
         // Write out the expanded shader file.
         // Write out the expanded shader file.
-        writeShaderToErrorFile(fshPath, shaderSource[2]);
+        if (fshPath)
+            writeShaderToErrorFile(fshPath, shaderSource[2]);
 
 
         GP_ERROR("Compile failed for fragment shader (%s): %s", fshPath == NULL ? "NULL" : fshPath, infoLog == NULL ? "" : infoLog);
         GP_ERROR("Compile failed for fragment shader (%s): %s", fshPath == NULL ? "NULL" : fshPath, infoLog == NULL ? "" : infoLog);
         SAFE_DELETE_ARRAY(infoLog);
         SAFE_DELETE_ARRAY(infoLog);

+ 123 - 111
gameplay/src/Form.cpp

@@ -10,12 +10,35 @@
 #include "CheckBox.h"
 #include "CheckBox.h"
 #include "Scene.h"
 #include "Scene.h"
 
 
+#define FORM_VSH \
+    "uniform mat4 u_worldViewProjectionMatrix;\n" \
+    "attribute vec3 a_position;\n" \
+    "attribute vec2 a_texCoord;\n" \
+    "varying vec2 v_texCoord;\n" \
+    "void main()\n" \
+    "{\n" \
+        "gl_Position = u_worldViewProjectionMatrix * vec4(a_position, 1);\n" \
+        "v_texCoord = a_texCoord;\n" \
+    "}\n"
+
+#define FORM_FSH \
+    "#ifdef OPENGL_ES\n" \
+    "precision highp float;\n" \
+    "#endif\n" \
+    "varying vec2 v_texCoord;\n" \
+    "uniform sampler2D u_texture;\n" \
+    "void main()\n" \
+    "{\n" \
+        "gl_FragColor = texture2D(u_texture, v_texCoord);\n" \
+    "}\n"
+
 namespace gameplay
 namespace gameplay
 {
 {
 
 
+static Effect* __formEffect = NULL;
 static std::vector<Form*> __forms;
 static std::vector<Form*> __forms;
 
 
-Form::Form() : _theme(NULL), _quad(NULL), _node(NULL), _frameBuffer(NULL), _spriteBatch(NULL)
+Form::Form() : _theme(NULL), _frameBuffer(NULL), _spriteBatch(NULL), _node(NULL), _nodeQuad(NULL), _nodeMaterial(NULL) , _u2(0), _v1(0)
 {
 {
 }
 }
 
 
@@ -25,11 +48,19 @@ Form::Form(const Form& copy)
 
 
 Form::~Form()
 Form::~Form()
 {
 {
-    SAFE_RELEASE(_quad);
     SAFE_RELEASE(_node);
     SAFE_RELEASE(_node);
+    SAFE_DELETE(_spriteBatch);
     SAFE_RELEASE(_frameBuffer);
     SAFE_RELEASE(_frameBuffer);
     SAFE_RELEASE(_theme);
     SAFE_RELEASE(_theme);
-    SAFE_DELETE(_spriteBatch);
+
+    if (__formEffect)
+    {
+        if (__formEffect->getRefCount() == 1)
+        {
+            __formEffect->release();
+            __formEffect = NULL;
+        }
+    }
 
 
     // Remove this Form from the global list.
     // Remove this Form from the global list.
     std::vector<Form*>::iterator it = std::find(__forms.begin(), __forms.end(), this);
     std::vector<Form*>::iterator it = std::find(__forms.begin(), __forms.end(), this);
@@ -190,7 +221,6 @@ Form* Form::getForm(const char* id)
             return f;
             return f;
         }
         }
     }
     }
-        
     return NULL;
     return NULL;
 }
 }
 
 
@@ -234,15 +264,13 @@ void Form::setSize(float width, float height)
         _spriteBatch = SpriteBatch::create(_frameBuffer->getRenderTarget()->getTexture());
         _spriteBatch = SpriteBatch::create(_frameBuffer->getRenderTarget()->getTexture());
         GP_ASSERT(_spriteBatch);
         GP_ASSERT(_spriteBatch);
 
 
-        // Clear FBO.
-        _frameBuffer->bind();
+        // Clear the framebuffer black
         Game* game = Game::getInstance();
         Game* game = Game::getInstance();
+        _frameBuffer->bind();
         Rectangle prevViewport = game->getViewport();
         Rectangle prevViewport = game->getViewport();
         game->setViewport(Rectangle(0, 0, width, height));
         game->setViewport(Rectangle(0, 0, width, height));
         _theme->setProjectionMatrix(_projectionMatrix);
         _theme->setProjectionMatrix(_projectionMatrix);
-        GL_ASSERT( glClearColor(0, 0, 0, 0) );
-        GL_ASSERT( glClear(GL_COLOR_BUFFER_BIT) );
-        GL_ASSERT( glClearColor(0, 0, 0, 1) );
+        game->clear(Game::CLEAR_COLOR, Vector4::zero(), 1.0, 0);
         _theme->setProjectionMatrix(_defaultProjectionMatrix);
         _theme->setProjectionMatrix(_defaultProjectionMatrix);
         FrameBuffer::bindDefault();
         FrameBuffer::bindDefault();
         game->setViewport(prevViewport);
         game->setViewport(prevViewport);
@@ -287,51 +315,83 @@ void Form::setAutoHeight(bool autoHeight)
     }
     }
 }
 }
 
 
-void Form::setQuad(const Vector3& p1, const Vector3& p2, const Vector3& p3, const Vector3& p4)
+Effect* createEffect()
 {
 {
-    Mesh* mesh = Mesh::createQuad(p1, p2, p3, p4);
-    initializeQuad(mesh);
-    SAFE_RELEASE(mesh);
-}
-
-void Form::setQuad(float x, float y, float width, float height)
-{
-    float x2 = x + width;
-    float y2 = y + height;
-
-    float vertices[] =
+    Effect* effect = NULL;
+    if (__formEffect == NULL)
     {
     {
-        x, y2, 0,   0, _v1,
-        x, y, 0,    0, 0,
-        x2, y2, 0,  _u2, _v1,
-        x2, y, 0,   _u2, 0
-    };
-
-    VertexFormat::Element elements[] =
+        __formEffect = Effect::createFromSource(FORM_VSH, FORM_FSH);
+        if (__formEffect == NULL)
+        {
+            GP_ERROR("Unable to load form effect.");
+            return NULL;
+        }
+        effect = __formEffect;
+    }
+    else
     {
     {
-        VertexFormat::Element(VertexFormat::POSITION, 3),
-        VertexFormat::Element(VertexFormat::TEXCOORD0, 2)
-    };
-    Mesh* mesh = Mesh::createMesh(VertexFormat(elements, 2), 4, false);
-    assert(mesh);
-
-    mesh->setPrimitiveType(Mesh::TRIANGLE_STRIP);
-    mesh->setVertexData(vertices, 0, 4);
-
-    initializeQuad(mesh);
-    SAFE_RELEASE(mesh);
+        effect = __formEffect;
+    }
+    return effect;
 }
 }
 
 
 void Form::setNode(Node* node)
 void Form::setNode(Node* node)
 {
 {
-    _node = node;
-        
-    if (_node)
+    // If the user wants a custom node then we need to create a 3D quad
+    if (node && node != _node)
     {
     {
         // Set this Form up to be 3D by initializing a quad.
         // Set this Form up to be 3D by initializing a quad.
-        setQuad(0.0f, 0.0f, _bounds.width, _bounds.height);
-        _node->setModel(_quad);
+        float x2 = _bounds.width;
+        float y2 = _bounds.height;
+        float vertices[] =
+        {
+            0, y2, 0,   0, _v1,
+            0, 0, 0,    0, 0,
+            x2, y2, 0,  _u2, _v1,
+            x2, 0, 0,   _u2, 0
+        };
+        VertexFormat::Element elements[] =
+        {
+            VertexFormat::Element(VertexFormat::POSITION, 3),
+            VertexFormat::Element(VertexFormat::TEXCOORD0, 2)
+        };
+        Mesh* mesh = Mesh::createMesh(VertexFormat(elements, 2), 4, false);
+        GP_ASSERT(mesh);
+        mesh->setPrimitiveType(Mesh::TRIANGLE_STRIP);
+        mesh->setVertexData(vertices, 0, 4);
+
+        _nodeQuad = Model::create(mesh);
+        SAFE_RELEASE(mesh);
+        GP_ASSERT(_nodeQuad);
+
+        // Create the effect and material
+        Effect* effect = createEffect();
+        GP_ASSERT(effect);
+        _nodeMaterial = Material::create(effect);
+
+        GP_ASSERT(_nodeMaterial);
+        _nodeQuad->setMaterial(_nodeMaterial);
+        _nodeMaterial->release();
+        node->setModel(_nodeQuad);
+        _nodeQuad->release();
+
+        // Bind the WorldViewProjection matrix.
+        _nodeMaterial->setParameterAutoBinding("u_worldViewProjectionMatrix", RenderState::WORLD_VIEW_PROJECTION_MATRIX);
+
+        // Bind the texture from the framebuffer and set the texture to clamp
+        Texture::Sampler* sampler = Texture::Sampler::create(_frameBuffer->getRenderTarget()->getTexture());
+        GP_ASSERT(sampler);
+        sampler->setWrapMode(Texture::CLAMP, Texture::CLAMP);
+        _nodeMaterial->getParameter("u_texture")->setValue(sampler);
+        sampler->release();
+
+        RenderState::StateBlock* rsBlock = _nodeMaterial->getStateBlock();
+        rsBlock->setDepthWrite(true);
+        rsBlock->setBlend(true);
+        rsBlock->setBlendSrc(RenderState::BLEND_SRC_ALPHA);
+        rsBlock->setBlendDst(RenderState::BLEND_ONE_MINUS_SRC_ALPHA);
     }
     }
+    _node = node;
 }
 }
 
 
 void Form::update()
 void Form::update()
@@ -385,8 +445,7 @@ void Form::update()
         y = 0;
         y = 0;
         _absoluteBounds.set(x, y, _bounds.width, _bounds.height);
         _absoluteBounds.set(x, y, _bounds.width, _bounds.height);
 
 
-        // Calculate the absolute viewport bounds.
-        // Absolute bounds minus border and padding.
+        // Calculate the absolute viewport bounds. Absolute bounds minus border and padding.
         const Theme::Border& border = getBorder(_state);
         const Theme::Border& border = getBorder(_state);
         const Theme::Padding& padding = getPadding();
         const Theme::Padding& padding = getPadding();
 
 
@@ -397,9 +456,7 @@ void Form::update()
 
 
         _viewportBounds.set(x, y, width, height);
         _viewportBounds.set(x, y, width, height);
 
 
-        // Calculate the clip area.
-        // Absolute bounds, minus border and padding,
-        // clipped to the parent container's clip area.
+        // Calculate the clip area. Absolute bounds, minus border and padding, clipped to the parent container's clip area.
         clipX2 = clip.x + clip.width;
         clipX2 = clip.x + clip.width;
         x2 = x + width;
         x2 = x + width;
         if (x2 > clipX2)
         if (x2 > clipX2)
@@ -467,20 +524,15 @@ void Form::update()
 
 
 void Form::draw()
 void Form::draw()
 {
 {
-    /*
-    The first time a form is drawn, its contents are rendered into a framebuffer.
-    The framebuffer will only be drawn into again when the contents of the form change.
-
-    If this form has a node then it's a 3D form and the framebuffer will be used
-    to texture a quad.  The quad will be given the same dimensions as the form and
-    must be transformed appropriately by the user, unless they call setQuad() themselves.
-
-    On the other hand, if this form has not been set on a node, SpriteBatch will be used
-    to render the contents of the frambuffer directly to the display.
-    */
-
-    // Check whether this form has changed since the last call to draw()
-    // and if so, render into the framebuffer.
+    // The first time a form is drawn, its contents are rendered into a framebuffer.
+    // The framebuffer will only be drawn into again when the contents of the form change.
+    // If this form has a node then it's a 3D form and the framebuffer will be used
+    // to texture a quad.  The quad will be given the same dimensions as the form and
+    // must be transformed appropriately by the user, unless they call setQuad() themselves.
+    // On the other hand, if this form has not been set on a node, SpriteBatch will be used
+    // to render the contents of the frambuffer directly to the display.
+
+    // Check whether this form has changed since the last call to draw() and if so, render into the framebuffer.
     if (isDirty())
     if (isDirty())
     {
     {
         GP_ASSERT(_frameBuffer);
         GP_ASSERT(_frameBuffer);
@@ -502,19 +554,20 @@ void Form::draw()
         game->setViewport(prevViewport);
         game->setViewport(prevViewport);
     }
     }
 
 
+    // Draw either with a 3D quad or sprite batch
     if (_node)
     if (_node)
     {
     {
-        GP_ASSERT(_quad);
-        _quad->draw();
+         // If we have the node set, then draw a 3D quad model
+        _nodeQuad->draw();
     }
     }
     else
     else
     {
     {
+        // Otherwise we draw the framebuffer in ortho space with a spritebatch.
         if (!_spriteBatch)
         if (!_spriteBatch)
         {
         {
             _spriteBatch = SpriteBatch::create(_frameBuffer->getRenderTarget()->getTexture());
             _spriteBatch = SpriteBatch::create(_frameBuffer->getRenderTarget()->getTexture());
             GP_ASSERT(_spriteBatch);
             GP_ASSERT(_spriteBatch);
         }
         }
-
         _spriteBatch->begin();
         _spriteBatch->begin();
         _spriteBatch->draw(_bounds.x, _bounds.y, 0, _bounds.width, _bounds.height, 0, _v1, _u2, 0, Vector4::one());
         _spriteBatch->draw(_bounds.x, _bounds.y, 0, _bounds.width, _bounds.height, 0, _v1, _u2, 0, Vector4::one());
         _spriteBatch->end();
         _spriteBatch->end();
@@ -526,38 +579,6 @@ const char* Form::getType() const
     return "form";
     return "form";
 }
 }
 
 
-void Form::initializeQuad(Mesh* mesh)
-{
-    // Release current model.
-    SAFE_RELEASE(_quad);
-
-    // Create the model.
-    _quad = Model::create(mesh);
-
-    // Create the material.
-    Material* material = _quad->setMaterial("res/shaders/textured-unlit.vert", "res/shaders/textured-unlit.frag");
-    GP_ASSERT(material);
-
-    // Set the common render state block for the material.
-    GP_ASSERT(_theme);
-    GP_ASSERT(_theme->getSpriteBatch());
-    RenderState::StateBlock* stateBlock = _theme->getSpriteBatch()->getStateBlock();
-    GP_ASSERT(stateBlock);
-    stateBlock->setDepthWrite(true);
-    material->setStateBlock(stateBlock);
-
-    // Bind the WorldViewProjection matrix.
-    material->setParameterAutoBinding("u_worldViewProjectionMatrix", RenderState::WORLD_VIEW_PROJECTION_MATRIX);
-
-    // Bind the texture.
-    Texture::Sampler* sampler = Texture::Sampler::create(_frameBuffer->getRenderTarget()->getTexture());
-    GP_ASSERT(sampler);
-    sampler->setWrapMode(Texture::CLAMP, Texture::CLAMP);
-    material->getParameter("u_diffuseTexture")->setValue(sampler);
-
-    SAFE_RELEASE(sampler);
-}
-
 bool Form::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
 bool Form::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
 {
 {
     // Check for a collision with each Form in __forms.
     // Check for a collision with each Form in __forms.
@@ -605,7 +626,6 @@ bool Form::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int
             }
             }
         }
         }
     }
     }
-
     return eventConsumed;
     return eventConsumed;
 }
 }
 
 
@@ -622,7 +642,6 @@ bool Form::keyEventInternal(Keyboard::KeyEvent evt, int key)
                 return true;
                 return true;
         }
         }
     }
     }
-
     return false;
     return false;
 }
 }
 
 
@@ -678,7 +697,6 @@ bool Form::mouseEventInternal(Mouse::MouseEvent evt, int x, int y, int wheelDelt
             }
             }
         }
         }
     }
     }
-
     return eventConsumed;
     return eventConsumed;
 }
 }
 
 
@@ -699,14 +717,11 @@ bool Form::projectPoint(int x, int y, Vector3* point)
         Ray ray;
         Ray ray;
         camera->pickRay(Game::getInstance()->getViewport(), 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.
+        // Find the quad's plane.  We know its normal is the quad's forward vector.
         Vector3 normal = _node->getForwardVectorWorld();
         Vector3 normal = _node->getForwardVectorWorld();
 
 
-        // To get the plane's distance from the origin,
-        // we'll find the distance from the plane defined
-        // by the quad's forward vector and one of its points
-        // to the plane defined by the same vector and the origin.
+        // To get the plane's distance from the origin, we'll find the distance from the plane defined
+        // by the quad's forward vector and one of its points to the plane defined by the same vector and the origin.
         const float& a = normal.x; const float& b = normal.y; const float& c = normal.z;
         const float& a = normal.x; const float& b = normal.y; const float& c = normal.z;
         const float d = -(a*min.x) - (b*min.y) - (c*min.z);
         const float d = -(a*min.x) - (b*min.y) - (c*min.z);
         const float distance = abs(d) /  sqrt(a*a + b*b + c*c);
         const float distance = abs(d) /  sqrt(a*a + b*b + c*c);
@@ -716,8 +731,7 @@ bool Form::projectPoint(int x, int y, Vector3* point)
         float collisionDistance = ray.intersects(plane);
         float collisionDistance = ray.intersects(plane);
         if (collisionDistance != Ray::INTERSECTS_NONE)
         if (collisionDistance != Ray::INTERSECTS_NONE)
         {
         {
-            // Multiply the ray's direction vector by collision distance
-            // and add that to the ray's origin.
+            // Multiply the ray's direction vector by collision distance and add that to the ray's origin.
             point->set(ray.getOrigin() + collisionDistance*ray.getDirection());
             point->set(ray.getOrigin() + collisionDistance*ray.getDirection());
 
 
             // Project this point into the plane.
             // Project this point into the plane.
@@ -727,13 +741,11 @@ bool Form::projectPoint(int x, int y, Vector3* point)
             return true;
             return true;
         }
         }
     }
     }
-
     return false;
     return false;
 }
 }
 
 
 unsigned int Form::nextPowerOfTwo(unsigned int v)
 unsigned int Form::nextPowerOfTwo(unsigned int v)
 {
 {
-
     if (!((v & (v - 1)) == 0))
     if (!((v & (v - 1)) == 0))
     {
     {
         v--;
         v--;

+ 12 - 31
gameplay/src/Form.h

@@ -78,7 +78,12 @@ public:
      * @return A form with the given ID, or null if one was not found.
      * @return A form with the given ID, or null if one was not found.
      */
      */
     static Form* getForm(const char* id);
     static Form* getForm(const char* id);
-
+    
+    /**
+     * Gets the theme for the form.
+     *
+     * @return The theme for the form.
+     */
     Theme* getTheme() const;
     Theme* getTheme() const;
 
 
     /**
     /**
@@ -110,30 +115,6 @@ public:
      */
      */
     virtual void setAutoHeight(bool autoHeight);
     virtual void setAutoHeight(bool autoHeight);
 
 
-    /**
-     * Create a 3D quad to texture with this Form.
-     *
-     * The specified points should describe a triangle strip with the first 3 points
-     * forming a triangle wound in counter-clockwise direction, with the second triangle
-     * formed from the last three points in clockwise direction.
-     *
-     * @param p1 The first point.
-     * @param p2 The second point.
-     * @param p3 The third point.
-     * @param p4 The fourth point.
-     */
-    void setQuad(const Vector3& p1, const Vector3& p2, const Vector3& p3, const Vector3& p4);
-
-    /**
-     * Create a 2D quad to texture with this Form.
-     *
-     * @param x The x coordinate.
-     * @param y The y coordinate.
-     * @param width The width of the quad.
-     * @param height The height of the quad.
-     */
-    void setQuad(float x, float y, float width, float height);
-
     /**
     /**
      * Attach this form to a node.
      * Attach this form to a node.
      *
      *
@@ -229,15 +210,15 @@ private:
     bool projectPoint(int x, int y, Vector3* point);
     bool projectPoint(int x, int y, Vector3* point);
 
 
     Theme* _theme;                      // The Theme applied to this Form.
     Theme* _theme;                      // The Theme applied to this Form.
-    Model* _quad;                       // Quad for rendering this Form in world-space.
-    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.
-    Matrix _defaultProjectionMatrix;
+    FrameBuffer* _frameBuffer;          // FBO the Form is rendered into for texturing the quad. 
     SpriteBatch* _spriteBatch;
     SpriteBatch* _spriteBatch;
-
+    Node* _node;                        // Node for transforming this Form in world-space.
+    Model* _nodeQuad;                   // Quad for rendering this Form in 3d space.
+    Material* _nodeMaterial;            // Material for rendering this Form in 3d space.
     float _u2;
     float _u2;
     float _v1;
     float _v1;
+    Matrix _projectionMatrix;           // Orthographic projection matrix to be set on SpriteBatch objects when rendering into the FBO.
+    Matrix _defaultProjectionMatrix;   
 };
 };
 
 
 }
 }

+ 4 - 1
gameplay/src/FrameBuffer.cpp

@@ -24,7 +24,10 @@ FrameBuffer::~FrameBuffer()
     {
     {
         for (unsigned int i = 0; i < __maxRenderTargets; ++i)
         for (unsigned int i = 0; i < __maxRenderTargets; ++i)
         {
         {
-            SAFE_RELEASE(_renderTargets[i]);
+            if (_renderTargets[i])
+            {
+                SAFE_RELEASE(_renderTargets[i]);
+            }
         }
         }
         SAFE_DELETE_ARRAY(_renderTargets);
         SAFE_DELETE_ARRAY(_renderTargets);
     }
     }

+ 9 - 1
gameplay/src/MeshSkin.cpp

@@ -79,7 +79,15 @@ MeshSkin* MeshSkin::clone(NodeCloneContext &context) const
             skin->_rootNode = _rootNode->cloneRecursive(context);
             skin->_rootNode = _rootNode->cloneRecursive(context);
         }
         }
         
         
-        Node* node = skin->_rootNode->findNode(_rootJoint->getId());
+        Node* node = NULL;
+        if (strcmp(skin->_rootNode->getId(), _rootJoint->getId()) == 0)
+        {
+            node = skin->_rootNode;
+        }
+        else
+        {
+            node = skin->_rootNode->findNode(_rootJoint->getId());
+        }
         GP_ASSERT(node);
         GP_ASSERT(node);
         skin->_rootJoint = static_cast<Joint*>(node);
         skin->_rootJoint = static_cast<Joint*>(node);
         for (unsigned int i = 0; i < jointCount; ++i)
         for (unsigned int i = 0; i < jointCount; ++i)

+ 1 - 0
gameplay/src/Scene.cpp

@@ -32,6 +32,7 @@ Scene::~Scene()
 
 
     // Remove all nodes from the scene
     // Remove all nodes from the scene
     removeAllNodes();
     removeAllNodes();
+    SAFE_DELETE(_debugBatch);
 }
 }
 
 
 Scene* Scene::createScene()
 Scene* Scene::createScene()

+ 1 - 1
gameplay/src/SpriteBatch.cpp

@@ -62,7 +62,7 @@ SpriteBatch::~SpriteBatch()
     SAFE_DELETE(_batch);
     SAFE_DELETE(_batch);
     if (!_customEffect)
     if (!_customEffect)
     {
     {
-        if (__spriteEffect->getRefCount() == 1)
+        if (__spriteEffect && __spriteEffect->getRefCount() == 1)
         {
         {
             __spriteEffect->release();
             __spriteEffect->release();
             __spriteEffect = NULL;
             __spriteEffect = NULL;

+ 1 - 0
gameplay/src/Transform.cpp

@@ -853,6 +853,7 @@ void Transform::cloneInto(Transform* transform, NodeCloneContext &context) const
     transform->_scale.set(_scale);
     transform->_scale.set(_scale);
     transform->_rotation.set(_rotation);
     transform->_rotation.set(_rotation);
     transform->_translation.set(_translation);
     transform->_translation.set(_translation);
+    transform->dirty(DIRTY_TRANSLATION | DIRTY_ROTATION | DIRTY_SCALE);
 }
 }
 
 
 void Transform::applyAnimationValueRotation(AnimationValue* value, unsigned int index, float blendWeight)
 void Transform::applyAnimationValueRotation(AnimationValue* value, unsigned int index, float blendWeight)