Parcourir la source

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

Conflicts:
	gameplay-samples/sample03-character/src/CharacterGame.cpp
Steve Grenier il y a 13 ans
Parent
commit
9c5fc534d4

+ 11 - 11
gameplay.sln

@@ -3,11 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 11.00
 # Visual Studio 2010
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gameplay", "gameplay\gameplay.vcxproj", "{1032BA4B-57EB-4348-9E03-29DD63E80E4A}"
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample00-mesh", "gameplay-samples\sample00-mesh\sample00-mesh.vcxproj", "{D672DC66-3CE0-4878-B0D2-813CA731012F}"
-	ProjectSection(ProjectDependencies) = postProject
-		{1032BA4B-57EB-4348-9E03-29DD63E80E4A} = {1032BA4B-57EB-4348-9E03-29DD63E80E4A}
-	EndProjectSection
-EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample01-longboard", "gameplay-samples\sample01-longboard\sample01-longboard.vcxproj", "{9A515C8B-3320-4C5C-9754-211E91206C9D}"
 	ProjectSection(ProjectDependencies) = postProject
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A} = {1032BA4B-57EB-4348-9E03-29DD63E80E4A}
@@ -30,6 +25,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample04-particles", "gamep
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A} = {1032BA4B-57EB-4348-9E03-29DD63E80E4A}
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample00-mesh", "gameplay-samples\sample00-mesh\sample00-mesh.vcxproj", "{D672DC66-3CE0-4878-B0D2-813CA731012F}"
+	ProjectSection(ProjectDependencies) = postProject
+		{1032BA4B-57EB-4348-9E03-29DD63E80E4A} = {1032BA4B-57EB-4348-9E03-29DD63E80E4A}
+	EndProjectSection
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Win32 = Debug|Win32
@@ -43,12 +43,6 @@ Global
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.DebugMem|Win32.Build.0 = DebugMem|Win32
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Release|Win32.ActiveCfg = Release|Win32
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Release|Win32.Build.0 = Release|Win32
-		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Debug|Win32.ActiveCfg = Debug|Win32
-		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Debug|Win32.Build.0 = Debug|Win32
-		{D672DC66-3CE0-4878-B0D2-813CA731012F}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
-		{D672DC66-3CE0-4878-B0D2-813CA731012F}.DebugMem|Win32.Build.0 = DebugMem|Win32
-		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Release|Win32.ActiveCfg = Release|Win32
-		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Release|Win32.Build.0 = Release|Win32
 		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Debug|Win32.ActiveCfg = Debug|Win32
 		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Debug|Win32.Build.0 = Debug|Win32
 		{9A515C8B-3320-4C5C-9754-211E91206C9D}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
@@ -79,6 +73,12 @@ Global
 		{F47B5740-3C0C-BACE-4C2B-EE23A358D499}.DebugMem|Win32.Build.0 = DebugMem|Win32
 		{F47B5740-3C0C-BACE-4C2B-EE23A358D499}.Release|Win32.ActiveCfg = Release|Win32
 		{F47B5740-3C0C-BACE-4C2B-EE23A358D499}.Release|Win32.Build.0 = Release|Win32
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Debug|Win32.ActiveCfg = Debug|Win32
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Debug|Win32.Build.0 = Debug|Win32
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.DebugMem|Win32.Build.0 = DebugMem|Win32
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Release|Win32.ActiveCfg = Release|Win32
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Release|Win32.Build.0 = Release|Win32
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

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

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

+ 1 - 0
gameplay/gameplay.vcxproj

@@ -48,6 +48,7 @@
     <ClCompile Include="src\Image.cpp" />
     <ClCompile Include="src\Joint.cpp" />
     <ClCompile Include="src\Label.cpp" />
+    <ClCompile Include="src\Layout.cpp" />
     <ClCompile Include="src\Light.cpp" />
     <ClCompile Include="src\Material.cpp" />
     <ClCompile Include="src\MeshBatch.cpp" />

+ 3 - 0
gameplay/gameplay.vcxproj.filters

@@ -276,6 +276,9 @@
     <ClCompile Include="src\ThemeStyle.cpp">
       <Filter>src</Filter>
     </ClCompile>
+    <ClCompile Include="src\Layout.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\Animation.h">

+ 6 - 0
gameplay/gameplay.xcodeproj/project.pbxproj

