Browse Source

Merge remote-tracking branch 'upstream/next' into next

John Brandle 13 years ago
parent
commit
58e8882811

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

@@ -419,6 +419,7 @@
 				ONLY_ACTIVE_ARCH = YES;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SDKROOT = macosx;
+				VALID_ARCHS = "armv7 armv7s i386 x86_64";
 			};
 			name = Debug;
 		};
@@ -441,6 +442,7 @@
 				MACOSX_DEPLOYMENT_TARGET = 10.7;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SDKROOT = macosx;
+				VALID_ARCHS = "armv7 armv7s i386 x86_64";
 			};
 			name = Release;
 		};
@@ -470,6 +472,7 @@
 				);
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				USER_HEADER_SEARCH_PATHS = "";
+				VALID_ARCHS = "i386 x86_64";
 				WRAPPER_EXTENSION = app;
 			};
 			name = Debug;
@@ -500,6 +503,7 @@
 				);
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				USER_HEADER_SEARCH_PATHS = "";
+				VALID_ARCHS = "i386 x86_64";
 				WRAPPER_EXTENSION = app;
 			};
 			name = Release;
@@ -532,6 +536,7 @@
 				SDKROOT = iphoneos;
 				TARGETED_DEVICE_FAMILY = "1,2";
 				USER_HEADER_SEARCH_PATHS = "";
+				VALID_ARCHS = "armv7 armv7s";
 				WRAPPER_EXTENSION = app;
 			};
 			name = Debug;
@@ -564,6 +569,7 @@
 				SDKROOT = iphoneos;
 				TARGETED_DEVICE_FAMILY = "1,2";
 				USER_HEADER_SEARCH_PATHS = "";
+				VALID_ARCHS = "armv7 armv7s";
 				WRAPPER_EXTENSION = app;
 			};
 			name = Release;

+ 17 - 36
gameplay.doxyfile

@@ -1,4 +1,4 @@
-# Doxyfile 1.8.0
+# Doxyfile 1.7.6.1
 
 # This file describes the settings to be used by the documentation system
 # doxygen (www.doxygen.org) for a project
@@ -250,15 +250,6 @@ OPTIMIZE_OUTPUT_VHDL   = NO
 
 EXTENSION_MAPPING      = 
 
-# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all 
-# comments according to the Markdown format, which allows for more readable 
-# documentation. See http://daringfireball.net/projects/markdown/ for details. 
-# The output of markdown processing is further processed by doxygen, so you 
-# can mix doxygen, HTML, and XML commands with Markdown formatting. 
-# Disable only in case of backward compatibilities issues.
-
-MARKDOWN_SUPPORT       = YES
-
 # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want 
 # to include (a tag file for) the STL sources as input, then you should 
 # set this tag to YES in order to let doxygen match functions declarations and 
@@ -372,11 +363,6 @@ EXTRACT_ALL            = NO
 
 EXTRACT_PRIVATE        = NO
 
-# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
-# scope will be included in the documentation.
-
-EXTRACT_PACKAGE        = NO
-
 # If the EXTRACT_STATIC tag is set to YES all static members of a file 
 # will be included in the documentation.
 
@@ -1182,7 +1168,7 @@ FORMULA_TRANSPARENT    = YES
 # (see http://www.mathjax.org) which uses client side Javascript for the 
 # rendering instead of using prerendered bitmaps. Use this if you do not 
 # have LaTeX installed or if you want to formulas look prettier in the HTML 
-# output. When enabled you may also need to install MathJax separately and 
+# output. When enabled you also need to install MathJax separately and 
 # configure the path to it using the MATHJAX_RELPATH option.
 
 USE_MATHJAX            = NO
@@ -1191,10 +1177,10 @@ USE_MATHJAX            = NO
 # HTML output directory using the MATHJAX_RELPATH option. The destination 
 # directory should contain the MathJax.js script. For instance, if the mathjax 
 # directory is located at the same level as the HTML output directory, then 
