Переглянути джерело

Merge pull request #508 from blackberry-gaming/next-setaylor

Next setaylor
Sean Paul Taylor 13 роки тому
батько
коміт
912b9b50a9

+ 5 - 2
gameplay/src/Effect.cpp

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

+ 122 - 109
gameplay/src/Form.cpp

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

+ 12 - 31
gameplay/src/Form.h

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

+ 4 - 1
gameplay/src/FrameBuffer.cpp

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

+ 1 - 1
gameplay/src/SpriteBatch.cpp

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