@@ -24,6 +24,8 @@
 		42554EA2152BC35C000ED910 /* PhysicsCollisionShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42554E9F152BC35C000ED910 /* PhysicsCollisionShape.cpp */; };
 		42554EA3152BC35C000ED910 /* PhysicsCollisionShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 42554EA0152BC35C000ED910 /* PhysicsCollisionShape.h */; };
 		42554EA4152BC35C000ED910 /* PhysicsCollisionShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 42554EA0152BC35C000ED910 /* PhysicsCollisionShape.h */; };
+		4271C08E15337C8200B89DA7 /* Layout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4271C08D15337C8200B89DA7 /* Layout.cpp */; };
+		4271C08F15337C8200B89DA7 /* Layout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4271C08D15337C8200B89DA7 /* Layout.cpp */; };
 		428390991489D6E800E2B2F5 /* SceneLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 428390971489D6E800E2B2F5 /* SceneLoader.cpp */; };
 		4283909A1489D6E800E2B2F5 /* SceneLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 428390981489D6E800E2B2F5 /* SceneLoader.h */; };
 		42CCD556146EC1EB00353661 /* libpng.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42CCD555146EC1EB00353661 /* libpng.a */; };
@@ -396,6 +398,7 @@
 		4251B130152D049B002F6199 /* ThemeStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThemeStyle.h; path = src/ThemeStyle.h; sourceTree = SOURCE_ROOT; };
 		42554E9F152BC35C000ED910 /* PhysicsCollisionShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PhysicsCollisionShape.cpp; path = src/PhysicsCollisionShape.cpp; sourceTree = SOURCE_ROOT; };
 		42554EA0152BC35C000ED910 /* PhysicsCollisionShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PhysicsCollisionShape.h; path = src/PhysicsCollisionShape.h; sourceTree = SOURCE_ROOT; };
+		4271C08D15337C8200B89DA7 /* Layout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Layout.cpp; path = src/Layout.cpp; sourceTree = SOURCE_ROOT; };
 		428390971489D6E800E2B2F5 /* SceneLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SceneLoader.cpp; path = src/SceneLoader.cpp; sourceTree = SOURCE_ROOT; };
 		428390981489D6E800E2B2F5 /* SceneLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SceneLoader.h; path = src/SceneLoader.h; sourceTree = SOURCE_ROOT; };
 		42C932AF14919FD10098216A /* Game.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Game.inl; path = src/Game.inl; sourceTree = SOURCE_ROOT; };
@@ -751,6 +754,7 @@
 				4208DEEB14A407B900D3C511 /* Keyboard.h */,
 				5BD52641150F822A004C9099 /* Label.cpp */,
 				5BD52642150F822A004C9099 /* Label.h */,
+				4271C08D15337C8200B89DA7 /* Layout.cpp */,
 				5BD52643150F822A004C9099 /* Layout.h */,
 				42CD0DE6147D8FF50000361E /* Light.cpp */,
 				42CD0DE7147D8FF50000361E /* Light.h */,
@@ -1301,6 +1305,7 @@
 				5BBE143E1513E400003FB362 /* PhysicsGhostObject.cpp in Sources */,
 				42554EA1152BC35C000ED910 /* PhysicsCollisionShape.cpp in Sources */,
 				4251B133152D049B002F6199 /* ThemeStyle.cpp in Sources */,
+				4271C08E15337C8200B89DA7 /* Layout.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1391,6 +1396,7 @@
 				5BBE143F1513E400003FB362 /* PhysicsGhostObject.cpp in Sources */,
 				42554EA2152BC35C000ED910 /* PhysicsCollisionShape.cpp in Sources */,
 				4251B134152D049B002F6199 /* ThemeStyle.cpp in Sources */,
+				4271C08F15337C8200B89DA7 /* Layout.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 6 - 2
gameplay/src/AbsoluteLayout.cpp

@@ -45,9 +45,13 @@ namespace gameplay
         unsigned int controlsCount = controls.size();
         for (unsigned int i = 0; i < controlsCount; i++)
         {
-            if (controls[i]->isDirty())
+            Control* control = controls[i];
+
+            align(control, container);
+
+            if (control->isDirty() || control->isContainer())
             {
-                controls[i]->update(container->getClip());
+                control->update(container->getClip());
             }
         }
     }

+ 5 - 0
gameplay/src/Button.h

@@ -17,8 +17,13 @@ namespace gameplay
  * button <buttonID>
  * {
  *      style       = <styleID>
+ *      alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
  *      position    = <x, y>
+ *      autoWidth   = <bool>
+ *      autoHeight  = <bool>
  *      size        = <width, height>
+ *      width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
+ *      height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
  *      text        = <string>
  * }
  */