-# MATHJAX_RELPATH should be ../mathjax. The default value points to 
-# the MathJax Content Delivery Network so you can quickly see the result without 
-# installing MathJax.  However, it is strongly recommended to install a local 
-# copy of MathJax from http://www.mathjax.org before deployment.
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the 
+# mathjax.org site, so you can quickly see the result without installing 
+# MathJax, but it is strongly recommended to install a local copy of MathJax 
+# before deployment.
 
 MATHJAX_RELPATH        = http://www.mathjax.org/mathjax
 
@@ -1542,16 +1528,20 @@ SKIP_FUNCTION_MACROS   = YES
 # Configuration::additions related to external references
 #---------------------------------------------------------------------------
 
-# The TAGFILES option can be used to specify one or more tagfiles. For each 
-# tag file the location of the external documentation should be added. The 
-# format of a tag file without this location is as follows: 
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. The format of a tag file without 
+# this location is as follows: 
 #   TAGFILES = file1 file2 ... 
 # Adding location for the tag files is done as follows: 
 #   TAGFILES = file1=loc1 "file2 = loc2" ... 
-# where "loc1" and "loc2" can be relative or absolute paths 
-# or URLs. Note that each tag file must have a unique name (where the name does 
-# NOT include the path). If a tag file is not located in the directory in which 
-# doxygen is run, you must also specify the path to the tagfile here.
+# where "loc1" and "loc2" can be relative or absolute paths or 
+# URLs. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links. 
+# Note that each tag file must have a unique name 
+# (where the name does NOT include the path) 
+# If a tag file is not located in the directory in which doxygen 
+# is run, you must also specify the path to the tagfile here.
 
 TAGFILES               = 
 
@@ -1664,15 +1654,6 @@ GROUP_GRAPHS           = YES
 
 UML_LOOK               = NO
 
-# If the UML_LOOK tag is enabled, the fields and methods are shown inside 
-# the class node. If there are many fields or methods and many nodes the 
-# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS 
-# threshold limits the number of items for each type to make the size more 
-# managable. Set this to 0 for no limit. Note that the threshold may be 
-# exceeded by 50% before the limit is enforced.
-
-UML_LIMIT_NUM_FIELDS   = 10
-
 # If set to YES, the inheritance and collaboration graphs will show the 
 # relations between templates and their instances.
 

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

@@ -3608,7 +3608,7 @@
 				ONLY_ACTIVE_ARCH = YES;
 				SDKROOT = macosx;
 				SUPPORTED_PLATFORMS = "iphonesimulator macosx iphoneos";
-				VALID_ARCHS = "armv7 armv6 i386 x86_64";
+				VALID_ARCHS = "armv7 armv7s i386 x86_64";
 			};
 			name = Debug;
 		};
@@ -3617,7 +3617,7 @@
 			buildSettings = {
 				SDKROOT = macosx;
 				SUPPORTED_PLATFORMS = "iphonesimulator macosx iphoneos";
-				VALID_ARCHS = "armv7 armv6 i386 x86_64";
+				VALID_ARCHS = "armv7 armv7s i386 x86_64";
 			};
 			name = Release;
 		};
@@ -3744,7 +3744,7 @@
 				SHARED_PRECOMPS_DIR = "";
 				SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
 				USER_HEADER_SEARCH_PATHS = "";
-				VALID_ARCHS = "armv7 armv6";
+				VALID_ARCHS = "armv7 armv7s ";
 			};
 			name = Debug;
 		};
@@ -3785,7 +3785,7 @@
 				SHARED_PRECOMPS_DIR = "";
 				SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
 				USER_HEADER_SEARCH_PATHS = "";
-				VALID_ARCHS = "armv7 armv6";
+				VALID_ARCHS = "armv7 armv7s ";
 			};
 			name = Release;
 		};

+ 1 - 0
gameplay/src/Base.h

@@ -27,6 +27,7 @@
 #include <limits>
 #include <functional>
 #include <bitset>
+#include <typeinfo>
 #include "Logger.h"
 
 // Bring common functions from C into global namespace

+ 1 - 1
gameplay/src/Button.h

@@ -77,7 +77,7 @@ protected:
      * @param evt The touch event that occurred.
      * @param x The x position of the touch in pixels. Left edge is zero.
      * @param y The y position of the touch in pixels. Top edge is zero.
