Przeglądaj źródła

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

Ramprasad Madhavan 14 lat temu
rodzic
commit
2b0b288c59

+ 4 - 4
gameplay-encoder/gameplay-encoder.vcxproj

@@ -145,16 +145,16 @@
       </PrecompiledHeader>
       <WarningLevel>Level4</WarningLevel>
       <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;NO_BOOST;NO_ZAE;USE_FBX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <AdditionalIncludeDirectories>../external-deps/freetype2/include;../external-deps/collada-dom/include;../external-deps/collada-dom/include/1.4;../external-deps/libpng/include;../external-deps/zlib/include;C:/Program Files/Autodesk/FBX/FbxSdk/2012.2/include</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;NO_BOOST;NO_ZAE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>../external-deps/freetype2/include;../external-deps/collada-dom/include;../external-deps/collada-dom/include/1.4;../external-deps/libpng/include;../external-deps/zlib/include</AdditionalIncludeDirectories>
       <DisableLanguageExtensions>
       </DisableLanguageExtensions>
     </ClCompile>
     <Link>
       <SubSystem>Console</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
-      <AdditionalLibraryDirectories>../external-deps/freetype2/lib/win32;../external-deps/collada-dom/lib/win32;../external-deps/libpng/lib/win32;../external-deps/zlib/lib/win32;C:/Program Files/Autodesk/FBX/FbxSdk/2012.2/lib/vs2010/x86</AdditionalLibraryDirectories>
-      <AdditionalDependencies>freetype245.lib;libcollada14dom22-d.lib;libpng14.lib;zlib.lib;fbxsdk-2012.2-mdd.lib;wininet.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>../external-deps/freetype2/lib/win32;../external-deps/collada-dom/lib/win32;../external-deps/libpng/lib/win32;../external-deps/zlib/lib/win32</AdditionalLibraryDirectories>
+      <AdditionalDependencies>freetype245.lib;libcollada14dom22-d.lib;libpng14.lib;zlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <IgnoreSpecificDefaultLibraries>MSVCRT</IgnoreSpecificDefaultLibraries>
     </Link>
     <PostBuildEvent>

+ 14 - 6
gameplay-encoder/src/DAESceneEncoder.cpp

@@ -272,23 +272,31 @@ void DAESceneEncoder::write(const std::string& filepath, const EncoderArguments&
         {
             if (nodeId == NULL)
             {
-                // If the -n <node_id> parameter was not passed then write out the entire scene.
+                // If the -i <node_id> parameter was not passed then write out the entire scene.
                 begin();
                 loadScene((domVisual_scene*)scene);
                 end("load scene");
             }
             else
             {
-                // Resolve/Search for the node the user specified with the -n <node_id> parameter.
+                // Resolve/Search for the node the user specified with the -i <node_id> parameter.
                 daeSIDResolver resolver(scene, nodeId);
-                const domNode* node = daeSafeCast<domNode>(resolver.getElement());
-                if (node)
+                domNode* nodeElement = daeSafeCast<domNode>(resolver.getElement());
+                if (nodeElement)
                 {
-                    //createNode(node, NULL);
+                    Node* node = loadNode(nodeElement, NULL);
+                    if (node)
+                    {
+                        _gamePlayFile.addScenelessNode(node);
+                    }
+                    else
+                    {
+                        fprintf(stderr,"COLLADA File loaded to the dom, but failed to load node %s.\n", nodeId);
+                    }
                 }
                 else
                 {
-                    fprintf(stderr,"COLLADA File loaded to the dom, but node was not found with -n%s.\n", nodeId);
+                    fprintf(stderr,"COLLADA File loaded to the dom, but node was not found with node ID %s.\n", nodeId);
                 }
             }
         }

+ 1 - 1
gameplay-encoder/src/EncoderArguments.cpp

@@ -141,7 +141,7 @@ void EncoderArguments::printUsage() const
     fprintf(stderr,"  .ttf\t(TrueType Font)\n");
     fprintf(stderr,"\n");
     fprintf(stderr,"COLLADA and FBX file options:\n");
-    fprintf(stderr,"  -i<id>\t\tFilter by node ID.\n");
+    fprintf(stderr,"  -i <id>\t\tFilter by node ID.\n");
     fprintf(stderr,"  -t\t\t\tWrite text/xml.\n");
     fprintf(stderr,"  -groupAnimations <node id> <animation id>\n" \
         "\t\t\tGroup all animation channels targetting the nodes into a new animation.\n");

+ 10 - 0
gameplay-encoder/src/GPBFile.cpp

@@ -115,6 +115,16 @@ void GPBFile::addNode(Node* node)
     _nodes.push_back(node);
 }
 
+void GPBFile::addScenelessNode(Node* node)
+{
+    addToRefTable(node);
+    _nodes.push_back(node);
+    // Nodes are normally written to file as part of a scene. 
+    // Nodes that don't belong to a scene need to be written on their own (outside a scene).
+    // That is why node is added to the list of objects here.
+    _objects.push_back(node);
+}
+
 void GPBFile::addAnimation(Animation* animation)
 {
     _animations.add(animation);

+ 4 - 0
gameplay-encoder/src/GPBFile.h

@@ -65,6 +65,10 @@ public:
     void addLight(Light* light);
     void addMesh(Mesh* mesh);
     void addNode(Node* node);
+    /**
+     * Adds a node that does not belong to a scene.
+     */
+    void addScenelessNode(Node* node);
     void addAnimation(Animation* animation);
 
     /**

+ 10 - 11
gameplay/src/AnimationClip.cpp

@@ -441,6 +441,16 @@ bool AnimationClip::update(unsigned long elapsedTime)
     if (!_isPlaying)
     {
         onEnd();
+        // Notify end listeners if any.
+        if (_endListeners)
+        {
+            std::vector<Listener*>::iterator listener = _endListeners->begin();
+            while (listener != _endListeners->end())
+            {
+                (*listener)->animationEvent(this, Listener::END);
+                listener++;
+            }
+        }
     }
 
     return !_isPlaying;
@@ -494,17 +504,6 @@ void AnimationClip::onEnd()
 
     _blendWeight = 1.0f;
     _timeStarted = 0;
-
-    // Notify end listeners if any.
-    if (_endListeners)
-    {
-        std::vector<Listener*>::iterator listener = _endListeners->begin();
-        while (listener != _endListeners->end())
-        {
-            (*listener)->animationEvent(this, Listener::END);
-            listener++;
-        }
-    }
 }
 
 }

+ 5 - 2
gameplay/src/AnimationController.cpp

@@ -7,7 +7,7 @@ namespace gameplay
 {
 
 AnimationController::AnimationController()
-    : _state(IDLE), _animations(NULL)
+    : _state(STOPPED), _animations(NULL)
 {
 }
 
@@ -66,6 +66,7 @@ Animation* AnimationController::createAnimationFromTo(const char* id, AnimationT
 
     Animation* animation = createAnimation(id, target, propertyId, 2, keyTimes, keyValues, type);
 
+    SAFE_DELETE_ARRAY(keyValues);
     SAFE_DELETE_ARRAY(keyTimes);
     
     return animation;
@@ -85,6 +86,7 @@ Animation* AnimationController::createAnimationFromBy(const char* id, AnimationT
 
     Animation* animation = createAnimation(id, target, propertyId, 2, keyTimes, keyValues, type);
 
+    SAFE_DELETE_ARRAY(keyValues);
     SAFE_DELETE_ARRAY(keyTimes);
 
     return animation;
@@ -112,6 +114,7 @@ void AnimationController::stopAllAnimations()
         clip->_isPlaying = false;
         clip->onEnd();
         SAFE_RELEASE(clip);
+        clipIter++;
     }
     _runningClips.clear();
 
@@ -269,7 +272,7 @@ void AnimationController::initialize()
 void AnimationController::finalize()
 {
     stopAllAnimations();
-    _state = PAUSED;
+    _state = STOPPED;
 }
 
 void AnimationController::resume()

+ 2 - 1
gameplay/src/AnimationController.h

@@ -117,7 +117,8 @@ private:
     {
         RUNNING,
         IDLE,
-        PAUSED
+        PAUSED,
+        STOPPED
     };
 
     /**

+ 4 - 0
gameplay/src/Game.h

@@ -191,6 +191,7 @@ public:
      * @param evt The key event that occured.
      * @param key The key code that was pressed, released or repeated.
      * 
+     * @see Keyboard::KeyEvent
      * @see Keyboard::Key
      */
     virtual void keyEvent(Keyboard::KeyEvent evt, int key);
@@ -199,6 +200,9 @@ public:
      * Touch callback on touch events.
      *
      * @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 The order of occurrence for multiple touch contacts starting at zero.
      *
      * @see Touch::TouchEvent
      */

+ 0 - 2
gameplay/src/Matrix.cpp

@@ -635,8 +635,6 @@ bool Matrix::invert(Matrix* dst) const
     inverse.m[14] = -m[12] * a3 + m[13] * a1 - m[14] * a0;
     inverse.m[15] = m[8] * a3 - m[9] * a1 + m[10] * a0;
 
-    memcpy(dst->m, inverse.m, MATRIX_SIZE);
-
     multiply(inverse, 1.0f / det, dst);
 
     return true;

+ 36 - 42
gameplay/src/Package.cpp

@@ -66,12 +66,30 @@ bool Package::readArray(unsigned int* length, T** ptr)
     }
     if (*length > 0)
     {
-       *ptr = new T[*length];
-       if (fread(*ptr, sizeof(T), *length, _file) != *length)
-       {
-           SAFE_DELETE_ARRAY(*ptr);
-           return false;
-       }
+        *ptr = new T[*length];
+        if (fread(*ptr, sizeof(T), *length, _file) != *length)
+        {
+            SAFE_DELETE_ARRAY(*ptr);
+            return false;
+        }
+    }
+    return true;
+}
+
+template <class T>
+bool Package::readArray(unsigned int* length, std::vector<T>* values)
+{
+    if (!read(length))
+    {
+        return false;
+    }
+    if (*length > 0 && values)
+    {
+        values->resize(*length);
+        if (fread(&(*values)[0], sizeof(T), *length, _file) != *length)
+        {
+            return false;
+        }
     }
     return true;
 }
@@ -87,20 +105,16 @@ std::string readString(FILE* fp)
     // Sanity check to detect if string length is far too big
     assert(length < PACKAGE_MAX_STRING_LENGTH);
 
-    char* str = new char[length + 1];
+    std::string str;
     if (length > 0)
     {
-        if (fread(str, 1, length, fp) != length)
+        str.resize(length);
+        if (fread(&str[0], 1, length, fp) != length)
         {
-            SAFE_DELETE_ARRAY(str);
             return std::string();
         }
     }