+ 5 - 0
gameplay/src/CheckBox.h

@@ -17,8 +17,13 @@ namespace gameplay
  * checkBox <checkBoxID>
  * {
  *      style       = <styleID>
+ *      alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
  *      position    = <x, y>
+ *      autoWidth   = <bool>
+ *      autoHeight  = <bool>
  *      size        = <width, height>
+ *      width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
+ *      height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
  *      text        = <string>
  *      checked     = <bool>
  *      iconSize    = <width, height>   // The size to draw the checkbox icon, if different from its size in the texture.

+ 1 - 4
gameplay/src/Container.cpp

@@ -231,10 +231,7 @@ namespace gameplay
         // Update this container's viewport.
         Control::update(clip);
 
-        if (isDirty())
-        {
-            _layout->update(this);
-        }
+        _layout->update(this);
     }
 
     void Container::drawBorder(SpriteBatch* spriteBatch, const Rectangle& clip)

+ 7 - 2
gameplay/src/Container.h

@@ -17,8 +17,13 @@ namespace gameplay
  *      // Container properties.
  *      layout   = <Layout::Type>        // A value from the Layout::Type enum.  E.g.: LAYOUT_VERTICAL
  *      style    = <styleID>           // A style from the form's theme.
- *      position = <x, y>               // Position of the container on-screen, measured in pixels.
- *      size     = <width, height>      // Size of the container, measured in pixels.
+ *      alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
+ *      position    = <x, y>    // Position of the container on-screen, measured in pixels.
+ *      autoWidth   = <bool>
+ *      autoHeight  = <bool>
+ *      size        = <width, height>   // Size of the container, measured in pixels.
+ *      width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
+ *      height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
  *   
  *      // All the nested controls within this container.
  *      container 

+ 120 - 2
gameplay/src/Control.cpp

@@ -36,10 +36,31 @@ namespace gameplay
     {
         _style = style;
 
+        _alignment = getAlignment(properties->getString("alignment"));
+        _autoWidth = properties->getBool("autoWidth");
+        _autoHeight = properties->getBool("autoHeight");
+
         Vector2 position;
         Vector2 size;
-        properties->getVector2("position", &position);
-        properties->getVector2("size", &size);
+        if (properties->exists("position"))
+        {
+            properties->getVector2("position", &position);
+        }
+        else
+        {
+            position.x = properties->getFloat("x");
+            position.y = properties->getFloat("y");
+        }
+        
+        if (properties->exists("size"))
+        {
+            properties->getVector2("size", &size);
+        }
+        else
+        {
+            size.x = properties->getFloat("width");
+            size.y = properties->getFloat("height");
+        }
         _bounds.set(position.x, position.y, size.x, size.y);
 
         _state = Control::getState(properties->getString("state"));
@@ -98,6 +119,31 @@ namespace gameplay
         return _bounds.height;
     }
 
+    void Control::setAlignment(Alignment alignment)
+    {
+        _alignment = alignment;
+    }
+
+    Control::Alignment Control::getAlignment() const
+    {
+        return _alignment;
+    }
+
+    void Control::setAutoWidth(bool autoWidth)
+    {
+        _autoWidth = autoWidth;
+    }
+
+    bool Control::getAutoWidth() const
+    {
+        return _autoWidth;
+    }
+
+    void Control::setAutoHeight(bool autoHeight)
+    {
+        _autoHeight = autoHeight;
+    }
+
     void Control::setOpacity(float opacity, unsigned char states)
     {
         overrideStyle();
@@ -925,4 +971,76 @@ namespace gameplay
         _style = new Theme::Style(*_style);
         _styleOverridden = true;
     }