-     * @param contactIndex An integer to identify this contact point within the currently active touch set.
+     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
      *
      * @return Whether the touch event was consumed by the control.
      *

+ 1 - 1
gameplay/src/CheckBox.h

@@ -123,7 +123,7 @@ protected:
      * @param evt The touch event that occurred.
      * @param x The x position of the touch in pixels. Left edge is zero.
      * @param y The y position of the touch in pixels. Top edge is zero.
-     * @param contactIndex An integer to identify this contact point within the currently active touch set.
+     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
      *
      * @return Whether the touch event was consumed by the control.
      *

+ 2 - 2
gameplay/src/Container.h

@@ -259,7 +259,7 @@ protected:
      * @param evt The touch event that occurred.
      * @param x The x position of the touch in pixels. Left edge is zero.
      * @param y The y position of the touch in pixels. Top edge is zero.
-     * @param contactIndex An integer to identify this contact point within the currently active touch set.
+     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
      *
      * @return Whether the touch event was consumed by a control within this container.
      *
@@ -340,7 +340,7 @@ protected:
      * @param evt The touch event that occurred.
      * @param x The x position of the touch in pixels. Left edge is zero.
      * @param y The y position of the touch in pixels. Top edge is zero.
-     * @param contactIndex An integer to identify this contact point within the currently active touch set.
+     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
      *
      * @return Whether the touch event was consumed by scrolling within this container.
      *

+ 1 - 1
gameplay/src/Control.h

@@ -805,7 +805,7 @@ protected:
      * @param evt The touch event that occurred.
      * @param x The x position of the touch in pixels. Left edge is zero.
      * @param y The y position of the touch in pixels. Top edge is zero.
-     * @param contactIndex An integer to identify this contact point within the currently active touch set.
+     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
      *
      * @return Whether the touch event was consumed by this control.
      *

+ 46 - 7
gameplay/src/DepthStencilTarget.cpp

@@ -1,21 +1,30 @@
 #include "Base.h"
 #include "DepthStencilTarget.h"
 
+#ifndef GL_DEPTH24_STENCIL8_OES
+#define GL_DEPTH24_STENCIL8_OES 0x88F0
+#endif
+#ifndef GL_DEPTH_COMPONENT24
+#define GL_DEPTH_COMPONENT24 GL_DEPTH_COMPONENT24_OES
+#endif
+
 namespace gameplay
 {
 
 static std::vector<DepthStencilTarget*> __depthStencilTargets;
 
 DepthStencilTarget::DepthStencilTarget(const char* id, Format format, unsigned int width, unsigned int height)
-    : _id(id ? id : ""), _format(format), _renderBuffer(0), _width(width), _height(height)
+    : _id(id ? id : ""), _format(format), _depthBuffer(0), _stencilBuffer(0), _width(width), _height(height)
 {
 }
 
 DepthStencilTarget::~DepthStencilTarget()
 {
     // Destroy GL resources.
-    if (_renderBuffer)
-        GL_ASSERT( glDeleteRenderbuffers(1, &_renderBuffer) );
+    if (_depthBuffer)
+        GL_ASSERT( glDeleteRenderbuffers(1, &_depthBuffer) );
+    if (_stencilBuffer)
+        GL_ASSERT( glDeleteRenderbuffers(1, &_stencilBuffer) );
 
     // Remove from vector.
     std::vector<DepthStencilTarget*>::iterator it = std::find(__depthStencilTargets.begin(), __depthStencilTargets.end(), this);
@@ -30,11 +39,41 @@ DepthStencilTarget* DepthStencilTarget::create(const char* id, Format format, un
     // Create the depth stencil target.
     DepthStencilTarget* depthStencilTarget = new DepthStencilTarget(id, format, width, height);
 
-    // Create a render buffer for this new depth stencil target
-    GL_ASSERT( glGenRenderbuffers(1, &depthStencilTarget->_renderBuffer) );
-    GL_ASSERT( glBindRenderbuffer(GL_RENDERBUFFER, depthStencilTarget->_renderBuffer) );
-    GL_ASSERT( glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height) );
+    // Create a render buffer for this new depth+stencil target
+    GL_ASSERT( glGenRenderbuffers(1, &depthStencilTarget->_depthBuffer) );
+    GL_ASSERT( glBindRenderbuffer(GL_RENDERBUFFER, depthStencilTarget->_depthBuffer) );
+
+    // First try to add storage for the most common standard GL_DEPTH24_STENCIL8 
+    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
 
+    // Fall back to less common GLES2 extension combination for seperate depth24 + stencil8 or depth16 + stencil8
+    __gl_error_code = glGetError();
+    if ( __gl_error_code != GL_NO_ERROR)
+    {
+        const char* extString = (const char*)glGetString(GL_EXTENSIONS);
+
+        if (strstr(extString, "GL_OES_packed_depth_stencil") != 0)
+        {
+            GL_ASSERT( glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, width, height) );
+        }
+        else
+        {
+            if (strstr(extString, "GL_OES_depth24") != 0)
+            {
+                GL_ASSERT( glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height) );
+            }
+            else
+            {
+                GL_ASSERT( glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height) );
+            }
+            if (format == DepthStencilTarget::DEPTH_STENCIL)
+            {
+                GL_ASSERT( glGenRenderbuffers(1, &depthStencilTarget->_stencilBuffer) );
+                GL_ASSERT( glBindRenderbuffer(GL_RENDERBUFFER, depthStencilTarget->_stencilBuffer) );
+                GL_ASSERT( glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height) );
+            }
+        }
+    }
     // Add it to the cache.
     __depthStencilTargets.push_back(depthStencilTarget);
 

