فهرست منبع

Merge pull request #1310 from seanpaultaylor/next

Fixed bug related to FrameBuffer width/height goes out of date.
Sean Taylor 12 سال پیش
والد
کامیت
18f94bcf97
3فایلهای تغییر یافته به همراه668 افزوده شده و 674 حذف شده
  1. 304 308
      gameplay/src/FrameBuffer.cpp
  2. 223 225
      gameplay/src/FrameBuffer.h
  3. 141 141
      samples/browser/res/common/light.form

+ 304 - 308
gameplay/src/FrameBuffer.cpp

@@ -1,308 +1,304 @@
-#include "Base.h"
-#include "FrameBuffer.h"
-#include "Game.h"
-
-#define FRAMEBUFFER_ID_DEFAULT "org.gameplay3d.framebuffer.default"
-
-namespace gameplay
-{
-
-unsigned int FrameBuffer::_maxRenderTargets = 0;
-std::vector<FrameBuffer*> FrameBuffer::_frameBuffers;
-FrameBuffer* FrameBuffer::_defaultFrameBuffer = NULL;
-FrameBuffer* FrameBuffer::_currentFrameBuffer = NULL;
-
-FrameBuffer::FrameBuffer(const char* id, unsigned int width, unsigned int height, FrameBufferHandle handle) :
-    _id(id ? id : ""), _width(width), _height(height), _handle(handle), 
-    _renderTargets(NULL), _renderTargetCount(0), _depthStencilTarget(NULL)
-{
-}
-
-FrameBuffer::~FrameBuffer()
-{
-    if (_renderTargets)
-    {
-        for (unsigned int i = 0; i < _maxRenderTargets; ++i)
-        {
-            if (_renderTargets[i])
-            {
-                SAFE_RELEASE(_renderTargets[i]);
-            }
-        }
-        SAFE_DELETE_ARRAY(_renderTargets);
-    }
-    if (_depthStencilTarget)
-    {
-        SAFE_RELEASE(_depthStencilTarget);
-    }
-
-    // Release GL resource.
-    if (_handle)
-    {
-        GL_ASSERT( glDeleteFramebuffers(1, &_handle) );
-    }
-
-    // Remove self from vector.
-    std::vector<FrameBuffer*>::iterator it = std::find(_frameBuffers.begin(), _frameBuffers.end(), this);
-    if (it != _frameBuffers.end())
-    {
-        _frameBuffers.erase(it);
-    }
-}
-
-void FrameBuffer::initialize()
-{
-    // Query the current/initial FBO handle and store is as out 'default' frame buffer.
-    // On many platforms this will simply be the zero (0) handle, but this is not always the case.
-    GLint fbo;
-    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);
-    _defaultFrameBuffer = new FrameBuffer(FRAMEBUFFER_ID_DEFAULT, 0, 0, (FrameBufferHandle)fbo);
-    _currentFrameBuffer = _defaultFrameBuffer;
-
-    // Query the max supported color attachments. This glGet operation is not supported
-    // on GL ES 2.x, so if the define does not exist, assume a value of 1.
-#ifdef GL_MAX_COLOR_ATTACHMENTS
-        GLint val;
-        GL_ASSERT( glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &val) );
-        _maxRenderTargets = (unsigned int)std::max(1, val);
-#else
-        _maxRenderTargets = 1;
-#endif
-}
-
-void FrameBuffer::finalize()
-{
-    SAFE_RELEASE(_defaultFrameBuffer);
-}
-
-FrameBuffer* FrameBuffer::create(const char* id)
-{
-    return create(id, 0, 0);
-}
-
-FrameBuffer* FrameBuffer::create(const char* id, unsigned int width, unsigned int height)
-{
-    RenderTarget* renderTarget = NULL;
-    if (width > 0 && height > 0)
-    {
-        // Create a default RenderTarget with same ID.
-        renderTarget = RenderTarget::create(id, width, height);
-        if (renderTarget == NULL)
-        {
-            GP_ERROR("Failed to create render target for frame buffer.");
-            return NULL;
-        }
-    }
-
-    // Create the frame buffer
-    GLuint handle = 0;
-    GL_ASSERT( glGenFramebuffers(1, &handle) );
-    FrameBuffer* frameBuffer = new FrameBuffer(id, width, height, handle);
-    
-    // Create the render target array for the new frame buffer
-    frameBuffer->_renderTargets = new RenderTarget*[_maxRenderTargets];
-    memset(frameBuffer->_renderTargets, 0, sizeof(RenderTarget*) * _maxRenderTargets);
-
-    if (renderTarget)
-    {
-        frameBuffer->setRenderTarget(renderTarget, 0);
-        SAFE_RELEASE(renderTarget);
-    }
-
-    _frameBuffers.push_back(frameBuffer);
-
-    return frameBuffer;
-}
-
-FrameBuffer* FrameBuffer::getFrameBuffer(const char* id)
-{
-    GP_ASSERT(id);
-
-    // Search the vector for a matching ID.
-    std::vector<FrameBuffer*>::const_iterator it;
-    for (it = _frameBuffers.begin(); it < _frameBuffers.end(); ++it)
-    {
-        FrameBuffer* fb = *it;
-        GP_ASSERT(fb);
-        if (strcmp(id, fb->getId()) == 0)
-        {
-            return fb;
-        }
-    }
-    return NULL;
-}
-
-const char* FrameBuffer::getId() const
-{
-    return _id.c_str();
-}
-
-unsigned int FrameBuffer::getWidth() const
-{
-    return _width;
-}
-
-unsigned int FrameBuffer::getHeight() const
-{
-    return _height;
-}
-
-unsigned int FrameBuffer::getMaxRenderTargets()
-{
-    return _maxRenderTargets;
-}
-
-void FrameBuffer::setRenderTarget(RenderTarget* target, unsigned int index)
-{
-    GP_ASSERT(index < _maxRenderTargets);
-    GP_ASSERT(_renderTargets);
-
-    // No change
-    if (_renderTargets[index] == target)
-        return;
-
-    // Release our reference to the current RenderTarget at this index.
-    if (_renderTargets[index])
-    {
-        SAFE_RELEASE(_renderTargets[index]);
-        --_renderTargetCount;
-    }
-
-    _renderTargets[index] = target;
-
-    if (target)
-    {
-        GP_ASSERT( _renderTargets[index]->getTexture() );
-
-        ++_renderTargetCount;
-
-        // This FrameBuffer now references the RenderTarget.
-        target->addRef();
-
-        // Now set this target as the color attachment corresponding to index.
-        GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, _handle) );
-        GLenum attachment = GL_COLOR_ATTACHMENT0 + index;
-        GL_ASSERT( glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, _renderTargets[index]->getTexture()->getHandle(), 0) );
-        GLenum fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
-        if (fboStatus != GL_FRAMEBUFFER_COMPLETE)
-        {
-            GP_ERROR("Framebuffer status incomplete: 0x%x", fboStatus);
-        }
-
-        // Restore the FBO binding
-        GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, _currentFrameBuffer->_handle) );
-    }
-
-}
-
-RenderTarget* FrameBuffer::getRenderTarget(unsigned int index) const
-{
-    GP_ASSERT(_renderTargets);
-    if (index < _maxRenderTargets)
-    {
-        return _renderTargets[index];
-    }
-    return NULL;
-}
-
-unsigned int FrameBuffer::getRenderTargetCount() const
-{
-    return _renderTargetCount;
-}
-
-void FrameBuffer::setDepthStencilTarget(DepthStencilTarget* target)
-{
-    if (_depthStencilTarget == target)
-        return;
-
-    // Release our existing depth stencil target.
-    SAFE_RELEASE(_depthStencilTarget);
-
-    _depthStencilTarget = target;
-
-    if (target)
-    {
-        // The FrameBuffer now owns this DepthStencilTarget.
-        target->addRef();
-
-        // Now set this target as the color attachment corresponding to index.
-        GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, _handle) );
-
-        // Attach the render buffer to the framebuffer
-        GL_ASSERT( glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthStencilTarget->_depthBuffer) );
-        if (target->isPacked())
-        {
-            GL_ASSERT( glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _depthStencilTarget->_depthBuffer) );
-        }
-        else if (target->getFormat() == DepthStencilTarget::DEPTH_STENCIL)
-        {
-            GL_ASSERT( glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _depthStencilTarget->_stencilBuffer) );
-        }
-
-        // Check the framebuffer is good to go.
-        GLenum fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
-        if (fboStatus != GL_FRAMEBUFFER_COMPLETE)
-        {
-            GP_ERROR("Framebuffer status incomplete: 0x%x", fboStatus);
-        }
-
-        // Restore the FBO binding
-        GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, _currentFrameBuffer->_handle) );
-    }
-}
-
-DepthStencilTarget* FrameBuffer::getDepthStencilTarget() const
-{
-    return _depthStencilTarget;
-}
-
-bool FrameBuffer::isDefault() const
-{
-    return (this == _defaultFrameBuffer);
-}
-
-FrameBuffer* FrameBuffer::bind()
-{
-    GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, _handle) );
-    FrameBuffer* previousFrameBuffer = _currentFrameBuffer;
-    _currentFrameBuffer = this;
-    return previousFrameBuffer;
-}
-
-void FrameBuffer::getScreenshot(Image* image)
-{
-	//While possible to have a non-static getScreenshot function, it would require the expensive operation 
-	//of binding the FrameBuffer, reading the pixels, then rebinding the original FrameBuffer. This is faster.(
-
-	GP_ASSERT(image);
-	GP_ASSERT(image->getFormat() == Image::RGBA);
-
-	unsigned int width = _currentFrameBuffer->getWidth();
-	unsigned int height = _currentFrameBuffer->getHeight();
-
-	if (image->getWidth() == width && image->getHeight() == height)
-		GL_ASSERT( glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, image->getData()) );
-}
-
-Image* FrameBuffer::createScreenshot()
-{
-	Image* screenshot = Image::create(_currentFrameBuffer->getWidth(), _currentFrameBuffer->getHeight(), Image::RGBA, NULL);
-
-	getScreenshot(screenshot);
-
-	return screenshot;
-}
-
-FrameBuffer* FrameBuffer::bindDefault()
-{
-    GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, _defaultFrameBuffer->_handle) );
-    _currentFrameBuffer = _defaultFrameBuffer;
-    return _defaultFrameBuffer;
-}
-
-FrameBuffer* FrameBuffer::getCurrent()
-{
-    return _currentFrameBuffer;
-}
-
-}
+#include "Base.h"
+#include "FrameBuffer.h"
+#include "Game.h"
+
+#define FRAMEBUFFER_ID_DEFAULT "org.gameplay3d.framebuffer.default"
+
+namespace gameplay
+{
+
+unsigned int FrameBuffer::_maxRenderTargets = 0;
+std::vector<FrameBuffer*> FrameBuffer::_frameBuffers;
+FrameBuffer* FrameBuffer::_defaultFrameBuffer = NULL;
+FrameBuffer* FrameBuffer::_currentFrameBuffer = NULL;
+
+FrameBuffer::FrameBuffer(const char* id, unsigned int width, unsigned int height, FrameBufferHandle handle) 
+    : _id(id ? id : ""), _handle(handle), _renderTargets(NULL), _renderTargetCount(0), _depthStencilTarget(NULL)
+{
+}
+
+FrameBuffer::~FrameBuffer()
+{
+    if (_renderTargets)
+    {
+        for (unsigned int i = 0; i < _maxRenderTargets; ++i)
+        {
+            if (_renderTargets[i])
+            {
+                SAFE_RELEASE(_renderTargets[i]);
+            }
+        }
+        SAFE_DELETE_ARRAY(_renderTargets);
+    }
+
+    if (_depthStencilTarget)
+        SAFE_RELEASE(_depthStencilTarget);
+
+    // Release GL resource.
+    if (_handle)
+        GL_ASSERT( glDeleteFramebuffers(1, &_handle) );
+
+    // Remove self from vector.
+    std::vector<FrameBuffer*>::iterator it = std::find(_frameBuffers.begin(), _frameBuffers.end(), this);
+    if (it != _frameBuffers.end())
+    {
+        _frameBuffers.erase(it);
+    }
+}
+
+void FrameBuffer::initialize()
+{
+    // Query the current/initial FBO handle and store is as out 'default' frame buffer.
+    // On many platforms this will simply be the zero (0) handle, but this is not always the case.
+    GLint fbo;
+    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);
+    _defaultFrameBuffer = new FrameBuffer(FRAMEBUFFER_ID_DEFAULT, 0, 0, (FrameBufferHandle)fbo);
+    _currentFrameBuffer = _defaultFrameBuffer;
+
+    // Query the max supported color attachments. This glGet operation is not supported
+    // on GL ES 2.x, so if the define does not exist, assume a value of 1.
+#ifdef GL_MAX_COLOR_ATTACHMENTS
+        GLint val;
+        GL_ASSERT( glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &val) );
+        _maxRenderTargets = (unsigned int)std::max(1, val);
+#else
+        _maxRenderTargets = 1;
+#endif
+}
+
+void FrameBuffer::finalize()
+{
+    SAFE_RELEASE(_defaultFrameBuffer);
+}
+
+FrameBuffer* FrameBuffer::create(const char* id)
+{
+    return create(id, 0, 0);
+}
+
+FrameBuffer* FrameBuffer::create(const char* id, unsigned int width, unsigned int height)
+{
+    RenderTarget* renderTarget = NULL;
+    if (width > 0 && height > 0)
+    {
+        // Create a default RenderTarget with same ID.
+        renderTarget = RenderTarget::create(id, width, height);
+        if (renderTarget == NULL)
+        {
+            GP_ERROR("Failed to create render target for frame buffer.");
+            return NULL;
+        }
+    }
+
+    // Create the frame buffer
+    GLuint handle = 0;
+    GL_ASSERT( glGenFramebuffers(1, &handle) );
+    FrameBuffer* frameBuffer = new FrameBuffer(id, width, height, handle);
+    
+    // Create the render target array for the new frame buffer
+    frameBuffer->_renderTargets = new RenderTarget*[_maxRenderTargets];
+    memset(frameBuffer->_renderTargets, 0, sizeof(RenderTarget*) * _maxRenderTargets);
+
+    if (renderTarget)
+    {
+        frameBuffer->setRenderTarget(renderTarget, 0);
+        SAFE_RELEASE(renderTarget);
+    }
+    _frameBuffers.push_back(frameBuffer);
+
+    return frameBuffer;
+}
+
+FrameBuffer* FrameBuffer::getFrameBuffer(const char* id)
+{
+    GP_ASSERT(id);
+
+    // Search the vector for a matching ID.
+    std::vector<FrameBuffer*>::const_iterator it;
+    for (it = _frameBuffers.begin(); it < _frameBuffers.end(); ++it)
+    {
+        FrameBuffer* fb = *it;
+        GP_ASSERT(fb);
+        if (strcmp(id, fb->getId()) == 0)
+        {
+            return fb;
+        }
+    }
+    return NULL;
+}
+
+const char* FrameBuffer::getId() const
+{
+    return _id.c_str();
+}
+
+unsigned int FrameBuffer::getWidth() const
+{
+    if (_renderTargetCount > 0 && _renderTargets != NULL && _renderTargets[0] != NULL)
+        return _renderTargets[0]->getWidth();
+
+    return 0;
+}
+
+unsigned int FrameBuffer::getHeight() const
+{
+    if (_renderTargetCount > 0 && _renderTargets != NULL && _renderTargets[0] != NULL)
+        return _renderTargets[0]->getHeight();
+
+    return 0;
+}
+
+unsigned int FrameBuffer::getMaxRenderTargets()
+{
+    return _maxRenderTargets;
+}
+
+void FrameBuffer::setRenderTarget(RenderTarget* target, unsigned int index)
+{
+    GP_ASSERT(index < _maxRenderTargets);
+    GP_ASSERT(_renderTargets);
+
+    // No change
+    if (_renderTargets[index] == target)
+        return;
+
+    // Release our reference to the current RenderTarget at this index.
+    if (_renderTargets[index])
+    {
+        SAFE_RELEASE(_renderTargets[index]);
+        --_renderTargetCount;
+    }
+
+    _renderTargets[index] = target;
+
+    if (target)
+    {
+        GP_ASSERT( _renderTargets[index]->getTexture() );
+
+        ++_renderTargetCount;
+
+        // This FrameBuffer now references the RenderTarget.
+        target->addRef();
+
+        // Now set this target as the color attachment corresponding to index.
+        GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, _handle) );
+        GLenum attachment = GL_COLOR_ATTACHMENT0 + index;
+        GL_ASSERT( glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, _renderTargets[index]->getTexture()->getHandle(), 0) );
+        GLenum fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+        if (fboStatus != GL_FRAMEBUFFER_COMPLETE)
+        {
+            GP_ERROR("Framebuffer status incomplete: 0x%x", fboStatus);
+        }
+
+        // Restore the FBO binding
+        GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, _currentFrameBuffer->_handle) );
+    }
+}
+
+RenderTarget* FrameBuffer::getRenderTarget(unsigned int index) const
+{
+    GP_ASSERT(_renderTargets);
+    if (index < _maxRenderTargets)
+    {
+        return _renderTargets[index];
+    }
+    return NULL;
+}
+
+unsigned int FrameBuffer::getRenderTargetCount() const
+{
+    return _renderTargetCount;
+}
+
+void FrameBuffer::setDepthStencilTarget(DepthStencilTarget* target)
+{
+    if (_depthStencilTarget == target)
+        return;
+
+    // Release our existing depth stencil target.
+    SAFE_RELEASE(_depthStencilTarget);
+
+    _depthStencilTarget = target;
+
+    if (target)
+    {
+        // The FrameBuffer now owns this DepthStencilTarget.
+        target->addRef();
+
+        // Now set this target as the color attachment corresponding to index.
+        GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, _handle) );
+
+        // Attach the render buffer to the framebuffer
+        GL_ASSERT( glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthStencilTarget->_depthBuffer) );
+        if (target->isPacked())
+        {
+            GL_ASSERT( glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _depthStencilTarget->_depthBuffer) );
+        }
+        else if (target->getFormat() == DepthStencilTarget::DEPTH_STENCIL)
+        {
+            GL_ASSERT( glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _depthStencilTarget->_stencilBuffer) );
+        }
+
+        // Check the framebuffer is good to go.
+        GLenum fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+        if (fboStatus != GL_FRAMEBUFFER_COMPLETE)
+        {
+            GP_ERROR("Framebuffer status incomplete: 0x%x", fboStatus);
+        }
+
+        // Restore the FBO binding
+        GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, _currentFrameBuffer->_handle) );
+    }
+}
+
+DepthStencilTarget* FrameBuffer::getDepthStencilTarget() const
+{
+    return _depthStencilTarget;
+}
+
+bool FrameBuffer::isDefault() const
+{
+    return (this == _defaultFrameBuffer);
+}
+
+FrameBuffer* FrameBuffer::bind()
+{
+    GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, _handle) );
+    FrameBuffer* previousFrameBuffer = _currentFrameBuffer;
+    _currentFrameBuffer = this;
+    return previousFrameBuffer;
+}
+
+void FrameBuffer::getScreenshot(Image* image)
+{
+	GP_ASSERT(image);
+	GP_ASSERT(image->getFormat() == Image::RGBA);
+
+	unsigned int width = _currentFrameBuffer->getWidth();
+	unsigned int height = _currentFrameBuffer->getHeight();
+
+	if (image->getWidth() == width && image->getHeight() == height)
+		GL_ASSERT( glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, image->getData()) );
+}
+
+Image* FrameBuffer::createScreenshot()
+{
+	Image* screenshot = Image::create(_currentFrameBuffer->getWidth(), _currentFrameBuffer->getHeight(), Image::RGBA, NULL);
+	getScreenshot(screenshot);
+
+	return screenshot;
+}
+
+FrameBuffer* FrameBuffer::bindDefault()
+{
+    GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, _defaultFrameBuffer->_handle) );
+    _currentFrameBuffer = _defaultFrameBuffer;
+    return _defaultFrameBuffer;
+}
+
+FrameBuffer* FrameBuffer::getCurrent()
+{
+    return _currentFrameBuffer;
+}
+
+}