+
+    Control::Alignment Control::getAlignment(const char* alignment)
+    {
+        if (!alignment)
+        {
+            return Control::ALIGN_TOP_LEFT;
+        }
+
+        if (strcmp(alignment, "ALIGN_LEFT") == 0)
+        {
+            return Control::ALIGN_LEFT;
+        }
+        else if (strcmp(alignment, "ALIGN_HCENTER") == 0)
+        {
+            return Control::ALIGN_HCENTER;
+        }
+        else if (strcmp(alignment, "ALIGN_RIGHT") == 0)
+        {
+            return Control::ALIGN_RIGHT;
+        }
+        else if (strcmp(alignment, "ALIGN_TOP") == 0)
+        {
+            return Control::ALIGN_TOP;
+        }
+        else if (strcmp(alignment, "ALIGN_VCENTER") == 0)
+        {
+            return Control::ALIGN_VCENTER;
+        }
+        else if (strcmp(alignment, "ALIGN_BOTTOM") == 0)
+        {
+            return Control::ALIGN_BOTTOM;
+        }
+        else if (strcmp(alignment, "ALIGN_TOP_LEFT") == 0)
+        {
+            return Control::ALIGN_TOP_LEFT;
+        }
+        else if (strcmp(alignment, "ALIGN_VCENTER_LEFT") == 0)
+        {
+            return Control::ALIGN_VCENTER_LEFT;
+        }
+        else if (strcmp(alignment, "ALIGN_BOTTOM_LEFT") == 0)
+        {
+            return Control::ALIGN_BOTTOM_LEFT;
+        }
+        else if (strcmp(alignment, "ALIGN_TOP_HCENTER") == 0)
+        {
+            return Control::ALIGN_TOP_HCENTER;
+        }
+        else if (strcmp(alignment, "ALIGN_VCENTER_HCENTER") == 0)
+        {
+            return Control::ALIGN_VCENTER_HCENTER;
+        }
+        else if (strcmp(alignment, "ALIGN_BOTTOM_HCENTER") == 0)
+        {
+            return Control::ALIGN_BOTTOM_HCENTER;
+        }
+        else if (strcmp(alignment, "ALIGN_TOP_RIGHT") == 0)
+        {
+            return Control::ALIGN_TOP_RIGHT;
+        }
+        else if (strcmp(alignment, "ALIGN_VCENTER_RIGHT") == 0)
+        {
+            return Control::ALIGN_VCENTER_RIGHT;
+        }
+        else if (strcmp(alignment, "ALIGN_BOTTOM_RIGHT") == 0)
+        {
+            return Control::ALIGN_BOTTOM_RIGHT;
+        }
+
+        // Default.
+        return Control::ALIGN_TOP_LEFT;
+    }
 }

+ 76 - 0
gameplay/src/Control.h

@@ -53,6 +53,33 @@ public:
         DISABLED = 0x08,
     };
 
+    /**
+     * Defines the set of alignments for positioning controls and justifying text.
+     */
+    enum Alignment
+    {
+        // Specify horizontal alignment, use default vertical alignment (ALIGN_TOP).
+        ALIGN_LEFT = 0x01,
+        ALIGN_HCENTER = 0x02,
+        ALIGN_RIGHT = 0x04,
+    
+        // Specify vertical alignment, use default horizontal alignment (ALIGN_LEFT).
+        ALIGN_TOP = 0x10,
+        ALIGN_VCENTER = 0x20,
+        ALIGN_BOTTOM = 0x40,
+
+        // Specify both vertical and horizontal alignment.
+        ALIGN_TOP_LEFT = ALIGN_TOP | ALIGN_LEFT,
+        ALIGN_VCENTER_LEFT = ALIGN_VCENTER | ALIGN_LEFT,
+        ALIGN_BOTTOM_LEFT = ALIGN_BOTTOM | ALIGN_LEFT,
+        ALIGN_TOP_HCENTER = ALIGN_TOP | ALIGN_HCENTER,
+        ALIGN_VCENTER_HCENTER = ALIGN_VCENTER | ALIGN_HCENTER,
+        ALIGN_BOTTOM_HCENTER = ALIGN_BOTTOM | ALIGN_HCENTER,
+        ALIGN_TOP_RIGHT = ALIGN_TOP | ALIGN_RIGHT,
+        ALIGN_VCENTER_RIGHT = ALIGN_VCENTER | ALIGN_RIGHT,
+        ALIGN_BOTTOM_RIGHT = ALIGN_BOTTOM | ALIGN_RIGHT
+    };
+
     /**
      * A constant used for setting themed attributes on all control states simultaneously.
      */
@@ -206,6 +233,50 @@ public:
      */
     float getHeight() const;
 