+ 2 - 1
gameplay/src/DepthStencilTarget.h

@@ -101,7 +101,8 @@ private:
 
     std::string _id;
     Format _format;
-    RenderBufferHandle _renderBuffer;
+    RenderBufferHandle _depthBuffer;
+    RenderBufferHandle _stencilBuffer;
     unsigned int _width;
     unsigned int _height;
 };

+ 2 - 2
gameplay/src/FrameBuffer.cpp

@@ -218,10 +218,10 @@ void FrameBuffer::setDepthStencilTarget(DepthStencilTarget* target)
         GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, _handle) );
 
         // Attach the render buffer to the framebuffer
-        GL_ASSERT( glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthStencilTarget->_renderBuffer) );
+        GL_ASSERT( glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthStencilTarget->_depthBuffer) );
         if (target->getFormat() == DepthStencilTarget::DEPTH_STENCIL)
         {
-            GL_ASSERT( glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _depthStencilTarget->_renderBuffer) );
+            GL_ASSERT( glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _depthStencilTarget->_stencilBuffer) );
         }
 
         // Check the framebuffer is good to go.

+ 1 - 1
gameplay/src/Game.h

@@ -295,7 +295,7 @@ public:
      * @param evt The touch event that occurred.
      * @param x The x position of the touch in pixels. Left edge is zero.
      * @param y The y position of the touch in pixels. Top edge is zero.
-     * @param contactIndex An integer to identify this contact point within the currently active touch set.
+     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
      *
      * @see Touch::TouchEvent
      */

+ 1 - 1
gameplay/src/Joystick.h

@@ -153,7 +153,7 @@ protected:
      * @param evt The touch event that occurred.
      * @param x The x position of the touch in pixels. Left edge is zero.
      * @param y The y position of the touch in pixels. Top edge is zero.
-     * @param contactIndex An integer to identify this contact point within the currently active touch set.
+     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
      *
      * @return Whether the touch event was consumed by the control.
      *

+ 1 - 1
gameplay/src/Layout.h

@@ -80,7 +80,7 @@ protected:
      * @param evt The touch event that occurred.
      * @param x The x position of the touch in pixels. Left edge is zero.
      * @param y The y position of the touch in pixels. Top edge is zero.
-     * @param contactIndex An integer to identify this contact point within the currently active touch set.
+     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
      *
      * @see Touch::TouchEvent
      */

+ 25 - 12
gameplay/src/PlatformAndroid.cpp

@@ -975,22 +975,35 @@ int Platform::enterMessagePump()
     }
     GP_ASSERT(env);
 