+ 223 - 225
gameplay/src/FrameBuffer.h

@@ -1,225 +1,223 @@
-#ifndef FRAMEBUFFER_H_
-#define FRAMEBUFFER_H_
-
-#include "Base.h"
-#include "RenderTarget.h"
-#include "DepthStencilTarget.h"
-#include "Image.h"
-
-namespace gameplay
-{
-
-/**
- * Defines a frame buffer object that may contain one or more render targets and optionally
- * a depth-stencil target.
- *
- * Frame buffers can be created and used for off-screen rendering, which is useful for
- * techniques such as shadow mapping and post-processing. Render targets within a frame
- * buffer can be both written to and read (by calling RenderTarget::getTexture).
- *
- * When binding a custom frame buffer, you should always store the return value of
- * FrameBuffer::bind and restore it when you are finished drawing to your frame buffer.
- *
- * To bind the default frame buffer, call FrameBuffer::bindDefault.
- */
-class FrameBuffer : public Ref
-{
-    friend class Game;
-
-public:
-
-    /**
-     * Creates a new, empty FrameBuffer object.
-     *
-     * The new FrameBuffer does not have any render targets or a depth/stencil target and these
-     * must be added before it can be used. The FrameBuffer is added to the list of available
-     * FrameBuffers.
-     *
-     * @param id The ID of the new FrameBuffer. Uniqueness is recommended but not enforced.
-     *
-     * @return A newly created FrameBuffer.
-     * @script{create}
-     */
-    static FrameBuffer* create(const char* id);
-
-    /**
-     * Creates a new FrameBuffer with a single RenderTarget of the specified width and height,
-     * and adds the FrameBuffer to the list of available FrameBuffers.
-     *
-     * If width and height are non-zero a default RenderTarget of type RGBA will be created
-     * and added to the FrameBuffer, with the same ID. The ID of the render target can be
-     * changed later via RenderTarget::setId(const char*).
-     *
-     * You can additionally add a DepthStencilTarget using FrameBuffer::setDepthStencilTarget.
-     *
-     * @param id The ID of the new FrameBuffer. Uniqueness is recommended but not enforced.
-     * @param width The width of the RenderTarget to be created and attached.
-     * @param height The height of the RenderTarget to be created and attached.
-     *
-     * @return A newly created FrameBuffer.
-     * @script{create}
-     */
-    static FrameBuffer* create(const char* id, unsigned int width, unsigned int height);
-
-    /**
-     * Get a named FrameBuffer from its ID.
-     *
-     * @param id The ID of the FrameBuffer to search for.
-     *
-     * @return The FrameBuffer with the specified ID, or NULL if one was not found.
-     */
-    static FrameBuffer* getFrameBuffer(const char* id);
-
-    /**
-     * Get the ID of this FrameBuffer.
-     *
-     * @return The ID of this FrameBuffer.
-     */
-    const char* getId() const;
-
-    /**
-     * Gets the width of the frame buffer.
-     *
-     * @return The width of the frame buffer.
-     */
-    unsigned int getWidth() const;
-
-    /**
-     * Gets the height of the frame buffer.
-     *
-     * @return The height of the frame buffer.
-     */
-    unsigned int getHeight() const;
-
-    /**
-     * Get the number of color attachments available on the current hardware.
-     *
-     * @return The number of color attachments available on the current hardware.
-     */
-    static unsigned int getMaxRenderTargets();
-
-    /**
-     * Set a RenderTarget on this FrameBuffer's color attachment at the specified index.
-     *
-     * @param target The RenderTarget to set.
-     * @param index The index of the color attachment to set.
-     */
-    void setRenderTarget(RenderTarget* target, unsigned int index = 0);
-
-    /**
-     * Get the RenderTarget attached to the FrameBuffer's color attachment at the specified index.
-     *
-     * @param index The index of the color attachment to retrieve a RenderTarget from.
-     *
-     * @return The RenderTarget attached at the specified index.
-     */
-    RenderTarget* getRenderTarget(unsigned int index = 0) const;
-
-    /**
-     * Returns the current number of render targets attached to this frame buffer.
-     *
-     * @return The number of render targets attached.
-     */
-    unsigned int getRenderTargetCount() const;
-
-    /**
-     * Set this FrameBuffer's DepthStencilTarget.
-     *
-     * @param target The DepthStencilTarget to set on this FrameBuffer.
-     */
-    void setDepthStencilTarget(DepthStencilTarget* target);
-
-    /**
-     * Get this FrameBuffer's DepthStencilTarget.
-     *
-     * @return This FrameBuffer's DepthStencilTarget.
-     */
-    DepthStencilTarget* getDepthStencilTarget() const;
-
-    /**
-     * Determines whether this is the default frame buffer.
-     *
-     * @return true if this is the default frame buffer, false otherwise.
-     */
-    bool isDefault() const;
-
-    /**
-     * Binds this FrameBuffer for off-screen rendering and return you the currently bound one.
-     *
-     * You should keep the return FrameBuffer and store it and call bind() when you rendering is complete.
-     *
-     * @ return The currently bound framebuffer.
-     */
-    FrameBuffer* bind();
-
-	/**
-	 * Records a screenshot of what is stored on the current FrameBuffer.
-	 *
-	 * @return A screenshot of the current framebuffer's content.
-	 */
-	static Image* createScreenshot();
-
-	/**
-	 * Records a screenshot of what is stored on the current FrameBuffer to an Image.
-	 *
-	 * The Image must be the same size as the FrameBuffer, otherwise the operation will fail.
-	 * The Image must be format RGBA.
-	 *
-	 * @param image The Image to write the current framebuffer's content to.
-	 */
-	static void getScreenshot(Image* image);
-
-    /**
-     * Binds the default FrameBuffer for rendering to the display.
-     *
-     * @ return The default framebuffer.
-     */
-    static FrameBuffer* bindDefault();
-
-    /**
-     * Gets the currently bound FrameBuffer.
-     *
-     * @return The currently bound FrameBuffer.
-     */
-    static FrameBuffer* getCurrent();
-
-private:
-
-    /**
-     * Constructor.
-     */
-    FrameBuffer(const char* id, unsigned int width, unsigned int height, FrameBufferHandle handle);
-
-    /**
-     * Destructor.
-     */
-    ~FrameBuffer();
-
-    /**
-     * Hidden copy assignment operator.
-     */
-    FrameBuffer& operator=(const FrameBuffer&);
-
-    static void initialize();
-
-    static void finalize();
-
-    static bool isPowerOfTwo(unsigned int value);
-
-    std::string _id;
-    unsigned int _width;
-    unsigned int _height;
-    FrameBufferHandle _handle;
-    RenderTarget** _renderTargets;
-    unsigned int _renderTargetCount;
-    DepthStencilTarget* _depthStencilTarget;
-
-    static unsigned int _maxRenderTargets;
-    static std::vector<FrameBuffer*> _frameBuffers;
-    static FrameBuffer* _defaultFrameBuffer;
-    static FrameBuffer* _currentFrameBuffer;
-};
-
-}
-
-#endif
+#ifndef FRAMEBUFFER_H_
+#define FRAMEBUFFER_H_
+
+#include "Base.h"
+#include "RenderTarget.h"
+#include "DepthStencilTarget.h"
+#include "Image.h"
+
+namespace gameplay
+{
+
+/**
+ * Defines a frame buffer object that may contain one or more render targets and optionally
+ * a depth-stencil target.
+ *
+ * Frame buffers can be created and used for off-screen rendering, which is useful for
+ * techniques such as shadow mapping and post-processing. Render targets within a frame
+ * buffer can be both written to and read (by calling RenderTarget::getTexture).
+ *
+ * When binding a custom frame buffer, you should always store the return value of
+ * FrameBuffer::bind and restore it when you are finished drawing to your frame buffer.
+ *
+ * To bind the default frame buffer, call FrameBuffer::bindDefault.
+ */
+class FrameBuffer : public Ref
+{
+    friend class Game;
+
+public:
+
+    /**
+     * Creates a new, empty FrameBuffer object.
+     *
+     * The new FrameBuffer does not have any render targets or a depth/stencil target and these
+     * must be added before it can be used. The FrameBuffer is added to the list of available
+     * FrameBuffers.
+     *
+     * @param id The ID of the new FrameBuffer. Uniqueness is recommended but not enforced.
+     *
+     * @return A newly created FrameBuffer.
+     * @script{create}
+     */
+    static FrameBuffer* create(const char* id);
+
+    /**
+     * Creates a new FrameBuffer with a single RenderTarget of the specified width and height,
+     * and adds the FrameBuffer to the list of available FrameBuffers.
+     *
+     * If width and height are non-zero a default RenderTarget of type RGBA will be created
+     * and added to the FrameBuffer, with the same ID. The ID of the render target can be
+     * changed later via RenderTarget::setId(const char*).
+     *
+     * You can additionally add a DepthStencilTarget using FrameBuffer::setDepthStencilTarget.
+     *
+     * @param id The ID of the new FrameBuffer. Uniqueness is recommended but not enforced.
+     * @param width The width of the RenderTarget to be created and attached.
+     * @param height The height of the RenderTarget to be created and attached.
+     *
+     * @return A newly created FrameBuffer.
+     * @script{create}
+     */
+    static FrameBuffer* create(const char* id, unsigned int width, unsigned int height);
+
+    /**
+     * Get a named FrameBuffer from its ID.
+     *
+     * @param id The ID of the FrameBuffer to search for.
+     *
+     * @return The FrameBuffer with the specified ID, or NULL if one was not found.
+     */
+    static FrameBuffer* getFrameBuffer(const char* id);
+
+    /**
+     * Get the ID of this FrameBuffer.
+     *
+     * @return The ID of this FrameBuffer.
+     */
+    const char* getId() const;
+
+    /**
+     * Gets the width of the frame buffer.
+     *
+     * @return The width of the frame buffer.
+     */
+    unsigned int getWidth() const;
+
+    /**
+     * Gets the height of the frame buffer.
+     *
+     * @return The height of the frame buffer.
+     */
+    unsigned int getHeight() const;
+
+    /**
+     * Get the number of color attachments available on the current hardware.
+     *
+     * @return The number of color attachments available on the current hardware.
+     */
+    static unsigned int getMaxRenderTargets();
+
+    /**
+     * Set a RenderTarget on this FrameBuffer's color attachment at the specified index.
+     *
+     * @param target The RenderTarget to set.
+     * @param index The index of the color attachment to set.
+     */
+    void setRenderTarget(RenderTarget* target, unsigned int index = 0);
+
+    /**
+     * Get the RenderTarget attached to the FrameBuffer's color attachment at the specified index.
+     *
+     * @param index The index of the color attachment to retrieve a RenderTarget from.
+     *
+     * @return The RenderTarget attached at the specified index.
+     */
+    RenderTarget* getRenderTarget(unsigned int index = 0) const;
+
+    /**
+     * Returns the current number of render targets attached to this frame buffer.
+     *
+     * @return The number of render targets attached.
+     */
+    unsigned int getRenderTargetCount() const;
+
+    /**
+     * Set this FrameBuffer's DepthStencilTarget.
+     *
+     * @param target The DepthStencilTarget to set on this FrameBuffer.
+     */
+    void setDepthStencilTarget(DepthStencilTarget* target);
+
+    /**
+     * Get this FrameBuffer's DepthStencilTarget.
+     *
+     * @return This FrameBuffer's DepthStencilTarget.
+     */
+    DepthStencilTarget* getDepthStencilTarget() const;
+
+    /**
+     * Determines whether this is the default frame buffer.
+     *
+     * @return true if this is the default frame buffer, false otherwise.
+     */
+    bool isDefault() const;
+
+    /**
+     * Binds this FrameBuffer for off-screen rendering and return you the currently bound one.
+     *
+     * You should keep the return FrameBuffer and store it and call bind() when you rendering is complete.
+     *
+     * @ return The currently bound framebuffer.
+     */
+    FrameBuffer* bind();
+
+	/**
+	 * Records a screenshot of what is stored on the current FrameBuffer.
+	 *
+	 * @return A screenshot of the current framebuffer's content.
+	 */
+	static Image* createScreenshot();
+
+	/**
+	 * Records a screenshot of what is stored on the current FrameBuffer to an Image.
+	 *
+	 * The Image must be the same size as the FrameBuffer, otherwise the operation will fail.
+	 * The Image must be format RGBA.
+	 *
+	 * @param image The Image to write the current framebuffer's content to.
+	 */
+	static void getScreenshot(Image* image);
+
+    /**
+     * Binds the default FrameBuffer for rendering to the display.
+     *
+     * @ return The default framebuffer.
+     */
+    static FrameBuffer* bindDefault();
+
+    /**
+     * Gets the currently bound FrameBuffer.
+     *
+     * @return The currently bound FrameBuffer.
+     */
+    static FrameBuffer* getCurrent();
+
+private:
+
+    /**
+     * Constructor.
+     */
+    FrameBuffer(const char* id, unsigned int width, unsigned int height, FrameBufferHandle handle);
+
+    /**
+     * Destructor.
+     */
+    ~FrameBuffer();
+
+    /**
+     * Hidden copy assignment operator.
+     */
+    FrameBuffer& operator=(const FrameBuffer&);
+
+    static void initialize();
+
+    static void finalize();
+
+    static bool isPowerOfTwo(unsigned int value);
+
+    std::string _id;
+    FrameBufferHandle _handle;
+    RenderTarget** _renderTargets;
+    unsigned int _renderTargetCount;
+    DepthStencilTarget* _depthStencilTarget;
+
+    static unsigned int _maxRenderTargets;
+    static std::vector<FrameBuffer*> _frameBuffers;
+    static FrameBuffer* _defaultFrameBuffer;
+    static FrameBuffer* _currentFrameBuffer;
+};
+
+}
+
+#endif