+    /**
+     * Set the alignment of this control within its parent container.
+     *
+     * @param alignment This control's alignment.
+     */
+    void setAlignment(Alignment alignment);
+
+    /**
+     * Get the alignment of this control within its parent container.
+     *
+     * @return The alignment of this control within its parent container.
+     */
+    Alignment getAlignment() const;
+
+    /**
+     * Set this control to fit horizontally within its parent container.
+     *
+     * @param autoWidth Whether to size this control to fit horizontally within its parent container.
+     */
+    void setAutoWidth(bool autoWidth);
+
+    /**
+     * Get whether this control's width is set to automatically adjust to
+     * fit horizontally within its parent container.
+     *
+     * @return Whether this control's width is set to automatically adjust.
+     */
+    bool getAutoWidth() const;
+
+    /**
+     * Set this control to fit vertically within its parent container.
+     *
+     * @param autoWidth Whether to size this control to fit vertically within its parent container.
+     */
+    void setAutoHeight(bool autoHeight);
+
+    /**
+     * Get whether this control's height is set to automatically adjust to
+     * fit vertically within its parent container.
+     *
+     * @return Whether this control's height is set to automatically adjust.
+     */
+    bool getAutoHeight() const;
+
     /**
      * Set the size of this control's border.
      *
@@ -712,6 +783,8 @@ protected:
      */
     void notifyListeners(Listener::EventType eventType);
 
+    static Alignment getAlignment(const char* alignment);
+
     std::string _id;
     State _state;           // Determines overlay used during draw().
     Rectangle _bounds;      // Position, relative to parent container's clipping window, and desired size.
@@ -720,6 +793,9 @@ protected:
     Rectangle _clip;        // Clipping window of this control's content, after clipping.
     bool _dirty;
     bool _consumeTouchEvents;
+    Alignment _alignment;
+    bool _autoWidth;
+    bool _autoHeight;
     Theme::Style* _style;
     std::map<Listener::EventType, std::list<Listener*>*>* _listeners;
 

+ 1 - 1
gameplay/src/Font.cpp

@@ -1568,7 +1568,7 @@ SpriteBatch* Font::getSpriteBatch() const
     return _batch;
 }
 