-    // Get the package name for this app from Java.
-    jclass clazz = env->GetObjectClass(activity->clazz);
-    jmethodID methodID = env->GetMethodID(clazz, "getPackageName", "()Ljava/lang/String;");
-    jobject result = env->CallObjectMethod(activity->clazz, methodID);
-    
-    const char* packageName;
+    /* Get external files directory on Android; this will result in a directory where all app files
+     * should be stored, like /mnt/sdcard/android/<package-name>/files/
+     */
     jboolean isCopy;
-    packageName = env->GetStringUTFChars((jstring)result, &isCopy);
-    jvm->DetachCurrentThread();
+
+    jclass clazz = env->GetObjectClass(activity->clazz);
+    jmethodID methodGetExternalStorage = env->GetMethodID(clazz, "getExternalFilesDir", "(Ljava/lang/String;)Ljava/io/File;");
+
+    jclass clazzFile = env->FindClass("java/io/File");
+    jmethodID methodGetPath = env->GetMethodID(clazzFile, "getPath", "()Ljava/lang/String;");
+
+    // Now has java.io.File object pointing to directory
+    jobject objectFile  = env->CallObjectMethod(activity->clazz, methodGetExternalStorage, NULL);
     
+    // Now has String object containing path to directory
+    jstring stringExternalPath = static_cast<jstring>(env->CallObjectMethod(objectFile, methodGetPath));
+    const char* externalPath = env->GetStringUTFChars(stringExternalPath, &isCopy);
+
     // Set the default path to store the resources.
-    std::string assetsPath = "/mnt/sdcard/android/data/";
-    assetsPath += packageName;
-    assetsPath += "/";
+    std::string assetsPath(externalPath);
+    if (externalPath[strlen(externalPath)-1] != '/')
+        assetsPath += "/";
+
     FileSystem::setResourcePath(assetsPath.c_str());    
-        
+
+    // Release string data
+    env->ReleaseStringUTFChars(stringExternalPath, externalPath);
+    jvm->DetachCurrentThread();
+    
     // Get the asset manager to get the resources from the .apk file.
     __assetManager = activity->assetManager; 
     

+ 5 - 1
gameplay/src/PlatformLinux.cpp

@@ -514,7 +514,7 @@ Platform* Platform::create(Game* game, void* attachToWindow)
      
     // Get the window configuration values
     const char *title = NULL;
-    int __x = 0, __y = 0, __width = 1280, __height = 800;
+    int __x = 0, __y = 0, __width = 1280, __height = 800, __samples = 0;
     bool fullscreen = false;
     if (game->getConfig())
     {
@@ -529,6 +529,7 @@ Platform* Platform::create(Game* game, void* attachToWindow)
             int y = config->getInt("y");
             int width = config->getInt("width");
             int height = config->getInt("height");
+            int samples = config->getInt("samples");
             fullscreen = config->getBool("fullscreen");
 
             if (fullscreen && width == 0 && height == 0)
@@ -542,6 +543,7 @@ Platform* Platform::create(Game* game, void* attachToWindow)
             if (y != 0) __y = y;
             if (width != 0) __width = width;
             if (height != 0) __height = height;
+            if (samples != 0) __samples = samples;
         }
     }
 
@@ -579,6 +581,8 @@ Platform* Platform::create(Game* game, void* attachToWindow)
         GLX_GREEN_SIZE,     8,
         GLX_BLUE_SIZE,      8,
         GLX_DOUBLEBUFFER,   True,
+        GLX_SAMPLE_BUFFERS, __samples > 0 ? 1 : 0,
+        GLX_SAMPLES,        __samples,
         0
     };
     GLXFBConfig* configs;

+ 119 - 3
gameplay/src/PlatformiOS.mm

@@ -38,6 +38,29 @@ extern const int WINDOW_SCALE = [[UIScreen mainScreen] scale];
 static AppDelegate *__appDelegate = NULL;
 static View* __view = NULL;
 
+class TouchPointListElement
+{
+public:
+    TouchPointListElement* _next;
+    TouchPointListElement* _prev;
+    unsigned int _id; // as assigned from hash
+    unsigned int _index; // to save time during touchesBegan
+    int _x;
+    int _y;
+    
+    TouchPointListElement()
+    {
+        _next = NULL;
+        _prev = NULL;
+        _id = 0;
+        _index = 0;
+        _x = 0;
+        _y = 0;
+    }
+};
+static TouchPointListElement* __touchPointListHead = NULL;
+static TouchPointListElement* __touchPointListTail = NULL;
+
 static double __timeStart;
 static double __timeAbsolute;
 static bool __vsync = WINDOW_VSYNC;