-
-    str[length] = '\0';
-    std::string result(str);
-    SAFE_DELETE_ARRAY(str);
-    return result;
+    return str;
 }
 
 Package* Package::create(const char* path)
@@ -907,11 +921,11 @@ Animation* Package::readAnimationChannel(Scene* scene, Animation* animation, con
         }
     }
 
-    unsigned long* keyTimes = NULL;
-    float* values = NULL;
-    float* tangentsIn = NULL;
-    float* tangentsOut = NULL;
-    unsigned int* interpolation = NULL;
+    std::vector<unsigned long> keyTimes;
+    std::vector<float> values;
+    std::vector<float> tangentsIn;
+    std::vector<float> tangentsOut;
+    std::vector<unsigned long> interpolation;
 
     // length of the arrays
     unsigned int keyTimesCount;
@@ -924,7 +938,6 @@ Animation* Package::readAnimationChannel(Scene* scene, Animation* animation, con
     if (!readArray(&keyTimesCount, &keyTimes))
     {
         LOG_ERROR_VARG("Failed to read %s for %s: %s", "keyTimes", "animation", id);
-        SAFE_DELETE_ARRAY(keyTimes);
         return NULL;
     }
     
@@ -932,8 +945,6 @@ Animation* Package::readAnimationChannel(Scene* scene, Animation* animation, con
     if (!readArray(&valuesCount, &values))
     {
         LOG_ERROR_VARG("Failed to read %s for %s: %s", "values", "animation", id);
-        SAFE_DELETE_ARRAY(keyTimes);
-        SAFE_DELETE_ARRAY(values);
         return NULL;
     }
     
@@ -941,9 +952,6 @@ Animation* Package::readAnimationChannel(Scene* scene, Animation* animation, con
     if (!readArray(&tangentsInCount, &tangentsIn))
     {
         LOG_ERROR_VARG("Failed to read %s for %s: %s", "tangentsIn", "animation", id);
-        SAFE_DELETE_ARRAY(keyTimes);
-        SAFE_DELETE_ARRAY(values);
-        SAFE_DELETE_ARRAY(tangentsIn);
         return NULL;
     }
     
@@ -951,10 +959,6 @@ Animation* Package::readAnimationChannel(Scene* scene, Animation* animation, con
     if (!readArray(&tangentsOutCount, &tangentsOut))
     {
         LOG_ERROR_VARG("Failed to read %s for %s: %s", "tangentsOut", "animation", id);
-        SAFE_DELETE_ARRAY(keyTimes);
-        SAFE_DELETE_ARRAY(values);
-        SAFE_DELETE_ARRAY(tangentsIn);
-        SAFE_DELETE_ARRAY(tangentsOut);
         return NULL;
     }
     
@@ -962,11 +966,6 @@ Animation* Package::readAnimationChannel(Scene* scene, Animation* animation, con
     if (!readArray(&interpolationCount, &interpolation))
     {
         LOG_ERROR_VARG("Failed to read %s for %s: %s", "interpolation", "animation", id);
-        SAFE_DELETE_ARRAY(keyTimes);
-        SAFE_DELETE_ARRAY(values);
-        SAFE_DELETE_ARRAY(tangentsIn);
-        SAFE_DELETE_ARRAY(tangentsOut);
-        SAFE_DELETE_ARRAY(interpolation);
         return NULL;
     }
 
@@ -976,23 +975,18 @@ Animation* Package::readAnimationChannel(Scene* scene, Animation* animation, con
     // TODO: Handle other target attributes later.
     if (targetAttribute > 0)
     {
+        assert(keyTimes.size() > 0 && values.size() > 0);
         if (animation == NULL)
         {
             // TODO: This code currently assumes LINEAR only
-            animation = controller->createAnimation(animationId, target, targetAttribute, keyTimesCount, keyTimes, values, Curve::LINEAR);
+            animation = controller->createAnimation(animationId, target, targetAttribute, keyTimesCount, &keyTimes[0], &values[0], Curve::LINEAR);
         }
         else
         {
-            animation->createChannel(target, targetAttribute, keyTimesCount, keyTimes, values, Curve::LINEAR);
+            animation->createChannel(target, targetAttribute, keyTimesCount, &keyTimes[0], &values[0], Curve::LINEAR);
         }
     }
 
-    SAFE_DELETE_ARRAY(keyTimes);
-    SAFE_DELETE_ARRAY(values);
-    SAFE_DELETE_ARRAY(tangentsIn);
-    SAFE_DELETE_ARRAY(tangentsOut);
-    SAFE_DELETE_ARRAY(interpolation);
-
     return animation;
 }
 

+ 11 - 0
gameplay/src/Package.h

@@ -252,6 +252,17 @@ private:
     template <class T>
     bool readArray(unsigned int* length, T** ptr);
 
+    /**
+     * Reads an array of values and the array length from the current file position.
+     * 
+     * @param length A pointer to where the length of the array will be copied to.
+     * @param values A pointer to the vector to copy the values to. The vector will be resized if it is smaller than length.
+     * 
+     * @return True if successful, false if an error occurred.
+     */
+    template <class T>
+    bool readArray(unsigned int* length, std::vector<T>* values);
+
     /**
      * Reads 16 floats from the current file position.
      *

+ 136 - 81
gameplay/src/PhysicsController.cpp

@@ -297,6 +297,23 @@ void PhysicsController::removeRigidBody(PhysicsRigidBody* rigidBody)
             break;
         }
     }
+
+    // Find the rigid body's collision shape and release the rigid body's reference to it.
+    for (unsigned int i = 0; i < _shapes.size(); i++)
+    {
+        if (_shapes[i]->_shape == rigidBody->_shape)
+        {
+            if (_shapes[i]->getRefCount() == 1)
+            {
+                _shapes[i]->release();
+                _shapes.erase(_shapes.begin() + i);
+            }
+            else
+                _shapes[i]->release();
+
+            return;
+        }
+    }
 }
 
 PhysicsRigidBody* PhysicsController::getRigidBody(const btCollisionObject* collisionObject)
@@ -314,12 +331,51 @@ PhysicsRigidBody* PhysicsController::getRigidBody(const btCollisionObject* colli
 btCollisionShape* PhysicsController::createBox(const Vector3& min, const Vector3& max, const btVector3& scale)
 {
     btVector3 halfExtents(scale.x() * 0.5 * abs(max.x - min.x), scale.y() * 0.5 * abs(max.y - min.y), scale.z() * 0.5 * abs(max.z - min.z));
+
+    // Return the box shape from the cache if it already exists.
+    for (unsigned int i = 0; i < _shapes.size(); i++)
+    {
+        if (_shapes[i]->_shape->getShapeType() == BOX_SHAPE_PROXYTYPE)
+        {
+            btBoxShape* box = static_cast<btBoxShape*>(_shapes[i]->_shape);
+            if (box->getHalfExtentsWithMargin() == halfExtents)
+            {
+                _shapes[i]->addRef();
+                return box;
+            }
+        }
+    }
+    
+    // Create the box shape and add it to the cache.
     btBoxShape* box = bullet_new<btBoxShape>(halfExtents);
-    _shapes.push_back(box);
+    _shapes.push_back(new PhysicsCollisionShape(box));
 
     return box;
 }
 
+btCollisionShape* PhysicsController::createCapsule(float radius, float height)
+{
+    // Return the capsule shape from the cache if it already exists.
+    for (unsigned int i = 0; i < _shapes.size(); i++)
+    {
+        if (_shapes[i]->_shape->getShapeType() == CAPSULE_SHAPE_PROXYTYPE)
+        {
+            btCapsuleShape* capsule = static_cast<btCapsuleShape*>(_shapes[i]->_shape);
+            if (capsule->getRadius() == radius && capsule->getHalfHeight() == 0.5f * height)
+            {
+                _shapes[i]->addRef();
+                return capsule;
+            }
+        }
+    }
+    
+    // Create the capsule shape and add it to the cache.
+    btCapsuleShape* capsule = bullet_new<btCapsuleShape>(radius, height);
+    _shapes.push_back(new PhysicsCollisionShape(capsule));
+
+    return capsule;
+}
+
 btCollisionShape* PhysicsController::createSphere(float radius, const btVector3& scale)
 {
     // Since sphere shapes depend only on the radius, the best we can do is take
@@ -330,8 +386,23 @@ btCollisionShape* PhysicsController::createSphere(float radius, const btVector3&
     if (uniformScale < scale.z())
         uniformScale = scale.z();
     
+    // Return the sphere shape from the cache if it already exists.
+    for (unsigned int i = 0; i < _shapes.size(); i++)
+    {
+        if (_shapes[i]->_shape->getShapeType() == SPHERE_SHAPE_PROXYTYPE)
+        {
+            btSphereShape* sphere = static_cast<btSphereShape*>(_shapes[i]->_shape);
+            if (sphere->getRadius() == uniformScale * radius)
+            {
+                _shapes[i]->addRef();
+                return sphere;
+            }
+        }
+    }
+
+    // Create the sphere shape and add it to the cache.
     btSphereShape* sphere = bullet_new<btSphereShape>(uniformScale * radius);
-    _shapes.push_back(sphere);
+    _shapes.push_back(new PhysicsCollisionShape(sphere));
     
     return sphere;
 }
@@ -431,7 +502,7 @@ btCollisionShape* PhysicsController::createMesh(PhysicsRigidBody* body)
     }
 
     btBvhTriangleMeshShape* shape = bullet_new<btBvhTriangleMeshShape>(meshInterface, true);
-    _shapes.push_back(shape);
+    _shapes.push_back(new PhysicsCollisionShape(shape));
 
     return shape;
 }
@@ -480,103 +551,87 @@ void PhysicsController::removeConstraint(PhysicsConstraint* constraint)
     
 PhysicsController::DebugDrawer::DebugDrawer()
     : _mode(btIDebugDraw::DBG_DrawAabb | btIDebugDraw::DBG_DrawConstraintLimits | btIDebugDraw::DBG_DrawConstraints | 
-       btIDebugDraw::DBG_DrawContactPoints | btIDebugDraw::DBG_DrawWireframe), _effect(NULL), _positionAttrib(0), _colorAttrib(0),
-       _viewProjectionMatrixUniform(NULL), _viewProjection(NULL), _vertexData(NULL), _vertexCount(0), _vertexDataSize(0)
+       btIDebugDraw::DBG_DrawContactPoints | btIDebugDraw::DBG_DrawWireframe), _viewProjection(NULL), _meshBatch(NULL)
 {
-    // Unused
+    // Vertex shader for drawing colored lines.
+    const char* vs_str = 
+    {
+        "uniform mat4 u_viewProjectionMatrix;\n"
+        "attribute vec4 a_position;\n"
+        "attribute vec4 a_color;\n"
+        "varying vec4 v_color;\n"
+        "void main(void) {\n"
+        "    v_color = a_color;\n"
+        "    gl_Position = u_viewProjectionMatrix * a_position;\n"
+        "}"
+    };
+        
+    // Fragment shader for drawing colored lines.
+    const char* fs_str = 
+    {
+    #ifdef OPENGL_ES
+        "precision highp float;\n"
+    #endif
+        "varying vec4 v_color;\n"
+        "void main(void) {\n"
+        "   gl_FragColor = v_color;\n"
+        "}"
+    };
+        
+    Effect* effect = Effect::createFromSource(vs_str, fs_str);
+    Material* material = Material::create(effect);
+
+    VertexFormat::Element elements[] =
+    {
+        VertexFormat::Element(VertexFormat::POSITION, 3),
+        VertexFormat::Element(VertexFormat::COLOR, 4),
+    };
+    _meshBatch = MeshBatch::create(VertexFormat(elements, 2), Mesh::LINES, material, false);
+    
+    SAFE_RELEASE(material);
+    SAFE_RELEASE(effect);
 }
 
 PhysicsController::DebugDrawer::~DebugDrawer()
 {
-    SAFE_RELEASE(_effect);
-    SAFE_DELETE_ARRAY(_vertexData);
+    SAFE_DELETE(_meshBatch);
 }
 
 void PhysicsController::DebugDrawer::begin(const Matrix& viewProjection)
 {
     _viewProjection = &viewProjection;
-    _vertexCount = 0;
+    _meshBatch->begin();
 }
 
 void PhysicsController::DebugDrawer::end()
 {
-    // Lazy load the effect for drawing.
-    if (!_effect)
-    {
-        // Vertex shader for drawing colored lines.
-        const char* vs_str = 
-        {
-            "uniform mat4 u_viewProjectionMatrix;\n"
-            "attribute vec4 a_position;\n"
-            "attribute vec4 a_color;\n"
-            "varying vec4 v_color;\n"
-            "void main(void) {\n"
-            "    v_color = a_color;\n"
-            "    gl_Position = u_viewProjectionMatrix * a_position;\n"
-            "}"
-        };
-        
-        // Fragment shader for drawing colored lines.
-        const char* fs_str = 
-        {
-        #ifdef OPENGL_ES
-            "precision highp float;\n"
-        #endif
-            "varying vec4 v_color;\n"
-            "void main(void) {\n"
-            "   gl_FragColor = v_color;\n"
-            "}"
-        };
-        
-        _effect = Effect::createFromSource(vs_str, fs_str);
-        _positionAttrib = _effect->getVertexAttribute("a_position");
-        _colorAttrib = _effect->getVertexAttribute("a_color");
-        _viewProjectionMatrixUniform = _effect->getUniform("u_viewProjectionMatrix");
-    }
-    
-    // Bind the effect and set the vertex attributes.
-    _effect->bind();
-    GL_ASSERT( glEnableVertexAttribArray(_positionAttrib) );
-    GL_ASSERT( glEnableVertexAttribArray(_colorAttrib) );
-    GL_ASSERT( glVertexAttribPointer(_positionAttrib, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 7, _vertexData) );
-    GL_ASSERT( glVertexAttribPointer(_colorAttrib, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 7, &_vertexData[3]) );
-    
-    // Set the camera's view projection matrix and draw.
-    _effect->setValue( _viewProjectionMatrixUniform, _viewProjection);
-    GL_ASSERT( glDrawArrays(GL_LINES, 0, _vertexCount / 7) );
+    _meshBatch->getMaterial()->getParameter("u_viewProjectionMatrix")->setValue(_viewProjection);
+    _meshBatch->draw();
+    _meshBatch->end();
 }
 
 void PhysicsController::DebugDrawer::drawLine(const btVector3& from, const btVector3& to, const btVector3& fromColor, const btVector3& toColor)
 {
-    // Allocate extra space in the vertex data batch if it is needed.
-    if (_vertexDataSize - _vertexCount < 14)
-    {
-        if (_vertexDataSize > 0)
-        {
-            unsigned int newVertexDataSize = _vertexDataSize * 2;
-            float* newVertexData = new float[newVertexDataSize];
-            memcpy(newVertexData, _vertexData, _vertexDataSize * sizeof(float));
-            SAFE_DELETE_ARRAY(_vertexData);
-            _vertexData = newVertexData;
-            _vertexDataSize = newVertexDataSize;
-        }
-        else
-        {
-            _vertexDataSize = INITIAL_CAPACITY;
-            _vertexData = new float[_vertexDataSize];
-        }
-    }
+    static DebugDrawer::DebugVertex fromVertex, toVertex;
     
-    // Create the vertex data for the line and copy it into the batch.
-    float vertexData[] = 
-    {
-        from.getX(), from.getY(), from.getZ(), 
-        fromColor.getX(), fromColor.getY(), fromColor.getZ(), 1.0f,
-        to.getX(), to.getY(), to.getZ(),
-        toColor.getX(), toColor.getY(), toColor.getZ(), 1.0f
-    };
-    memcpy(&_vertexData[_vertexCount], vertexData, sizeof(float) * 14);
-    _vertexCount += 14;
+    fromVertex.x = from.getX();
+    fromVertex.y = from.getY();
+    fromVertex.z = from.getZ();
+    fromVertex.r = fromColor.getX();
+    fromVertex.g = fromColor.getY();
+    fromVertex.b = fromColor.getZ();
+    fromVertex.a = 1.0f;
+
+    toVertex.x = to.getX();
+    toVertex.y = to.getY();
+    toVertex.z = to.getZ();
+    toVertex.r = toColor.getX();
+    toVertex.g = toColor.getY();
+    toVertex.b = toColor.getZ();
+    toVertex.a = 1.0f;
+
+    _meshBatch->add(&fromVertex, 1);
+    _meshBatch->add(&toVertex, 1);
 }
 
 void PhysicsController::DebugDrawer::drawLine(const btVector3& from, const btVector3& to, const btVector3& color)

+ 20 - 9
gameplay/src/PhysicsController.h

@@ -191,6 +191,14 @@ public:
 
 private:
 
+    struct PhysicsCollisionShape : public Ref
+    {
+        PhysicsCollisionShape(btCollisionShape* shape) : _shape(shape) {}
+        ~PhysicsCollisionShape() { SAFE_DELETE(_shape); }
+
+        btCollisionShape* _shape;
+    };
+
     /**
      * Constructor.
      */
@@ -238,6 +246,9 @@ private:
     // Creates a box collision shape to be used in the creation of a rigid body.
     btCollisionShape* createBox(const Vector3& min, const Vector3& max, const btVector3& scale);
 
+    // Creates a capsule collision shape to be used in the creation of a rigid body.
+    btCollisionShape* createCapsule(float radius, float height);
+
     // Creates a sphere collision shape to be used in the creation of a rigid body.
     btCollisionShape* createSphere(float radius, const btVector3& scale);
 
@@ -258,6 +269,12 @@ private:
     {
     public:
 
+        struct DebugVertex
+        {
+            float x, y, z;
+            float r, g, b, a;
+        };
+
         DebugDrawer();        
         ~DebugDrawer();
         
@@ -268,7 +285,7 @@ private:
         void drawLine(const btVector3& from, const btVector3& to, const btVector3& fromColor, const btVector3& toColor);        
         void drawLine(const btVector3& from, const btVector3& to, const btVector3& color);        
         void drawContactPoint(const btVector3& pointOnB, const btVector3& normalOnB, btScalar distance, int lifeTime, const btVector3& color);        
-        void reportErrorWarning(const char* warningString);        
+        void reportErrorWarning(const char* warningString);
         void draw3dText(const btVector3& location, const char* textString);        
         void setDebugMode(int mode);        
         int	getDebugMode() const;
@@ -276,14 +293,8 @@ private:
     private:
         
         int _mode;
-        Effect* _effect;
-        VertexAttribute _positionAttrib;
-        VertexAttribute _colorAttrib;
-        Uniform* _viewProjectionMatrixUniform;
         const Matrix* _viewProjection;
-        float* _vertexData;
-        unsigned int _vertexCount;
-        unsigned int _vertexDataSize;
+        MeshBatch* _meshBatch;
     };
     
     btDefaultCollisionConfiguration* _collisionConfiguration;
@@ -291,7 +302,7 @@ private:
     btBroadphaseInterface* _overlappingPairCache;
     btSequentialImpulseConstraintSolver* _solver;
     btDynamicsWorld* _world;
-    btAlignedObjectArray<btCollisionShape*> _shapes;
+    std::vector<PhysicsCollisionShape*> _shapes;
     DebugDrawer* _debugDrawer;
     Listener::EventType _status;
     std::vector<Listener*>* _listeners;

+ 79 - 27
gameplay/src/PhysicsRigidBody.cpp

@@ -14,15 +14,16 @@ const int PhysicsRigidBody::Listener::DIRTY         = 0x01;
 const int PhysicsRigidBody::Listener::COLLISION     = 0x02;
 const int PhysicsRigidBody::Listener::REGISTERED    = 0x04;
 
-// Internal values used for creating mesh and heightfield rigid bodies.
+// Internal values used for creating mesh, heightfield, and capsule rigid bodies.
 #define SHAPE_MESH ((PhysicsRigidBody::Type)(PhysicsRigidBody::SHAPE_NONE + 1))
 #define SHAPE_HEIGHTFIELD ((PhysicsRigidBody::Type)(PhysicsRigidBody::SHAPE_NONE + 2))
+#define SHAPE_CAPSULE ((PhysicsRigidBody::Type)(PhysicsRigidBody::SHAPE_NONE + 3))
 
 // Helper function for calculating heights from heightmap (image) or heightfield data.
 static float calculateHeight(float* data, unsigned int width, unsigned int height, float x, float y);
 
 PhysicsRigidBody::PhysicsRigidBody(Node* node, PhysicsRigidBody::Type type, float mass, 
-        float friction, float restitution, float linearDamping, float angularDamping)
+    float friction, float restitution, float linearDamping, float angularDamping)
         : _shape(NULL), _body(NULL), _node(node), _listeners(NULL), _angularVelocity(NULL),
         _anisotropicFriction(NULL), _gravity(NULL), _linearVelocity(NULL), _vertexData(NULL),
         _indexData(NULL), _heightfieldData(NULL), _inverse(NULL), _inverseIsDirty(true)
@@ -144,6 +145,29 @@ PhysicsRigidBody::PhysicsRigidBody(Node* node, Image* image, float mass,
     _node->addListener(this);
 }
 
+PhysicsRigidBody::PhysicsRigidBody(Node* node, float radius, float height, float mass, float friction,
+    float restitution, float linearDamping, float angularDamping)
+        : _shape(NULL), _body(NULL), _node(node), _listeners(NULL), _angularVelocity(NULL),
+        _anisotropicFriction(NULL), _gravity(NULL), _linearVelocity(NULL), _vertexData(NULL),
+        _indexData(NULL), _heightfieldData(NULL), _inverse(NULL), _inverseIsDirty(true)
+{
+    // Create the capsule collision shape.
+    _shape = Game::getInstance()->getPhysicsController()->createCapsule(radius, height);
+
+    // Use the center of the bounding sphere as the center of mass offset.
+    Vector3 c(node->getModel()->getMesh()->getBoundingSphere().center);
+    c.negate();
+
+    // Create the Bullet rigid body.
+    if (c.lengthSquared() > MATH_EPSILON)
+        _body = createRigidBodyInternal(_shape, mass, node, friction, restitution, linearDamping, angularDamping, &c);
+    else
+        _body = createRigidBodyInternal(_shape, mass, node, friction, restitution, linearDamping, angularDamping);
+
+    // Add the rigid body to the physics world.
+    Game::getInstance()->getPhysicsController()->addRigidBody(this);
+}
+
 PhysicsRigidBody::~PhysicsRigidBody()
 {
     // Clean up all constraints linked to this rigid body.
@@ -161,8 +185,6 @@ PhysicsRigidBody::~PhysicsRigidBody()
         if (_body->getMotionState())
             delete _body->getMotionState();
 
-        SAFE_DELETE(_shape);
-
         Game::getInstance()->getPhysicsController()->removeRigidBody(this);
         SAFE_DELETE(_body);
     }
@@ -294,6 +316,8 @@ PhysicsRigidBody* PhysicsRigidBody::create(Node* node, Properties* properties)
     Vector3* gravity = NULL;
     Vector3* anisotropicFriction = NULL;
     const char* imagePath = NULL;
+    float radius = -1.0f;
+    float height = -1.0f;
 
     // Load the defined properties.
     properties->rewind();
@@ -311,6 +335,8 @@ PhysicsRigidBody* PhysicsRigidBody::create(Node* node, Properties* properties)
                 type = SHAPE_MESH;
             else if (typeStr == "HEIGHTFIELD")
                 type = SHAPE_HEIGHTFIELD;
+            else if (typeStr == "CAPSULE")
+                type = SHAPE_CAPSULE;
             else
             {
                 WARN_VARG("Could not create rigid body; unsupported value for rigid body type: '%s'.", typeStr.c_str());
@@ -355,6 +381,14 @@ PhysicsRigidBody* PhysicsRigidBody::create(Node* node, Properties* properties)
         {
             imagePath = properties->getString();
         }
+        else if (strcmp(name, "radius") == 0)
+        {
+            radius = properties->getFloat();
+        }
+        else if (strcmp(name, "height") == 0)
+        {
+            height = properties->getFloat();
+        }
     }
 
     // If the rigid body type is equal to mesh, check that the node's mesh's primitive type is supported.
@@ -380,30 +414,48 @@ PhysicsRigidBody* PhysicsRigidBody::create(Node* node, Properties* properties)
 
     // Create the rigid body.
     PhysicsRigidBody* body = NULL;
-    if (imagePath == NULL)
-    {
-        body = new PhysicsRigidBody(node, type, mass, friction, restitution, linearDamping, angularDamping);
-    }
-    else
+    switch (type)
     {
-        // Load the image data from the given file path.
-        Image* image = Image::create(imagePath);
-        if (!image)
-            return NULL;
-
-        // Ensure that the image's pixel format is supported.
-        switch (image->getFormat())
-        {
-            case Image::RGB:
-            case Image::RGBA:
-                break;
-            default:
-                WARN_VARG("Heightmap: pixel format is not supported: %d", image->getFormat());
-                return NULL;
-        }
-
-        body = new PhysicsRigidBody(node, image, mass, friction, restitution, linearDamping, angularDamping);
-        SAFE_RELEASE(image);
+        case SHAPE_HEIGHTFIELD:
+            if (imagePath == NULL)
+            {
+                WARN("Heightfield rigid body requires an image path.");
+            }
+            else
+            {
+                // Load the image data from the given file path.
+                Image* image = Image::create(imagePath);
+                if (!image)
+                    return NULL;
+
+                // Ensure that the image's pixel format is supported.
+                switch (image->getFormat())
+                {
+                    case Image::RGB:
+                    case Image::RGBA:
+                        break;
+                    default:
+                        WARN_VARG("Heightmap: pixel format is not supported: %d", image->getFormat());
+                        return NULL;
+                }
+
+                body = new PhysicsRigidBody(node, image, mass, friction, restitution, linearDamping, angularDamping);
+                SAFE_RELEASE(image);
+            }
+            break;
+        case SHAPE_CAPSULE:
+            if (radius == -1.0f || height == -1.0f)
+            {
+                WARN("Both 'radius' and 'height' must be specified for a capsule rigid body.");
+            }
+            else
+            {
+                body = new PhysicsRigidBody(node, radius, height, mass, friction, restitution, linearDamping, angularDamping);
+            }
+            break;
+        default:
+            body = new PhysicsRigidBody(node, type, mass, friction, restitution, linearDamping, angularDamping);
+            break;
     }
 
     // Set any initially defined properties.

+ 17 - 0
gameplay/src/PhysicsRigidBody.h

@@ -325,6 +325,23 @@ private:
     PhysicsRigidBody(Node* node, Image* image, float mass, float friction = 0.5,
         float restitution = 0.0, float linearDamping = 0.0, float angularDamping = 0.0);
 
+    /**
+     * Creates a capsule rigid body.
+     * 
+     * @param node The node to create the heightfield rigid body for; note that the node must have
+     *      a model attached to it prior to creating a rigid body for it.
+     * @param radius The radius of the capsule.
+     * @param height The height of the cylindrical part of the capsule (not including the ends).
+     * @param mass The mass of the rigid body, in kilograms.
+     * @param friction The friction of the rigid body (non-zero values give best simulation results).
+     * @param restitution The restitution of the rigid body (this controls the bounciness of
+     *      the rigid body; use zero for best simulation results).
+     * @param linearDamping The percentage of linear velocity lost per second (between 0.0 and 1.0).
+     * @param angularDamping The percentage of angular velocity lost per second (between 0.0 and 1.0).
+     */
+    PhysicsRigidBody(Node* node, float radius, float height, float mass, float friction = 0.5,
+        float restitution = 0.0, float linearDamping = 0.0, float angularDamping = 0.0);
+
     /**
      * Destructor.
      */

+ 504 - 373
gameplay/src/PlatformAndroid.cpp

@@ -1,373 +1,504 @@
-#ifdef __ANDROID__
-
-#include "Base.h"
-#include "Platform.h"
-#include "FileSystem.h"
-#include "Game.h"
-#include <unistd.h>
-
-#include <android/sensor.h>
-#include <android_native_app_glue.h>
-
-#include <android/log.h>
-#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
-
-#define TOUCH_COUNT_MAX     4
-
-using namespace std;
-
-struct timespec __timespec;
-static long __timeStart;
-static long __timeAbsolute;
-static bool __vsync = WINDOW_VSYNC;
-
-struct android_app* __state;
-extern std::string __assetsPath;
-int __width;
-int __height;
-static EGLDisplay __eglDisplay = EGL_NO_DISPLAY;
-static EGLContext __eglContext = EGL_NO_CONTEXT;
-static EGLSurface __eglSurface = EGL_NO_SURFACE;
-static EGLConfig __eglConfig = 0;
-ASensorManager* __sensorManager;
-const ASensor* __accelerometerSensor;
-ASensorEventQueue* __sensorEventQueue;
-ASensorEvent __sensorEvent;
-static int __orientationAngle;
-static bool __multiTouch = false;
-
-static const char* __glExtensions;
-PFNGLBINDVERTEXARRAYOESPROC glBindVertexArray = NULL;
-PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays = NULL;
-PFNGLGENVERTEXARRAYSOESPROC glGenVertexArrays = NULL;
-PFNGLISVERTEXARRAYOESPROC glIsVertexArray = NULL;
-
-
-
-//gameplay::Keyboard::Key getKey(int keycode, int metastate);
-
-namespace gameplay
-{
-
-// Gets the Keyboard::Key enumeration constant that corresponds to the given QNX key code.
-Keyboard::Key getKey(int keycode, int metastate)
-{
-    
-	// TODO.
-	
-	return Keyboard::KEY_NONE;
-}
-
-
-extern void printError(const char* format, ...)
-{
-    va_list argptr;
-    va_start(argptr, format);
-    LOGI(format, argptr);
-    va_end(argptr);
-}
-
-EGLenum checkErrorEGL(const char* msg)
-{
-    static const char* errmsg[] =
-    {
-        "EGL function succeeded",
-        "EGL is not initialized, or could not be initialized, for the specified display",
-        "EGL cannot access a requested resource",
-        "EGL failed to allocate resources for the requested operation",
-        "EGL fail to access an unrecognized attribute or attribute value was passed in an attribute list",
-        "EGLConfig argument does not name a valid EGLConfig",
-        "EGLContext argument does not name a valid EGLContext",
-        "EGL current surface of the calling thread is no longer valid",
-        "EGLDisplay argument does not name a valid EGLDisplay",
-        "EGL arguments are inconsistent",
-        "EGLNativePixmapType argument does not refer to a valid native pixmap",
-        "EGLNativeWindowType argument does not refer to a valid native window",
-        "EGL one or more argument values are invalid",
-        "EGLSurface argument does not name a valid surface configured for rendering",
-        "EGL power management event has occurred",
-    };
-    EGLenum error = eglGetError();
-    LOGI("%s: %s\n", msg, errmsg[error - EGL_SUCCESS]);
-    return error;
-}
-
-Platform::Platform(Game* game)
-    : _game(game)
-{
-}
-
-Platform::Platform(const Platform& copy)
-{
-    // hidden
-}
-
-Platform::~Platform()
-{
-    if (__eglDisplay != EGL_NO_DISPLAY)
-    {
-        eglMakeCurrent(__eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-    }
-
-    if (__eglSurface != EGL_NO_SURFACE)
-    {
-        eglDestroySurface(__eglDisplay, __eglSurface);
-        __eglSurface = EGL_NO_SURFACE;
-    }
-
-    if (__eglContext != EGL_NO_CONTEXT)
-    {
-        eglDestroyContext(__eglDisplay, __eglContext);
-        __eglContext = EGL_NO_CONTEXT;
-    }
-
-    if (__eglDisplay != EGL_NO_DISPLAY)
-    {
-        eglTerminate(__eglDisplay);
-        __eglDisplay = EGL_NO_DISPLAY;
-    }
-}
-
-Platform* Platform::create(Game* game)
-{
-    FileSystem::setResourcePath(__assetsPath.c_str());
-   
-    Platform* platform = new Platform(game);
-
-    // Hard-coded to 32-bit/OpenGL ES 2.0.
-    const EGLint eglConfigAttrs[] =
-    {
-        EGL_RED_SIZE,           8,
-        EGL_GREEN_SIZE,         8,
-        EGL_BLUE_SIZE,          8,
-        EGL_ALPHA_SIZE,         8,
-        EGL_DEPTH_SIZE,         24,
-        EGL_STENCIL_SIZE,       8,
-        EGL_SURFACE_TYPE,       EGL_WINDOW_BIT,
-        EGL_RENDERABLE_TYPE,    EGL_OPENGL_ES2_BIT,
-        EGL_NONE
-    };
-    
-    EGLint eglConfigCount;
-    const EGLint eglContextAttrs[] =
-    {
-        EGL_CONTEXT_CLIENT_VERSION,    2,
-        EGL_NONE
-    };
-
-	const EGLint eglSurfaceAttrs[] =
-    {
-        EGL_RENDER_BUFFER,    EGL_BACK_BUFFER,
-        EGL_NONE
-    };
-
-    // Get the EGL display and initialize.
-    __eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    if (__eglDisplay == EGL_NO_DISPLAY)
-    {
-        checkErrorEGL("eglGetDisplay");
-        goto error;
-    }
-    
-    if (eglInitialize(__eglDisplay, NULL, NULL) != EGL_TRUE)
-    {
-        checkErrorEGL("eglInitialize");
-        goto error;
-    }
-
-    if (eglChooseConfig(__eglDisplay, eglConfigAttrs, &__eglConfig, 1, &eglConfigCount) != EGL_TRUE || eglConfigCount == 0)
-    {
-        checkErrorEGL("eglChooseConfig");
-        goto error;
-    }
-    
-    __eglContext = eglCreateContext(__eglDisplay, __eglConfig, EGL_NO_CONTEXT, eglContextAttrs);
-    if (__eglContext == EGL_NO_CONTEXT)
-    {
-        checkErrorEGL("eglCreateContext");
-        goto error;
-    }
-    
-    // EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
-    // guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
-    // As soon as we picked a EGLConfig, we can safely reconfigure the
-    // ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID.
-    EGLint format;
-    eglGetConfigAttrib(__eglDisplay, __eglConfig, EGL_NATIVE_VISUAL_ID, &format);
-    ANativeWindow_setBuffersGeometry(__state->window, 0, 0, format);
-
-    __eglSurface = eglCreateWindowSurface(__eglDisplay, __eglConfig, __state->window, eglSurfaceAttrs);
-    if (__eglSurface == EGL_NO_SURFACE)
-    {
-        checkErrorEGL("eglCreateWindowSurface");
-        goto error;
-    }
-
-    LOGI("Platform::create - 3");
-    
-    if (eglMakeCurrent(__eglDisplay, __eglSurface, __eglSurface, __eglContext) != EGL_TRUE)
-    {
-        checkErrorEGL("eglMakeCurrent");
-        goto error;
-    }
-
-    eglQuerySurface(__eglDisplay, __eglSurface, EGL_WIDTH, &__width);
-    eglQuerySurface(__eglDisplay, __eglSurface, EGL_HEIGHT, &__height);
-	
-    WARN_VARG("Platform::create - WIDTH: %d HEIGHT = %d" , __width, __height);
-    
-    // Set vsync.
-    eglSwapInterval(__eglDisplay, WINDOW_VSYNC ? 1 : 0);
-
-    // Initialize OpenGL ES extensions.
-    __glExtensions = (const char*)glGetString(GL_EXTENSIONS);
-
-    if (strstr(__glExtensions, "GL_OES_vertex_array_object") || strstr(__glExtensions, "GL_ARB_vertex_array_object"))
-    {
-        WARN("Platform::create - VAOs supported");
-		
-		// Disable VAO extension for now.
-        glBindVertexArray = (PFNGLBINDVERTEXARRAYOESPROC)eglGetProcAddress("glBindVertexArrayOES");
-        glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSOESPROC)eglGetProcAddress("glDeleteVertexArrays");
-        glGenVertexArrays = (PFNGLGENVERTEXARRAYSOESPROC)eglGetProcAddress("glGenVertexArraysOES");
-        glIsVertexArray = (PFNGLISVERTEXARRAYOESPROC)eglGetProcAddress("glIsVertexArrayOES");
-    }
-
-    
-    // TODO: Determine initial orientation angle.
-    //orientation_direction_t direction;
-    //orientation_get(&direction, &__orientationAngle);
-
-    return platform;
-
-error:
-
-    // TODO: cleanup.
-
-    return NULL;
-}
-
-/**
- * Convert the timespec into milliseconds.
- */
-long timespec2millis(struct timespec *a)
-{
-    return a->tv_sec*1000 + a->tv_nsec/1000000;
-}
-
-int Platform::enterMessagePump()
-{
-    static int state = 0;
-	
-	switch (state)
-	{
-		case 0:
-			// Get the initial time.
-			clock_gettime(CLOCK_REALTIME, &__timespec);
-			__timeStart = timespec2millis(&__timespec);
-			__timeAbsolute = 0L;
-			WARN_VARG("Platform::enterMessagePump() - WIDTH: %d HEIGHT = %d" , __width, __height);
-			_game->run(__width, __height);
-			
-			state = 1;
-			break;
-		case 1:
-			// Idle time (no events left to process) is spent rendering.
-			// We skip rendering when the app is paused.
-			if (_game->getState() != Game::PAUSED)
-			{
-				_game->frame();
-
-				// Post the new frame to the display.
-				// Note that there are a couple cases where eglSwapBuffers could fail
-				// with an error code that requires a certain level of re-initialization:
-				//
-				// 1) EGL_BAD_NATIVE_WINDOW - Called when the surface we're currently using
-				//    is invalidated. This would require us to destroy our EGL surface,
-				//    close our OpenKODE window, and start again.
-				//
-				// 2) EGL_CONTEXT_LOST - Power management event that led to our EGL context
-				//    being lost. Requires us to re-create and re-initalize our EGL context
-				//    and all OpenGL ES state.
-				//
-				// For now, if we get these, we'll simply exit.
-				int rc = eglSwapBuffers(__eglDisplay, __eglSurface);
-				if (rc != EGL_TRUE)
-				{
-					perror("eglSwapBuffers");
-					_game->exit();
-					break;
-				}
-			}
-			break;
-	}
-    
-    return 0;
-}
-
-long Platform::getAbsoluteTime()
-{
-    clock_gettime(CLOCK_REALTIME, &__timespec);
-    long now = timespec2millis(&__timespec);
-    __timeAbsolute = now - __timeStart;
-
-    return __timeAbsolute;
-}
-
-void Platform::setAbsoluteTime(long time)
-{
-    __timeAbsolute = time;
-}
-
-bool Platform::isVsync()
-{
-    return __vsync;
-}
-
-void Platform::setVsync(bool enable)
-{
-    eglSwapInterval(__eglDisplay, enable ? 1 : 0);
-    __vsync = enable;
-}
-
-int Platform::getOrientationAngle()
-{
-    return __orientationAngle;
-}
-
-void Platform::setMultiTouch(bool enabled)
-{
-    __multiTouch = enabled;
-}
-
-bool Platform::isMultiTouch()
-{
-    return __multiTouch;
-}
-
-void Platform::getAccelerometerValues(float* pitch, float* roll)
-{
-    double tx, ty, tz;
-	ASensorEvent event;
-	
-	// By default, android accelerometer values are oriented to the portrait mode.
-	// flipping the x and y to get the desired landscape mode values.
-	tx = -__sensorEvent.acceleration.y;
-	ty = __sensorEvent.acceleration.x;
-	tz = -__sensorEvent.acceleration.z;
-	
-	if (pitch != NULL)
-		*pitch = atan(ty / sqrt(tx * tx + tz * tz)) * 180.0f * M_1_PI;
-	if (roll != NULL)
-		*roll = atan(tx / sqrt(ty * ty + tz * tz)) * 180.0f * M_1_PI;
-}
-
-void Platform::swapBuffers()
-{
-    if (__eglDisplay && __eglSurface)
-        eglSwapBuffers(__eglDisplay, __eglSurface);
-}
-
-}
-
-#endif
+#ifdef __ANDROID__
+
+#include "Base.h"
+#include "Platform.h"
+#include "FileSystem.h"
+#include "Game.h"
+#include <unistd.h>
+
+#include <android/sensor.h>
+#include <android_native_app_glue.h>
+
+#include <android/log.h>
+#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
+
+#define TOUCH_COUNT_MAX     4
+
+using namespace std;
+
+struct timespec __timespec;
+static long __timeStart;
+static long __timeAbsolute;
+static bool __vsync = WINDOW_VSYNC;
+
+struct android_app* __state;
+extern std::string __assetsPath;
+int __width;
+int __height;
+static EGLDisplay __eglDisplay = EGL_NO_DISPLAY;
+static EGLContext __eglContext = EGL_NO_CONTEXT;
+static EGLSurface __eglSurface = EGL_NO_SURFACE;
+static EGLConfig __eglConfig = 0;
+ASensorManager* __sensorManager;
+const ASensor* __accelerometerSensor;
+ASensorEventQueue* __sensorEventQueue;
+ASensorEvent __sensorEvent;
+static int __orientationAngle;
+static bool __multiTouch = false;
+
+static const char* __glExtensions;
+PFNGLBINDVERTEXARRAYOESPROC glBindVertexArray = NULL;
+PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays = NULL;
+PFNGLGENVERTEXARRAYSOESPROC glGenVertexArrays = NULL;
+PFNGLISVERTEXARRAYOESPROC glIsVertexArray = NULL;
+
+namespace gameplay
+{
+
+// Gets the Keyboard::Key enumeration constant that corresponds to the given QNX key code.
+Keyboard::Key getKey(int keycode, int metastate)
+{
+    bool shiftOn = (metastate == AMETA_SHIFT_ON);
+    
+    switch(keycode)
+    {
+        case AKEYCODE_HOME:
+            return Keyboard::KEY_HOME;
+        case AKEYCODE_0:
+            return Keyboard::KEY_ZERO;
+        case AKEYCODE_1:
+            return Keyboard::KEY_ONE;
+        case AKEYCODE_2:
+            return Keyboard::KEY_TWO;
+        case AKEYCODE_3:
+            return Keyboard::KEY_THREE;
+        case AKEYCODE_4:
+            return Keyboard::KEY_FOUR;
+        case AKEYCODE_5:
+            return Keyboard::KEY_FIVE;
+        case AKEYCODE_6:
+            return Keyboard::KEY_SIX;
+        case AKEYCODE_7:
+            return Keyboard::KEY_SEVEN;
+        case AKEYCODE_8:
+            return Keyboard::KEY_EIGHT;
+        case AKEYCODE_9:
+            return Keyboard::KEY_NINE;
+        case AKEYCODE_STAR:
+            return Keyboard::KEY_ASTERISK;
+        case AKEYCODE_POUND:
+            return Keyboard::KEY_NUMBER;
+        case AKEYCODE_DPAD_UP:
+            return Keyboard::KEY_UP_ARROW;
+        case AKEYCODE_DPAD_DOWN:
+            return Keyboard::KEY_DOWN_ARROW;
+        case AKEYCODE_DPAD_LEFT:
+            return Keyboard::KEY_LEFT_ARROW;
+        case AKEYCODE_DPAD_RIGHT:
+            return Keyboard::KEY_RIGHT_ARROW;
+        case AKEYCODE_A:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_A : Keyboard::KEY_A;
+        case AKEYCODE_B:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_B : Keyboard::KEY_B;
+       case AKEYCODE_C:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_C : Keyboard::KEY_C;
+        case AKEYCODE_D:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_D : Keyboard::KEY_D;
+        case AKEYCODE_E:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_E : Keyboard::KEY_E;
+        case AKEYCODE_F:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_F : Keyboard::KEY_F;
+        case AKEYCODE_G:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_G : Keyboard::KEY_G;
+        case AKEYCODE_H:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_H : Keyboard::KEY_H;
+        case AKEYCODE_I:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_I : Keyboard::KEY_I;
+        case AKEYCODE_J:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_J : Keyboard::KEY_J;
+        case AKEYCODE_K:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_K : Keyboard::KEY_K;
+        case AKEYCODE_L:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_L : Keyboard::KEY_L;
+        case AKEYCODE_M:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_M : Keyboard::KEY_M;
+        case AKEYCODE_N:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_N : Keyboard::KEY_N;
+        case AKEYCODE_O:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_O : Keyboard::KEY_O;
+        case AKEYCODE_P:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_P : Keyboard::KEY_P;
+        case AKEYCODE_Q:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_Q : Keyboard::KEY_Q;
+        case AKEYCODE_R:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_R : Keyboard::KEY_R;
+        case AKEYCODE_S:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_S : Keyboard::KEY_S;
+        case AKEYCODE_T:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_T : Keyboard::KEY_T;
+        case AKEYCODE_U:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_U : Keyboard::KEY_U;
+        case AKEYCODE_V:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_V : Keyboard::KEY_V;
+        case AKEYCODE_W:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_W : Keyboard::KEY_W;
+        case AKEYCODE_X:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_X : Keyboard::KEY_X;
+        case AKEYCODE_Y:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_Y : Keyboard::KEY_Y;
+        case AKEYCODE_Z:
+            return (shiftOn) ? Keyboard::KEY_CAPITAL_Y : Keyboard::KEY_Y;
+        case AKEYCODE_COMMA:
+            return Keyboard::KEY_COMMA;
+        case AKEYCODE_PERIOD:
+            return Keyboard::KEY_PERIOD;
+        case AKEYCODE_ALT_LEFT:
+            return Keyboard::KEY_LEFT_ALT;
+        case AKEYCODE_ALT_RIGHT:
+            return Keyboard::KEY_RIGHT_ALT;
+        case AKEYCODE_SHIFT_LEFT:
+            return Keyboard::KEY_LEFT_SHIFT;
+        case AKEYCODE_SHIFT_RIGHT:
+            return Keyboard::KEY_RIGHT_SHIFT;
+        case AKEYCODE_TAB:
+            return Keyboard::KEY_TAB;
+        case AKEYCODE_SPACE:
+            return Keyboard::KEY_SPACE;
+        case AKEYCODE_ENTER:
+            return Keyboard::KEY_RETURN;
+        case AKEYCODE_DEL:
+            return Keyboard::KEY_DELETE;
+        case AKEYCODE_GRAVE:
+            return Keyboard::KEY_GRAVE;
+        case AKEYCODE_MINUS:
+            return Keyboard::KEY_MINUS;
+        case AKEYCODE_EQUALS:
+            return Keyboard::KEY_EQUAL;
+        case AKEYCODE_LEFT_BRACKET:
+            return Keyboard::KEY_LEFT_BRACKET;
+        case AKEYCODE_RIGHT_BRACKET:
+            return Keyboard::KEY_RIGHT_BRACKET;
+        case AKEYCODE_BACKSLASH:
+            return Keyboard::KEY_BACK_SLASH;
+        case AKEYCODE_SEMICOLON:
+            return Keyboard::KEY_SEMICOLON;
+        case AKEYCODE_APOSTROPHE:
+            return Keyboard::KEY_APOSTROPHE;
+        case AKEYCODE_SLASH:
+            return Keyboard::KEY_SLASH;
+        case AKEYCODE_AT:
+            return Keyboard::KEY_AT;
+        case AKEYCODE_PLUS:
+            return Keyboard::KEY_PLUS;
+        case AKEYCODE_PAGE_UP:
+            return Keyboard::KEY_PG_UP;
+        case AKEYCODE_PAGE_DOWN:
+            return Keyboard::KEY_PG_DOWN;
+        default:
+            return Keyboard::KEY_NONE;
+    }
+}
+
+
+extern void printError(const char* format, ...)
+{
+    va_list argptr;
+    va_start(argptr, format);
+    LOGI(format, argptr);
+    va_end(argptr);
+}
+
+EGLenum checkErrorEGL(const char* msg)
+{
+    static const char* errmsg[] =
+    {
+        "EGL function succeeded",
+        "EGL is not initialized, or could not be initialized, for the specified display",
+        "EGL cannot access a requested resource",
+        "EGL failed to allocate resources for the requested operation",
+        "EGL fail to access an unrecognized attribute or attribute value was passed in an attribute list",
+        "EGLConfig argument does not name a valid EGLConfig",
+        "EGLContext argument does not name a valid EGLContext",
+        "EGL current surface of the calling thread is no longer valid",
+        "EGLDisplay argument does not name a valid EGLDisplay",
+        "EGL arguments are inconsistent",
+        "EGLNativePixmapType argument does not refer to a valid native pixmap",
+        "EGLNativeWindowType argument does not refer to a valid native window",
+        "EGL one or more argument values are invalid",
+        "EGLSurface argument does not name a valid surface configured for rendering",
+        "EGL power management event has occurred",
+    };
+    EGLenum error = eglGetError();
+    LOGI("%s: %s\n", msg, errmsg[error - EGL_SUCCESS]);
+    return error;
+}
+
+Platform::Platform(Game* game)
+    : _game(game)
+{
+}
+
+Platform::Platform(const Platform& copy)
+{
+    // hidden
+}
+
+Platform::~Platform()
+{
+    if (__eglDisplay != EGL_NO_DISPLAY)
+    {
+        eglMakeCurrent(__eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    }
+
+    if (__eglSurface != EGL_NO_SURFACE)
+    {
+        eglDestroySurface(__eglDisplay, __eglSurface);
+        __eglSurface = EGL_NO_SURFACE;
+    }
+
+    if (__eglContext != EGL_NO_CONTEXT)
+    {
+        eglDestroyContext(__eglDisplay, __eglContext);
+        __eglContext = EGL_NO_CONTEXT;
+    }
+
+    if (__eglDisplay != EGL_NO_DISPLAY)
+    {
+        eglTerminate(__eglDisplay);
+        __eglDisplay = EGL_NO_DISPLAY;
+    }
+}
+
+Platform* Platform::create(Game* game)
+{
+    FileSystem::setResourcePath(__assetsPath.c_str());
+   
+    Platform* platform = new Platform(game);
+
+    // Hard-coded to 32-bit/OpenGL ES 2.0.
+    const EGLint eglConfigAttrs[] =
+    {
+        EGL_RED_SIZE,           8,
+        EGL_GREEN_SIZE,         8,
+        EGL_BLUE_SIZE,          8,
+        EGL_ALPHA_SIZE,         8,
+        EGL_DEPTH_SIZE,         24,
+        EGL_STENCIL_SIZE,       8,
+        EGL_SURFACE_TYPE,       EGL_WINDOW_BIT,
+        EGL_RENDERABLE_TYPE,    EGL_OPENGL_ES2_BIT,
+        EGL_NONE
+    };
+    
+    EGLint eglConfigCount;
+    const EGLint eglContextAttrs[] =
+    {
+        EGL_CONTEXT_CLIENT_VERSION,    2,
+        EGL_NONE
+    };
+
+	const EGLint eglSurfaceAttrs[] =
+    {
+        EGL_RENDER_BUFFER,    EGL_BACK_BUFFER,
+        EGL_NONE
+    };
+
+    // Get the EGL display and initialize.
+    __eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    if (__eglDisplay == EGL_NO_DISPLAY)
+    {
+        checkErrorEGL("eglGetDisplay");
+        goto error;
+    }
+    
+    if (eglInitialize(__eglDisplay, NULL, NULL) != EGL_TRUE)
+    {
+        checkErrorEGL("eglInitialize");
+        goto error;
+    }
+
+    if (eglChooseConfig(__eglDisplay, eglConfigAttrs, &__eglConfig, 1, &eglConfigCount) != EGL_TRUE || eglConfigCount == 0)
+    {
+        checkErrorEGL("eglChooseConfig");
+        goto error;
+    }
+    
+    __eglContext = eglCreateContext(__eglDisplay, __eglConfig, EGL_NO_CONTEXT, eglContextAttrs);
+    if (__eglContext == EGL_NO_CONTEXT)
+    {
+        checkErrorEGL("eglCreateContext");
+        goto error;
+    }
+    
+    // EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
+    // guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
+    // As soon as we picked a EGLConfig, we can safely reconfigure the
+    // ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID.
+    EGLint format;
+    eglGetConfigAttrib(__eglDisplay, __eglConfig, EGL_NATIVE_VISUAL_ID, &format);
+    ANativeWindow_setBuffersGeometry(__state->window, 0, 0, format);
+
+    __eglSurface = eglCreateWindowSurface(__eglDisplay, __eglConfig, __state->window, eglSurfaceAttrs);
+    if (__eglSurface == EGL_NO_SURFACE)
+    {
+        checkErrorEGL("eglCreateWindowSurface");
+        goto error;
+    }
+
+    LOGI("Platform::create - 3");
+    
+    if (eglMakeCurrent(__eglDisplay, __eglSurface, __eglSurface, __eglContext) != EGL_TRUE)
+    {
+        checkErrorEGL("eglMakeCurrent");
+        goto error;
+    }
+
+    eglQuerySurface(__eglDisplay, __eglSurface, EGL_WIDTH, &__width);
+    eglQuerySurface(__eglDisplay, __eglSurface, EGL_HEIGHT, &__height);
+	
+    WARN_VARG("Platform::create - WIDTH: %d HEIGHT = %d" , __width, __height);
+    
+    // Set vsync.
+    eglSwapInterval(__eglDisplay, WINDOW_VSYNC ? 1 : 0);
+
+    // Initialize OpenGL ES extensions.
+    __glExtensions = (const char*)glGetString(GL_EXTENSIONS);
+
+    if (strstr(__glExtensions, "GL_OES_vertex_array_object") || strstr(__glExtensions, "GL_ARB_vertex_array_object"))
+    {
+        WARN("Platform::create - VAOs supported");
+		
+		// Disable VAO extension for now.
+        glBindVertexArray = (PFNGLBINDVERTEXARRAYOESPROC)eglGetProcAddress("glBindVertexArrayOES");
+        glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSOESPROC)eglGetProcAddress("glDeleteVertexArrays");
+        glGenVertexArrays = (PFNGLGENVERTEXARRAYSOESPROC)eglGetProcAddress("glGenVertexArraysOES");
+        glIsVertexArray = (PFNGLISVERTEXARRAYOESPROC)eglGetProcAddress("glIsVertexArrayOES");
+    }
+
+    
+    // TODO: Determine initial orientation angle.
+    //orientation_direction_t direction;
+    //orientation_get(&direction, &__orientationAngle);
+
+    return platform;
+
+error:
+
+    // TODO: cleanup.
+
+    return NULL;
+}
+
+/**
+ * Convert the timespec into milliseconds.
+ */
+long timespec2millis(struct timespec *a)
+{
+    return a->tv_sec*1000 + a->tv_nsec/1000000;
+}
+
+int Platform::enterMessagePump()
+{
+    static int state = 0;
+	
+	switch (state)
+	{
+		case 0:
+			// Get the initial time.
+			clock_gettime(CLOCK_REALTIME, &__timespec);
+			__timeStart = timespec2millis(&__timespec);
+			__timeAbsolute = 0L;
+			WARN_VARG("Platform::enterMessagePump() - WIDTH: %d HEIGHT = %d" , __width, __height);
+			_game->run(__width, __height);
+			
+			state = 1;
+			break;
+		case 1:
+			// Idle time (no events left to process) is spent rendering.
+			// We skip rendering when the app is paused.
+			if (_game->getState() != Game::PAUSED)
+			{
+				_game->frame();
+
+				// Post the new frame to the display.
+				// Note that there are a couple cases where eglSwapBuffers could fail
+				// with an error code that requires a certain level of re-initialization:
+				//
+				// 1) EGL_BAD_NATIVE_WINDOW - Called when the surface we're currently using
+				//    is invalidated. This would require us to destroy our EGL surface,
+				//    close our OpenKODE window, and start again.
+				//
+				// 2) EGL_CONTEXT_LOST - Power management event that led to our EGL context
+				//    being lost. Requires us to re-create and re-initalize our EGL context
+				//    and all OpenGL ES state.
+				//
+				// For now, if we get these, we'll simply exit.
+				int rc = eglSwapBuffers(__eglDisplay, __eglSurface);
+				if (rc != EGL_TRUE)
+				{
+					perror("eglSwapBuffers");
+					_game->exit();
+					break;
+				}
+			}
+			break;
+	}
+    
+    return 0;
+}
+
+long Platform::getAbsoluteTime()
+{
+    clock_gettime(CLOCK_REALTIME, &__timespec);
+    long now = timespec2millis(&__timespec);
+    __timeAbsolute = now - __timeStart;
+
+    return __timeAbsolute;
+}
+
+void Platform::setAbsoluteTime(long time)
+{
+    __timeAbsolute = time;
+}
+
+bool Platform::isVsync()
+{
+    return __vsync;
+}
+
+void Platform::setVsync(bool enable)
+{
+    eglSwapInterval(__eglDisplay, enable ? 1 : 0);
+    __vsync = enable;
+}
+
+int Platform::getOrientationAngle()
+{
+    return __orientationAngle;
+}
+
+void Platform::setMultiTouch(bool enabled)
+{
+    __multiTouch = enabled;
+}
+
+bool Platform::isMultiTouch()
+{
+    return __multiTouch;
+}
+
+void Platform::getAccelerometerValues(float* pitch, float* roll)
+{
+    double tx, ty, tz;
+	ASensorEvent event;
+	
+	// By default, android accelerometer values are oriented to the portrait mode.
+	// flipping the x and y to get the desired landscape mode values.
+	tx = -__sensorEvent.acceleration.y;
+	ty = __sensorEvent.acceleration.x;
+	tz = -__sensorEvent.acceleration.z;
+	
+	if (pitch != NULL)
+		*pitch = atan(ty / sqrt(tx * tx + tz * tz)) * 180.0f * M_1_PI;
+	if (roll != NULL)
+		*roll = atan(tx / sqrt(ty * ty + tz * tz)) * 180.0f * M_1_PI;
+}
+
+void Platform::swapBuffers()
+{
+    if (__eglDisplay && __eglSurface)
+        eglSwapBuffers(__eglDisplay, __eglSurface);
+}
+
+}
+
+#endif

+ 7 - 0
gameplay/src/Transform.cpp

@@ -551,6 +551,7 @@ unsigned int Transform::getAnimationPropertyComponentCount(int propertyId) const
 {
     switch (propertyId)
     {
+        case ANIMATE_SCALE_UNIT:
         case ANIMATE_SCALE_X:
         case ANIMATE_SCALE_Y:
         case ANIMATE_SCALE_Z:
@@ -576,6 +577,9 @@ void Transform::getAnimationPropertyValue(int propertyId, AnimationValue* value)
 {
     switch (propertyId)
     {
+        case ANIMATE_SCALE_UNIT:
+            value->setFloat(0, _scale.x);
+            break;
         case ANIMATE_SCALE:
             value->setFloat(0, _scale.x);
             value->setFloat(1, _scale.y);
@@ -640,6 +644,9 @@ void Transform::setAnimationPropertyValue(int propertyId, AnimationValue* value)
 {
     switch (propertyId)
     {
+        case ANIMATE_SCALE_UNIT:
+            setScale(value->getFloat(0));
+            break;
         case ANIMATE_SCALE:
             setScale(value->getFloat(0), value->getFloat(1), value->getFloat(2));
             break;

+ 5 - 0
gameplay/src/Transform.h

@@ -33,6 +33,11 @@ public:
     /**
      * Scale animation property. Data=sx,sy,sz
      */
+    static const int ANIMATE_SCALE_UNIT = 0;
+
+    /**
+     * Scale animation property. Data=scale
+     */
     static const int ANIMATE_SCALE = 1;
 
     /**

+ 203 - 207
gameplay/src/gameplay-main-android.cpp

@@ -1,207 +1,203 @@
-#ifdef __ANDROID__
-
-#include "gameplay.h"
-#include <android/sensor.h>
-#include <android_native_app_glue.h>
-
-
-#include <android/log.h>
-#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
-
-using namespace gameplay;
-
-extern struct android_app* __state;
-AAssetManager* __assetManager;
-std::string __assetsPath;
-extern ASensorManager* __sensorManager;
-extern const ASensor* __accelerometerSensor;
-extern ASensorEventQueue* __sensorEventQueue;
-extern ASensorEvent __sensorEvent;
-
-//extern gameplay::Keyboard::Key getKey(int keycode, int metastate);
-bool __initialized;
-
-
-/**
- * Process the next input event.
- */
-static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) 
-{
-    Platform* platform = static_cast<Platform*>(app->userData);
-    
-    if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION)
-    {
-        int32_t data = AMotionEvent_getAction(event);
-        int contactIndex = data >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
-        Touch::TouchEvent touchEvent;
-        switch (data & AMOTION_EVENT_ACTION_MASK)
-        {
-            case AMOTION_EVENT_ACTION_DOWN:
-                touchEvent = Touch::TOUCH_PRESS;
-                break;
-            case AMOTION_EVENT_ACTION_UP:
-                touchEvent = Touch::TOUCH_RELEASE;
-                break;
-            case AMOTION_EVENT_ACTION_MOVE:
-                touchEvent = Touch::TOUCH_MOVE;
-                break;
-        }
-    
-        Game::getInstance()->touchEvent(touchEvent, AMotionEvent_getX(event, 0), AMotionEvent_getY(event, 0), contactIndex);
-        return 1;
-    } 
-    else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY)
-    {
-        int32_t action = AKeyEvent_getAction(event);
-		int32_t keycode = AKeyEvent_getKeyCode(event);
-		int32_t metastate = AKeyEvent_getMetaState(event); 
-		
-		WARN_VARG("Key event: action=%d keyCode=%d metaState=0x%x", action, keycode, metastate);
-        
-		switch(action)
-		{
-			case AKEY_EVENT_ACTION_DOWN:
-				//Game::getInstance()->keyEvent(Keyboard::KEY_PRESS, getKey(keycode, metastate));
-				break;
-					
-			case AKEY_EVENT_ACTION_UP:
-				//Game::getInstance()->keyEvent(Keyboard::KEY_RELEASE, getKey(keycode, metastate));
-				break;
-			
-		
-		}
-    }
-    return 0;
-}
-
-/**
- * Process the next main command.
- */
-static void engine_handle_cmd(struct android_app* app, int32_t cmd) 
-{
-    switch (cmd) 
-    {
-        case APP_CMD_SAVE_STATE:
-            WARN("engine_handle_cmd - APP_CMD_SAVE_STATE");
-            // TODO
-            break;
-        case APP_CMD_INIT_WINDOW:
-            WARN("engine_handle_cmd - APP_CMD_INIT_WINDOW");
-			// The window is being shown, get it ready.
-            if (app->window != NULL)
-            {
-                Game* game = Game::getInstance();
-                assert(game != NULL);
-                Platform* platform = Platform::create(game);
-                app->userData = platform;
-				__initialized = true;
-            }
-            break;
-        case APP_CMD_TERM_WINDOW:
-		{
-			WARN("engine_handle_cmd - APP_CMD_TERM_WINDOW");
-            Game::getInstance()->exit();
-			Platform* platform = static_cast<Platform*>(app->userData);
-			if (!platform)
-			{
-				return;
-			}
-			delete platform;
-			app->userData = NULL;
-			break;
-		}
-        case APP_CMD_GAINED_FOCUS:
-            WARN("engine_handle_cmd - APP_CMD_GAINED_FOCUS");
-			// When our app gains focus, we start monitoring the accelerometer.
-            if (__accelerometerSensor != NULL) {
-                ASensorEventQueue_enableSensor(__sensorEventQueue, __accelerometerSensor);
-                // We'd like to get 60 events per second (in us).
-                ASensorEventQueue_setEventRate(__sensorEventQueue, __accelerometerSensor, (1000L/60)*1000);
-            }
-            Game::getInstance()->resume();
-            break;
-        case APP_CMD_LOST_FOCUS:
-            WARN("engine_handle_cmd - APP_CMD_LOST_FOCUS");
-			// When our app loses focus, we stop monitoring the accelerometer.
-            // This is to avoid consuming battery while not being used.
-            if (__accelerometerSensor != NULL) {
-                ASensorEventQueue_disableSensor(__sensorEventQueue, __accelerometerSensor);
-            }
-            Game::getInstance()->pause();
-            ((Platform*)static_cast<Platform*>(app->userData))->swapBuffers();
-            break;
-    }
-}
-
-/**
- * Main entry point.
- */
-void amain(struct android_app* state)
-{
-	ANativeActivity* activity = state->activity;
-	JNIEnv* env = activity->env;
-
-    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;
-    jboolean isCopy;
-    packageName = env->GetStringUTFChars((jstring)result, &isCopy);
-    
-    __assetsPath = "/mnt/sdcard/android/data/";
-    __assetsPath += packageName;
-    __assetsPath += "/";
-    
-    __assetManager = state->activity->assetManager; 
-    
-    state->onAppCmd = engine_handle_cmd;
-    state->onInputEvent = engine_handle_input;
-    __state = state;
-    
-	// Prepare to monitor accelerometer.
-    __sensorManager = ASensorManager_getInstance();
-    __accelerometerSensor = ASensorManager_getDefaultSensor(__sensorManager, ASENSOR_TYPE_ACCELEROMETER);
-    __sensorEventQueue = ASensorManager_createEventQueue(__sensorManager, __state->looper, LOOPER_ID_USER, NULL, NULL);
-	
-	ANativeActivity_showSoftInput(state->activity, ANATIVEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT);
-	
-	
-	__initialized = false;
-	while (true) 
-    {
-		// Read all pending events.
-        int ident;
-        int events;
-        struct android_poll_source* source;
-        
-		bool _shouldPoll = !(__initialized && Game::getInstance()->getState() == Game::UNINITIALIZED) && (Game::getInstance()->getState() != Game::PAUSED); 
-		
-		while ((ident=ALooper_pollAll( _shouldPoll ? 0 : -1, NULL, &events, (void**)&source)) >= 0) 
-        {
-			// Process this event.
-            if (source != NULL) 
-                source->process(__state, source);
-            
-            // If a sensor has data, process it now.
-            if (ident == LOOPER_ID_USER && __accelerometerSensor != NULL)
-                ASensorEventQueue_getEvents(__sensorEventQueue, &__sensorEvent, 1);
-			
-			if (__state->destroyRequested != 0)
-				break;
-        }
-		
-		Platform* platform = static_cast<Platform*>(state->userData);
-		if (platform)
-			platform->enterMessagePump();
-		
-		// Check if we are exiting.
-        if ((__state->destroyRequested != 0) || (__initialized && Game::getInstance()->getState() == Game::UNINITIALIZED))
-            break;        
-    }
-	
-	// We need to exit the process to cleanup global resources.
-	exit(0);
-}
-
-#endif
+#ifdef __ANDROID__
+
+#include "gameplay.h"
+#include <android/sensor.h>
+#include <android_native_app_glue.h>
+
+
+#include <android/log.h>
+#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
+
+using namespace gameplay;
+
+extern struct android_app* __state;
+AAssetManager* __assetManager;
+std::string __assetsPath;
+extern ASensorManager* __sensorManager;
+extern const ASensor* __accelerometerSensor;
+extern ASensorEventQueue* __sensorEventQueue;
+extern ASensorEvent __sensorEvent;
+extern Keyboard::Key getKey(int keycode, int metastate);
+bool __initialized;
+
+/**
+ * Process the next input event.
+ */
+static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) 
+{
+    Platform* platform = static_cast<Platform*>(app->userData);
+    
+    if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION)
+    {
+        int32_t data = AMotionEvent_getAction(event);
+        int contactIndex = data >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+        Touch::TouchEvent touchEvent;
+        switch (data & AMOTION_EVENT_ACTION_MASK)
+        {
+            case AMOTION_EVENT_ACTION_DOWN:
+                touchEvent = Touch::TOUCH_PRESS;
+                break;
+            case AMOTION_EVENT_ACTION_UP:
+                touchEvent = Touch::TOUCH_RELEASE;
+                break;
+            case AMOTION_EVENT_ACTION_MOVE:
+                touchEvent = Touch::TOUCH_MOVE;
+                break;
+        }
+    
+        Game::getInstance()->touchEvent(touchEvent, AMotionEvent_getX(event, 0), AMotionEvent_getY(event, 0), contactIndex);
+        return 1;
+    } 
+    else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY)
+    {
+        int32_t action = AKeyEvent_getAction(event);
+		int32_t keycode = AKeyEvent_getKeyCode(event);
+		int32_t metastate = AKeyEvent_getMetaState(event); 
+		
+		WARN_VARG("Key event: action=%d keyCode=%d metaState=0x%x", action, keycode, metastate);
+        
+		switch(action)
+		{
+			case AKEY_EVENT_ACTION_DOWN:
+				Game::getInstance()->keyEvent(Keyboard::KEY_PRESS, getKey(keycode, metastate));
+				break;
+					
+			case AKEY_EVENT_ACTION_UP:
+				Game::getInstance()->keyEvent(Keyboard::KEY_RELEASE, getKey(keycode, metastate));
+				break;
+		}
+    }
+    return 0;
+}
+
+/**
+ * Process the next main command.
+ */
+static void engine_handle_cmd(struct android_app* app, int32_t cmd) 
+{
+    switch (cmd) 
+    {
+        case APP_CMD_SAVE_STATE:
+            WARN("engine_handle_cmd - APP_CMD_SAVE_STATE");
+            // TODO
+            break;
+        case APP_CMD_INIT_WINDOW:
+            WARN("engine_handle_cmd - APP_CMD_INIT_WINDOW");
+			// The window is being shown, get it ready.
+            if (app->window != NULL)
+            {
+                Game* game = Game::getInstance();
+                assert(game != NULL);
+                Platform* platform = Platform::create(game);
+                app->userData = platform;
+				__initialized = true;
+            }
+            break;
+        case APP_CMD_TERM_WINDOW:
+		{
+			WARN("engine_handle_cmd - APP_CMD_TERM_WINDOW");
+            Game::getInstance()->exit();
+			Platform* platform = static_cast<Platform*>(app->userData);
+			if (!platform)
+			{
+				return;
+			}
+			delete platform;
+			app->userData = NULL;
+			break;
+		}
+        case APP_CMD_GAINED_FOCUS:
+            WARN("engine_handle_cmd - APP_CMD_GAINED_FOCUS");
+			// When our app gains focus, we start monitoring the accelerometer.
+            if (__accelerometerSensor != NULL) {
+                ASensorEventQueue_enableSensor(__sensorEventQueue, __accelerometerSensor);
+                // We'd like to get 60 events per second (in us).
+                ASensorEventQueue_setEventRate(__sensorEventQueue, __accelerometerSensor, (1000L/60)*1000);
+            }
+            Game::getInstance()->resume();
+            break;
+        case APP_CMD_LOST_FOCUS:
+            WARN("engine_handle_cmd - APP_CMD_LOST_FOCUS");
+			// When our app loses focus, we stop monitoring the accelerometer.
+            // This is to avoid consuming battery while not being used.
+            if (__accelerometerSensor != NULL) {
+                ASensorEventQueue_disableSensor(__sensorEventQueue, __accelerometerSensor);
+            }
+            Game::getInstance()->pause();
+            ((Platform*)static_cast<Platform*>(app->userData))->swapBuffers();
+            break;
+    }
+}
+
+/**
+ * Main entry point.
+ */
+void amain(struct android_app* state)
+{
+	ANativeActivity* activity = state->activity;
+	JNIEnv* env = activity->env;
+
+    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;
+    jboolean isCopy;
+    packageName = env->GetStringUTFChars((jstring)result, &isCopy);
+    
+    __assetsPath = "/mnt/sdcard/android/data/";
+    __assetsPath += packageName;
+    __assetsPath += "/";
+    
+    __assetManager = state->activity->assetManager; 
+    
+    state->onAppCmd = engine_handle_cmd;
+    state->onInputEvent = engine_handle_input;
+    __state = state;
+    
+	// Prepare to monitor accelerometer.
+    __sensorManager = ASensorManager_getInstance();
+    __accelerometerSensor = ASensorManager_getDefaultSensor(__sensorManager, ASENSOR_TYPE_ACCELEROMETER);
+    __sensorEventQueue = ASensorManager_createEventQueue(__sensorManager, __state->looper, LOOPER_ID_USER, NULL, NULL);
+	
+	ANativeActivity_showSoftInput(state->activity, ANATIVEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT);
+	
+	
+	__initialized = false;
+	while (true) 
+    {
+		// Read all pending events.
+        int ident;
+        int events;
+        struct android_poll_source* source;
+        
+		bool _shouldPoll = !(__initialized && Game::getInstance()->getState() == Game::UNINITIALIZED) && (Game::getInstance()->getState() != Game::PAUSED); 
+		
+		while ((ident=ALooper_pollAll( _shouldPoll ? 0 : -1, NULL, &events, (void**)&source)) >= 0) 
+        {
+			// Process this event.
+            if (source != NULL) 
+                source->process(__state, source);
+            
+            // If a sensor has data, process it now.
+            if (ident == LOOPER_ID_USER && __accelerometerSensor != NULL)
+                ASensorEventQueue_getEvents(__sensorEventQueue, &__sensorEvent, 1);
+			
+			if (__state->destroyRequested != 0)
+				break;
+        }
+		
+		Platform* platform = static_cast<Platform*>(state->userData);
+		if (platform)
+			platform->enterMessagePump();
+		
+		// Check if we are exiting.
+        if ((__state->destroyRequested != 0) || (__initialized && Game::getInstance()->getState() == Game::UNINITIALIZED))
+            break;        
+    }
+	
+	// We need to exit the process to cleanup global resources.
+	exit(0);
+}
+
+#endif