-Font::Justify Font::getJustifyFromString(const char* justify)
+Font::Justify Font::getJustify(const char* justify)
 {
     if (!justify)
     {

+ 1 - 1
gameplay/src/Font.h

@@ -205,7 +205,7 @@ public:
      * 
      * @return The Justify value.
      */
-    static Justify getJustifyFromString(const char* justify);
+    static Justify getJustify(const char* justify);
 
 
 private:

+ 14 - 1
gameplay/src/Form.cpp

@@ -84,6 +84,16 @@ namespace gameplay
         const char* styleName = formProperties->getString("style");
         form->initialize(theme->getStyle(styleName), formProperties);
 
+        if (form->_autoWidth)
+        {
+            form->_bounds.width = Game::getInstance()->getWidth();
+        }
+
+        if (form->_autoHeight)
+        {
+            form->_bounds.height = Game::getInstance()->getHeight();
+        }
+
         // Add all the controls to the form.
         form->addControls(theme, formProperties);
 
@@ -141,7 +151,10 @@ namespace gameplay
 
     void Form::update()
     {
-        Container::update(Rectangle(0, 0, _bounds.width, _bounds.height));
+        if (isDirty())
+        {
+            Container::update(Rectangle(0, 0, _bounds.width, _bounds.height));
+        }
     }
 
     void Form::draw()

+ 6 - 0
gameplay/src/Form.h

@@ -35,6 +35,12 @@ public:
      *      style    = <styleID>                // A style from the referenced theme.
      *      position = <x, y>                   // Position of the form on-screen, measured in pixels.
      *      size     = <width, height>          // Size of the form, measured in pixels.
+     *      alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
+     *      autoWidth   = <bool>                // Will result in a form the width of the display.
+     *      autoHeight  = <bool>                // Will result in a form the height of the display.
+     *      size        = <width, height>
+     *      width       = <width>               // Can be used in place of 'size', e.g. with 'autoHeight = true'
+     *      height      = <height>              // Can be used in place of 'size', e.g. with 'autoWidth = true'
      *   
      *      // All the nested controls within this form.
      *      container 

+ 5 - 0
gameplay/src/Label.h

@@ -15,8 +15,13 @@ namespace gameplay
  * label <labelID>
  * {
  *      style       = <styleID>
+ *      alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
  *      position    = <x, y>
+ *      autoWidth   = <bool>
+ *      autoHeight  = <bool>
  *      size        = <width, height>
+ *      width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
+ *      height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
  *      text        = <string>
  * }
  */

+ 51 - 0
gameplay/src/Layout.cpp

@@ -0,0 +1,51 @@
+#include "Base.h"
+#include "Layout.h"
+#include "Control.h"
+#include "Container.h"
+
+namespace gameplay
+{
+    void Layout::align(Control* control, const Container* container)
+    {
+        if (control->_alignment != Control::ALIGN_TOP_LEFT ||
+            control->_autoWidth || control->_autoHeight)
+        {
+            Rectangle controlBounds = control->getBounds();
+            const Rectangle& containerBounds = container->getClip();
+            const Theme::Border& containerBorder = container->getBorder(container->getState());
+            const Theme::Padding& containerPadding = container->getPadding();
+
+            if (control->_autoWidth)
+            {
+                controlBounds.width = containerBounds.width;
+            }
+
+            if (control->_autoHeight)
+            {
+                controlBounds.height = containerBounds.height;
+            }
+
+            // Vertical alignment
+            if ((control->_alignment & Control::ALIGN_BOTTOM) == Control::ALIGN_BOTTOM)
+            {
+                controlBounds.y = containerBounds.height - controlBounds.height;
+            }
+            else if ((control->_alignment & Control::ALIGN_VCENTER) == Control::ALIGN_VCENTER)
+            {
+                controlBounds.y = containerBounds.height * 0.5f - controlBounds.height * 0.5f;
+            }
+
+            // Horizontal alignment
+            if ((control->_alignment & Control::ALIGN_RIGHT) == Control::ALIGN_RIGHT)
+            {
+                controlBounds.x = containerBounds.width - controlBounds.width;
+            }
+            else if ((control->_alignment & Control::ALIGN_HCENTER) == Control::ALIGN_HCENTER)
+            {
+                controlBounds.x = containerBounds.width * 0.5f - controlBounds.width * 0.5f;
+            }
+
+            control->setBounds(controlBounds);
+        }
+    }
+}

+ 9 - 0
gameplay/src/Layout.h

@@ -7,6 +7,7 @@ namespace gameplay
 {
 
 class Container;
+class Control;
 
 /**
  * The layout interface for UI containers.
@@ -58,6 +59,14 @@ protected:
      * @param container The container to update.
      */
     virtual void update(const Container* container) = 0;
+
+    /**
+     * Align a control within a container.
+     *
+     * @param control The control to align.
+     * @param container The container to align the control within.
+     */
+    virtual void align(Control* control, const Container* container);
 };
 
 }

+ 6 - 1
gameplay/src/ParticleEmitter.cpp

@@ -34,6 +34,11 @@ ParticleEmitter::ParticleEmitter(SpriteBatch* batch, unsigned int particleCountM
 
     _spriteBatch->getStateBlock()->setDepthWrite(false);
     _spriteBatch->getStateBlock()->setDepthTest(true);
+    /*
+    _spriteBatch->getStateBlock()->setBlend(true);
+    _spriteBatch->getStateBlock()->setBlendSrc(RenderState::BLEND_SRC_ALPHA);
+    _spriteBatch->getStateBlock()->setBlendDst(RenderState::BLEND_ONE_MINUS_SRC_ALPHA);
+    */
 }
 
 ParticleEmitter::~ParticleEmitter()
@@ -524,7 +529,7 @@ void ParticleEmitter::setTextureBlending(TextureBlending textureBlending)
             break;
         case BLEND_ADDITIVE:
             _spriteBatch->getStateBlock()->setBlend(true);
-            _spriteBatch->getStateBlock()->setBlendSrc(RenderState::BLEND_ONE);
+            _spriteBatch->getStateBlock()->setBlendSrc(RenderState::BLEND_SRC_ALPHA);
             _spriteBatch->getStateBlock()->setBlendDst(RenderState::BLEND_ONE);
             break;
         case BLEND_MULTIPLIED:

+ 24 - 20
gameplay/src/PlatformiOS.mm

@@ -20,8 +20,9 @@ using namespace std;
 using namespace gameplay;
 
 // UIScreen bounds are provided as if device was in portrait mode Gameplay defaults to landscape
-extern const int WINDOW_WIDTH  = [[UIScreen mainScreen] bounds].size.height;
-extern const int WINDOW_HEIGHT = [[UIScreen mainScreen] bounds].size.width;
+extern const int WINDOW_WIDTH  = [[UIScreen mainScreen] bounds].size.height * [[UIScreen mainScreen] scale];
+extern const int WINDOW_HEIGHT = [[UIScreen mainScreen] bounds].size.width * [[UIScreen mainScreen] scale];
+extern const int WINDOW_SCALE = [[UIScreen mainScreen] scale];
 
 @class AppDelegate;
 @class View;
@@ -102,13 +103,16 @@ int getKey(unichar keyCode);
             return nil;
         }
         