@@ -516,7 +539,29 @@ int getUnicode(int key);
         {
             touchID = [touch hash];
         }
-        Platform::touchEventInternal(Touch::TOUCH_PRESS, touchPoint.x * WINDOW_SCALE, touchPoint.y * WINDOW_SCALE, touchID);
+
+        // Map hash to index
+        TouchPointListElement* elem = new TouchPointListElement();
+        if (__touchPointListTail)
+        {
+            // Insert at end of list
+            __touchPointListTail->_next = elem;
+            elem->_index = __touchPointListTail->_index + 1;
+        }
+        else
+        {
+            // Insert into empty list
+            __touchPointListHead = elem;
+            elem->_index = 0;
+        }
+
+        elem->_prev = __touchPointListTail;
+        __touchPointListTail = elem;
+        elem->_id = touchID;
+        elem->_x = touchPoint.x * WINDOW_SCALE;
+        elem->_y = touchPoint.y * WINDOW_SCALE;
+
+        Platform::touchEventInternal(Touch::TOUCH_PRESS, elem->_x, elem->_y, elem->_index);
     }
 }
 
@@ -528,7 +573,67 @@ int getUnicode(int key);
         CGPoint touchPoint = [touch locationInView:self];
         if(self.multipleTouchEnabled == YES) 
             touchID = [touch hash];
-        Platform::touchEventInternal(Touch::TOUCH_RELEASE, touchPoint.x * WINDOW_SCALE, touchPoint.y * WINDOW_SCALE, touchID);
+
+        // Map hash to index
+        TouchPointListElement* elem = NULL;
+        for (TouchPointListElement* p = __touchPointListHead; p; p = p->_next)
+        {
+            if (p->_id == touchID)
+            {
+                // Remove from list
+                elem = p;
+                p = elem->_next;
+
+                if (elem->_prev)
+                {
+                    elem->_prev->_next = p;
+                }
+                else
+                {
+                    __touchPointListHead = p;
+                }
+                
+                if (p)
+                {
+                    p->_prev = elem->_prev;
+                }
+                else
+                {
+                    __touchPointListTail = elem->_prev;
+                    break;
+                }
+            }
+
+            if (elem)
+            {
+                // Release at the old index and press at the new index
+                Platform::touchEventInternal(Touch::TOUCH_RELEASE, p->_x, p->_y, p->_index);
+                p->_index--;
+                Platform::touchEventInternal(Touch::TOUCH_PRESS, p->_x, p->_y, p->_index);
+            }
+        }
+        
+        if (elem)
+        {
+            Platform::touchEventInternal(Touch::TOUCH_RELEASE, touchPoint.x * WINDOW_SCALE, touchPoint.y * WINDOW_SCALE, elem->_index);
+            delete elem;
+        }
+        else
+        {
+            // It seems possible to receive an ID not in the list.
+            // The best we can do is clear the whole list.
+            TouchPointListElement* p = __touchPointListTail;
+            while (p)
+            {
+                TouchPointListElement* e = p;
+                p = e->_prev;
+                // Neglect p->_next since the whole list is being deleted.
+                Platform::touchEventInternal(Touch::TOUCH_RELEASE, e->_x, e->_y, e->_index);
+                delete e;
+            }
+            __touchPointListTail = NULL;
+            __touchPointListHead = NULL;
+        }
     }
 }
 
@@ -546,7 +651,18 @@ int getUnicode(int key);
         CGPoint touchPoint = [touch locationInView:self];
         if(self.multipleTouchEnabled == YES) 
             touchID = [touch hash];