+ 141 - 141
samples/browser/res/common/light.form

@@ -1,142 +1,142 @@
-form formLightSelect
-{
-    theme = res/common/default.theme
-    layout = LAYOUT_ABSOLUTE
-    style = noBorder
-    alignment = ALIGN_TOP_LEFT
-    autoWidth = AUTO_SIZE_FIT
-    autoHeight = AUTO_SIZE_FIT
-
-	container lightingType
-    {
-		style = basic
-        layout = LAYOUT_VERTICAL
-        position = 0, 20
-        size = 230, 210
-		
-        label
-        {
-            style = iconNoBorder
-            size = 210, 20
-            textAlignment = ALIGN_TOP_HCENTER
-            text = Type
-        }
-        
-		radioButton noLighting
-		{
-			style = iconNoBorder
-			imageSize = 35, 35
-			size = 200, 40
-			text = No Light
-			value = true
-		}
-
-	    radioButton directional
-		{
-			style = iconNoBorder
-			imageSize = 35, 35
-			size = 200, 40
-			text = Directional Light
-			value = false
-		}
-
-		radioButton spot
-		{
-			style = iconNoBorder
-			imageSize = 35, 35
-			size = 200, 40
-			text = Spot Light
-			value = false
-		}
-
-		radioButton point
-		{
-			style = iconNoBorder
-			imageSize = 35, 35
-			size = 200, 40
-			text = Point Light
-			value = false
-		}
-	}
-
-	container lightProperties
-    {
-		style = basic
-        layout = LAYOUT_VERTICAL
-        position = 0, 230
-        size = 230, 380
-    
-        label
-        {
-            style = iconNoBorder
-            size = 210, 20
-            textAlignment = ALIGN_TOP_HCENTER
-            text = Properties
-        }
-        
-		slider redSlider
-		{
-			style = iconNoBorder
-			size = 210, 60
-			orientation = HORIZONTAL
-            textAlignment = ALIGN_LEFT
-			min = 0
-			max = 1
-			value = 1.0
-			text = Red
-		}
-	
-		slider greenSlider
-		{
-			style = iconNoBorder
-			size = 210, 60
-			orientation = HORIZONTAL
-            textAlignment = ALIGN_LEFT
-			min = 0
-			max = 1
-			value = 1.0
-			text = Green
-		}
-
-		slider blueSlider
-		{
-			style = iconNoBorder
-			size = 210, 60
-			orientation = HORIZONTAL
-            textAlignment = ALIGN_LEFT
-			min = 0
-			max = 1
-			value = 1.0
-			text = Blue
-		}
-
-		slider specularSlider
-		{
-			style = iconNoBorder
-			size = 210, 60
-			orientation = HORIZONTAL
-            textAlignment = ALIGN_LEFT
-			min = 1
-			max = 500
-			value = 1
-			text = Specular
-		}
-		checkbox specularCheckBox
-		{
-			style = iconNoBorder
-			imageSize = 35, 35
-			size = 200, 40
-			text = Enable Specular
-			value = false
-		}
-
-		checkbox bumpedCheckBox
-		{
-			style = iconNoBorder
-			imageSize = 35, 35
-			size = 200, 40
-			text = Enable BumpMapping
-			value = false
-		}
-	}
+form formLightSelect
+{
+    theme = res/common/default.theme
+    layout = LAYOUT_ABSOLUTE
+    style = noBorder
+    alignment = ALIGN_TOP_LEFT
+    autoWidth = AUTO_SIZE_FIT
+    autoHeight = AUTO_SIZE_FIT
+
+	container lightingType
+    {
+		style = basic
+        layout = LAYOUT_VERTICAL
+        position = 0, 20
+        size = 230, 210
+		
+        label
+        {
+            style = iconNoBorder
+            size = 210, 20
+            textAlignment = ALIGN_TOP_HCENTER
+            text = Type
+        }
+        
+		radioButton noLighting
+		{
+			style = iconNoBorder
+			imageSize = 35, 35
+			size = 200, 40
+			text = No Light
+			value = true
+		}
+
+	    radioButton directional
+		{
+			style = iconNoBorder
+			imageSize = 35, 35
+			size = 200, 40
+			text = Directional Light
+			value = false
+		}
+
+		radioButton spot
+		{
+			style = iconNoBorder
+			imageSize = 35, 35
+			size = 200, 40
+			text = Spot Light
+			value = false
+		}
+
+		radioButton point
+		{
+			style = iconNoBorder
+			imageSize = 35, 35
+			size = 200, 40
+			text = Point Light
+			value = false
+		}
+	}
+
+	container lightProperties
+    {
+		style = basic
+        layout = LAYOUT_VERTICAL
+        position = 0, 230
+        size = 230, 380
+    
+        label
+        {
+            style = iconNoBorder
+            size = 210, 20
+            textAlignment = ALIGN_TOP_HCENTER
+            text = Properties
+        }
+        
+		slider redSlider
+		{
+			style = iconNoBorder
+			size = 210, 60
+			orientation = HORIZONTAL
+            textAlignment = ALIGN_LEFT
+			min = 0
+			max = 1
+			value = 1.0
+			text = Red
+		}
+	
+		slider greenSlider
+		{
+			style = iconNoBorder
+			size = 210, 60
+			orientation = HORIZONTAL
+            textAlignment = ALIGN_LEFT
+			min = 0
+			max = 1
+			value = 1.0
+			text = Green
+		}
+
+		slider blueSlider
+		{
+			style = iconNoBorder
+			size = 210, 60
+			orientation = HORIZONTAL
+            textAlignment = ALIGN_LEFT
+			min = 0
+			max = 1
+			value = 1.0
+			text = Blue
+		}
+
+		slider specularSlider
+		{
+			style = iconNoBorder
+			size = 210, 60
+			orientation = HORIZONTAL
+            textAlignment = ALIGN_LEFT
+			min = 1
+			max = 256
+			value = 64
+			text = Specular
+		}
+		checkbox specularCheckBox
+		{
+			style = iconNoBorder
+			imageSize = 35, 35
+			size = 200, 40
+			text = Enable Specular
+			value = false
+		}
+
+		checkbox bumpedCheckBox
+		{
+			style = iconNoBorder
+			imageSize = 35, 35
+			size = 200, 40
+			text = Enable BumpMapping
+			value = false
+		}
+	}
 }
 }