-        
         // Configure the CAEAGLLayer and setup out the rendering context
+        CGFloat scale = [[UIScreen mainScreen] scale];
         CAEAGLLayer* layer = (CAEAGLLayer *)self.layer;
         layer.opaque = TRUE;
         layer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                    [NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking, 
                                     kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
+        self.contentScaleFactor = scale;
+        layer.contentsScale = scale;
+        
 		context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
         if (!context || ![EAGLContext setCurrentContext:context])
 		{
@@ -123,7 +127,7 @@ int getKey(unichar keyCode);
             
         glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);
         glViewport(0, 0, framebufferWidth, framebufferHeight);
-        
+
         // Initialize Internal Defaults
         displayLink = nil;
         defaultFramebuffer = 0;
@@ -324,27 +328,27 @@ int getKey(unichar keyCode);
 
 - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event 
 {
-    unsigned int uniqueTouch = 0;
-    for(UITouch *t in touches) 
+    unsigned int touchID = 0;
+    for(UITouch* touch in touches) 
     {
-        CGPoint touchLoc = [t locationInView:self];
+        CGPoint touchPoint = [touch locationInView:self];
         if(self.multipleTouchEnabled == YES)
         {
-            uniqueTouch = [t hash];
+            touchID = [touch hash];
         }
-        Platform::touchEventInternal(Touch::TOUCH_PRESS, touchLoc.x, touchLoc.y, uniqueTouch);
+        Platform::touchEventInternal(Touch::TOUCH_PRESS, touchPoint.x * WINDOW_SCALE, touchPoint.y * WINDOW_SCALE, touchID);
     }
 }
 
-- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent *)event 
+- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event 
 {
-    unsigned int uniqueTouch = 0;
-    for(UITouch* t in touches) 
+    unsigned int touchID = 0;
+    for(UITouch* touch in touches) 
     {
-        CGPoint touchLoc = [t locationInView:self];
+        CGPoint touchPoint = [touch locationInView:self];
         if(self.multipleTouchEnabled == YES) 
-            uniqueTouch = [t hash];
-        Platform::touchEventInternal(Touch::TOUCH_RELEASE, touchLoc.x, touchLoc.y, uniqueTouch);
+            touchID = [touch hash];
+        Platform::touchEventInternal(Touch::TOUCH_RELEASE, touchPoint.x * WINDOW_SCALE, touchPoint.y * WINDOW_SCALE, touchID);
     }
 }
 