-        Platform::touchEventInternal(Touch::TOUCH_MOVE, touchPoint.x * WINDOW_SCALE, touchPoint.y * WINDOW_SCALE, touchID);
+
+        // Map hash to index
+        for (TouchPointListElement* p = __touchPointListHead; p; p = p->_next)
+        {
+            if (p->_id == touchID)
+            {
+                p->_x = touchPoint.x * WINDOW_SCALE;
+                p->_y = touchPoint.y * WINDOW_SCALE;
+                Platform::touchEventInternal(Touch::TOUCH_MOVE, p->_x, p->_y, p->_index);
+                break;
+            }
+        }
     }
 }
 

+ 1 - 1
gameplay/src/RadioButton.h

@@ -136,7 +136,7 @@ protected:
      * @param evt The touch event that occurred.
      * @param x The x position of the touch in pixels. Left edge is zero.
      * @param y The y position of the touch in pixels. Top edge is zero.
-     * @param contactIndex An integer to identify this contact point within the currently active touch set.
+     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
      *
      * @return Whether the touch event was consumed by the control.
      *

+ 8 - 0
gameplay/src/RenderState.cpp

@@ -556,6 +556,14 @@ static RenderState::Blend parseBlend(const char* value)
         return RenderState::BLEND_ZERO;
     else if (upper == "ONE")
         return RenderState::BLEND_ONE;
+    else if (upper == "SRC_COLOR")
+        return RenderState::BLEND_SRC_COLOR;
+    else if (upper == "ONE_MINUS_SRC_COLOR")
+        return RenderState::BLEND_ONE_MINUS_SRC_COLOR;
+    else if (upper == "DST_COLOR")
+        return RenderState::BLEND_DST_COLOR;
+    else if (upper == "ONE_MINUS_DST_COLOR")
+        return RenderState::BLEND_ONE_MINUS_DST_COLOR;
     else if (upper == "SRC_ALPHA")
         return RenderState::BLEND_SRC_ALPHA;
     else if (upper == "ONE_MINUS_SRC_ALPHA")

+ 1 - 1
gameplay/src/RenderState.h

@@ -134,7 +134,7 @@ public:
         BLEND_ZERO = GL_ZERO,
         BLEND_ONE = GL_ONE,
         BLEND_SRC_COLOR = GL_SRC_COLOR,
-        BLEN_ONE_MINUS_SRC_COLOR = GL_ONE_MINUS_SRC_COLOR,
+        BLEND_ONE_MINUS_SRC_COLOR = GL_ONE_MINUS_SRC_COLOR,
         BLEND_DST_COLOR = GL_DST_COLOR,
         BLEND_ONE_MINUS_DST_COLOR = GL_ONE_MINUS_DST_COLOR,
         BLEND_SRC_ALPHA = GL_SRC_ALPHA,

+ 1 - 1
gameplay/src/ScriptController.h

@@ -811,7 +811,7 @@ private:
      * @param evt The touch event that occurred.
      * @param x The x position of the touch in pixels. Left edge is zero.
      * @param y The y position of the touch in pixels. Top edge is zero.
-     * @param contactIndex An integer to identify this contact point within the currently active touch set.
+     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
      *
      * @see Touch::TouchEvent
      */

+ 1 - 1
gameplay/src/Slider.h

@@ -192,7 +192,7 @@ protected:
      * @param evt The touch event that occurred.
      * @param x The x position of the touch in pixels. Left edge is zero.
      * @param y The y position of the touch in pixels. Top edge is zero.
-     * @param contactIndex An integer to identify this contact point within the currently active touch set.
+     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
      *
      * @return Whether the touch event was consumed by the control.
      *

+ 1 - 1
gameplay/src/TextBox.h

@@ -102,7 +102,7 @@ protected:
      * @param evt The touch event that occurred.
      * @param x The x position of the touch in pixels. Left edge is zero.
      * @param y The y position of the touch in pixels. Top edge is zero.
-     * @param contactIndex An integer to identify this contact point within the currently active touch set.
+     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
      *
      * @return Whether the touch event was consumed by the control.
      *

+ 1 - 1
gameplay/src/lua/lua_Global.cpp

@@ -730,7 +730,7 @@ void luaRegister_lua_Global()
         ScriptUtil::registerConstantString("BLEND_ZERO", "BLEND_ZERO", scopePath);
         ScriptUtil::registerConstantString("BLEND_ONE", "BLEND_ONE", scopePath);
         ScriptUtil::registerConstantString("BLEND_SRC_COLOR", "BLEND_SRC_COLOR", scopePath);