@@ -356,13 +360,13 @@ int getKey(unichar keyCode);
 
 - (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event 
 {
-    unsigned int uniqueTouch = 0;
-    for(UITouch* t in touches) 
+    unsigned int touchID = 0;
+    for(UITouch* touch in touches) 
     {
-        CGPoint touchLoc = [t locationInView:self];
+        CGPoint touchPoint = [touch locationInView:self];
         if(self.multipleTouchEnabled == YES) 
-            uniqueTouch = [t hash];
-        Platform::touchEventInternal(Touch::TOUCH_MOVE, touchLoc.x, touchLoc.y, uniqueTouch);
+            touchID = [touch hash];
+        Platform::touchEventInternal(Touch::TOUCH_MOVE, touchPoint.x * WINDOW_SCALE, touchPoint.y * WINDOW_SCALE, touchID);
     }
 }
 

+ 5 - 0
gameplay/src/RadioButton.h

@@ -19,8 +19,13 @@ namespace gameplay
  * radioButton <RadioButton ID>
  * {
  *      style       = <Style ID>
+ *      alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
  *      position    = <x, y>
+ *      autoWidth   = <bool>
+ *      autoHeight  = <bool>
  *      size        = <width, height>
+ *      width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
+ *      height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
  *      text        = <string>
  *      group       = <string>
  *      iconSize    = <width, height>   // The size to draw the radio button icon, if different from its size in the texture.

+ 5 - 0
gameplay/src/TextBox.h

@@ -21,8 +21,13 @@ namespace gameplay
  * label <labelID>
  * {
  *      style       = <styleID>
+ *      alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
  *      position    = <x, y>
+ *      autoWidth   = <bool>
+ *      autoHeight  = <bool>
  *      size        = <width, height>
+ *      width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
+ *      height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
  *      text        = <string>
  * }
  */

+ 13 - 13
gameplay/src/Theme.cpp

@@ -181,11 +181,11 @@ namespace gameplay
                             font = Font::create(fontPath);
                         }
                         unsigned int fontSize = innerSpace->getInt("fontSize");
-                        const char* alignmentString = innerSpace->getString("alignment");
-                        Font::Justify alignment = Font::ALIGN_TOP_LEFT;
-                        if (alignmentString)
+                        const char* textAlignmentString = innerSpace->getString("textAlignment");
+                        Font::Justify textAlignment = Font::ALIGN_TOP_LEFT;
+                        if (textAlignmentString)
                         {
-                            alignment = Font::getJustifyFromString(alignmentString);
+                            textAlignment = Font::getJustify(textAlignmentString);
                         }
                         bool rightToLeft = innerSpace->getBool("rightToLeft");
 
@@ -207,7 +207,7 @@ namespace gameplay
                         normal->setTextColor(textColor);
                         normal->setFont(font);
                         normal->setFontSize(fontSize);
-                        normal->setTextAlignment(alignment);
+                        normal->setTextAlignment(textAlignment);
                         normal->setTextRightToLeft(rightToLeft);
                         normal->setOpacity(opacity);
 
@@ -275,15 +275,15 @@ namespace gameplay
                             fontSize = normal->getFontSize();
                         }
 
-                        const char* alignmentString = innerSpace->getString("alignment");
-                        Font::Justify alignment;
-                        if (alignmentString)
+                        const char* textAlignmentString = innerSpace->getString("textAlignment");
+                        Font::Justify textAlignment;
+                        if (textAlignmentString)
                         {
-                            alignment = Font::getJustifyFromString(alignmentString);
+                            textAlignment = Font::getJustify(textAlignmentString);
                         }
                         else
                         {
-                            alignment = normal->getTextAlignment();
+                            textAlignment = normal->getTextAlignment();
                         }
 
                         bool rightToLeft;
@@ -335,7 +335,7 @@ namespace gameplay
                             focus->setTextColor(textColor);
                             focus->setFont(font);
                             focus->setFontSize(fontSize);
-                            focus->setTextAlignment(alignment);
+                            focus->setTextAlignment(textAlignment);
                             focus->setTextRightToLeft(rightToLeft);
                             focus->setOpacity(opacity);
 
@@ -350,7 +350,7 @@ namespace gameplay
                             active->setTextColor(textColor);
                             active->setFont(font);
                             active->setFontSize(fontSize);
-                            active->setTextAlignment(alignment);
+                            active->setTextAlignment(textAlignment);
                             active->setTextRightToLeft(rightToLeft);
                             active->setOpacity(opacity);
 
@@ -365,7 +365,7 @@ namespace gameplay
                             disabled->setTextColor(textColor);
                             disabled->setFont(font);
                             disabled->setFontSize(fontSize);
-                            disabled->setTextAlignment(alignment);
+                            disabled->setTextAlignment(textAlignment);
                             disabled->setTextRightToLeft(rightToLeft);
                             disabled->setOpacity(opacity);
 

+ 3 - 1
gameplay/src/VerticalLayout.cpp

@@ -69,13 +69,15 @@ namespace gameplay
         {
             Control* control = controls.at(i);
 
+            align(control, container);
+
             const Rectangle& bounds = control->getClipBounds();
             const Theme::Margin& margin = control->getMargin();
 
             yPosition += margin.top;
 
             control->setPosition(0, yPosition);
-            if (control->isDirty())
+            if (control->isDirty() || control->isContainer())
             {
                 control->update(container->getClip());
             }