-        ScriptUtil::registerConstantString("BLEN_ONE_MINUS_SRC_COLOR", "BLEN_ONE_MINUS_SRC_COLOR", scopePath);
+        ScriptUtil::registerConstantString("BLEND_ONE_MINUS_SRC_COLOR", "BLEND_ONE_MINUS_SRC_COLOR", scopePath);
         ScriptUtil::registerConstantString("BLEND_DST_COLOR", "BLEND_DST_COLOR", scopePath);
         ScriptUtil::registerConstantString("BLEND_ONE_MINUS_DST_COLOR", "BLEND_ONE_MINUS_DST_COLOR", scopePath);
         ScriptUtil::registerConstantString("BLEND_SRC_ALPHA", "BLEND_SRC_ALPHA", scopePath);

+ 5 - 5
gameplay/src/lua/lua_RenderStateBlend.cpp

@@ -9,7 +9,7 @@ static const char* enumStringEmpty = "";
 static const char* luaEnumString_RenderStateBlend_BLEND_ZERO = "BLEND_ZERO";
 static const char* luaEnumString_RenderStateBlend_BLEND_ONE = "BLEND_ONE";
 static const char* luaEnumString_RenderStateBlend_BLEND_SRC_COLOR = "BLEND_SRC_COLOR";
-static const char* luaEnumString_RenderStateBlend_BLEN_ONE_MINUS_SRC_COLOR = "BLEN_ONE_MINUS_SRC_COLOR";
+static const char* luaEnumString_RenderStateBlend_BLEND_ONE_MINUS_SRC_COLOR = "BLEND_ONE_MINUS_SRC_COLOR";
 static const char* luaEnumString_RenderStateBlend_BLEND_DST_COLOR = "BLEND_DST_COLOR";
 static const char* luaEnumString_RenderStateBlend_BLEND_ONE_MINUS_DST_COLOR = "BLEND_ONE_MINUS_DST_COLOR";
 static const char* luaEnumString_RenderStateBlend_BLEND_SRC_ALPHA = "BLEND_SRC_ALPHA";
@@ -28,8 +28,8 @@ RenderState::Blend lua_enumFromString_RenderStateBlend(const char* s)
         return RenderState::BLEND_ONE;
     if (strcmp(s, luaEnumString_RenderStateBlend_BLEND_SRC_COLOR) == 0)
         return RenderState::BLEND_SRC_COLOR;
-    if (strcmp(s, luaEnumString_RenderStateBlend_BLEN_ONE_MINUS_SRC_COLOR) == 0)
-        return RenderState::BLEN_ONE_MINUS_SRC_COLOR;
+    if (strcmp(s, luaEnumString_RenderStateBlend_BLEND_ONE_MINUS_SRC_COLOR) == 0)
+        return RenderState::BLEND_ONE_MINUS_SRC_COLOR;
     if (strcmp(s, luaEnumString_RenderStateBlend_BLEND_DST_COLOR) == 0)
         return RenderState::BLEND_DST_COLOR;
     if (strcmp(s, luaEnumString_RenderStateBlend_BLEND_ONE_MINUS_DST_COLOR) == 0)
@@ -60,8 +60,8 @@ const char* lua_stringFromEnum_RenderStateBlend(RenderState::Blend e)
         return luaEnumString_RenderStateBlend_BLEND_ONE;
     if (e == RenderState::BLEND_SRC_COLOR)
         return luaEnumString_RenderStateBlend_BLEND_SRC_COLOR;
-    if (e == RenderState::BLEN_ONE_MINUS_SRC_COLOR)
-        return luaEnumString_RenderStateBlend_BLEN_ONE_MINUS_SRC_COLOR;
+    if (e == RenderState::BLEND_ONE_MINUS_SRC_COLOR)
+        return luaEnumString_RenderStateBlend_BLEND_ONE_MINUS_SRC_COLOR;
     if (e == RenderState::BLEND_DST_COLOR)
         return luaEnumString_RenderStateBlend_BLEND_DST_COLOR;
     if (e == RenderState::BLEND_ONE_MINUS_DST_COLOR)