FrameBuffer.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /**
  2. * FrameBuffer.cpp
  3. */
  4. #include "Base.h"
  5. #include "FrameBuffer.h"
  6. #include "Game.h"
  7. #define FRAMEBUFFER_ID_DEFAULT "org.gameplay3d.framebuffer.default"
  8. namespace gameplay
  9. {
  10. static unsigned int __maxRenderTargets = 0;
  11. static std::vector<FrameBuffer*> __frameBuffers;
  12. static FrameBuffer* __defaultFrameBuffer = NULL;
  13. static FrameBuffer* __currentFrameBuffer = NULL;
  14. FrameBuffer::FrameBuffer(const char* id, unsigned int width, unsigned int height, FrameBufferHandle handle) :
  15. _id(id ? id : ""), _width(width), _height(height), _handle(handle),
  16. _renderTargets(NULL), _depthStencilTarget(NULL)
  17. {
  18. }
  19. FrameBuffer::~FrameBuffer()
  20. {
  21. if (_renderTargets)
  22. {
  23. for (unsigned int i = 0; i < __maxRenderTargets; ++i)
  24. {
  25. if (_renderTargets[i])
  26. {
  27. SAFE_RELEASE(_renderTargets[i]);
  28. }
  29. }
  30. SAFE_DELETE_ARRAY(_renderTargets);
  31. }
  32. if (_depthStencilTarget)
  33. {
  34. SAFE_RELEASE(_depthStencilTarget);
  35. }
  36. // Release GL resource.
  37. if (_handle)
  38. {
  39. GL_ASSERT( glDeleteFramebuffers(1, &_handle) );
  40. }
  41. // Remove self from vector.
  42. std::vector<FrameBuffer*>::iterator it = std::find(__frameBuffers.begin(), __frameBuffers.end(), this);
  43. if (it != __frameBuffers.end())
  44. {
  45. __frameBuffers.erase(it);
  46. }
  47. }
  48. void FrameBuffer::initialize()
  49. {
  50. // Query the current/initial FBO handle and store is as out 'default' frame buffer.
  51. // On many platforms this will simply be the zero (0) handle, but this is not always the case.
  52. GLint fbo;
  53. glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);
  54. __defaultFrameBuffer = new FrameBuffer(FRAMEBUFFER_ID_DEFAULT, 0, 0, (FrameBufferHandle)fbo);
  55. __currentFrameBuffer = __defaultFrameBuffer;
  56. // Query the max supported color attachments. This glGet operation is not supported
  57. // on GL ES 2.x, so if the define does not exist, assume a value of 1.
  58. #ifdef GL_MAX_COLOR_ATTACHMENTS
  59. GLint val;
  60. GL_ASSERT( glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &val) );
  61. __maxRenderTargets = (unsigned int)std::max(1, val);
  62. #else
  63. __maxRenderTargets = 1;
  64. #endif
  65. }
  66. FrameBuffer* FrameBuffer::create(const char* id)
  67. {
  68. return create(id, 0, 0);
  69. }
  70. FrameBuffer* FrameBuffer::create(const char* id, unsigned int width, unsigned int height)
  71. {
  72. // Call getMaxRenderTargets() to force __maxRenderTargets to be set
  73. getMaxRenderTargets();
  74. RenderTarget* renderTarget = NULL;
  75. if (width > 0 && height > 0)
  76. {
  77. // Create a default RenderTarget with same ID.
  78. renderTarget = RenderTarget::create(id, width, height);
  79. if (renderTarget == NULL)
  80. {
  81. GP_ERROR("Failed to create render target for frame buffer.");
  82. return NULL;
  83. }
  84. }
  85. // Create the frame buffer
  86. GLuint handle = 0;
  87. GL_ASSERT( glGenFramebuffers(1, &handle) );
  88. FrameBuffer* frameBuffer = new FrameBuffer(id, width, height, handle);
  89. // Create the render target array for the new frame buffer
  90. frameBuffer->_renderTargets = new RenderTarget*[__maxRenderTargets];
  91. memset(frameBuffer->_renderTargets, 0, sizeof(RenderTarget*) * __maxRenderTargets);
  92. if (renderTarget)
  93. {
  94. frameBuffer->setRenderTarget(renderTarget, 0);
  95. SAFE_RELEASE(renderTarget);
  96. }
  97. __frameBuffers.push_back(frameBuffer);
  98. return frameBuffer;
  99. }
  100. FrameBuffer* FrameBuffer::getFrameBuffer(const char* id)
  101. {
  102. GP_ASSERT(id);
  103. // Search the vector for a matching ID.
  104. std::vector<FrameBuffer*>::const_iterator it;
  105. for (it = __frameBuffers.begin(); it < __frameBuffers.end(); ++it)
  106. {
  107. FrameBuffer* fb = *it;
  108. GP_ASSERT(fb);
  109. if (strcmp(id, fb->getId()) == 0)
  110. {
  111. return fb;
  112. }
  113. }
  114. return NULL;
  115. }
  116. const char* FrameBuffer::getId() const
  117. {
  118. return _id.c_str();
  119. }
  120. unsigned int FrameBuffer::getWidth() const
  121. {
  122. return _width;
  123. }
  124. unsigned int FrameBuffer::getHeight() const
  125. {
  126. return _height;
  127. }
  128. unsigned int FrameBuffer::getMaxRenderTargets()
  129. {
  130. return __maxRenderTargets;
  131. }
  132. void FrameBuffer::setRenderTarget(RenderTarget* target, unsigned int index)
  133. {
  134. GP_ASSERT(index < __maxRenderTargets);
  135. GP_ASSERT(_renderTargets);
  136. // No change
  137. if (_renderTargets[index] == target)
  138. return;
  139. // Release our reference to the current RenderTarget at this index.
  140. SAFE_RELEASE(_renderTargets[index]);
  141. _renderTargets[index] = target;
  142. if (target)
  143. {
  144. GP_ASSERT( _renderTargets[index]->getTexture() );
  145. // This FrameBuffer now references the RenderTarget.
  146. target->addRef();
  147. // Now set this target as the color attachment corresponding to index.
  148. GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, _handle) );
  149. GLenum attachment = GL_COLOR_ATTACHMENT0 + index;
  150. GL_ASSERT( glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, _renderTargets[index]->getTexture()->getHandle(), 0) );
  151. GLenum fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
  152. if (fboStatus != GL_FRAMEBUFFER_COMPLETE)
  153. {
  154. GP_ERROR("Framebuffer status incomplete: 0x%x", fboStatus);
  155. }
  156. // Restore the FBO binding
  157. GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, __currentFrameBuffer->_handle) );
  158. }
  159. }
  160. RenderTarget* FrameBuffer::getRenderTarget(unsigned int index) const
  161. {
  162. GP_ASSERT(_renderTargets);
  163. if (index < __maxRenderTargets)
  164. {
  165. return _renderTargets[index];
  166. }
  167. return NULL;
  168. }
  169. void FrameBuffer::setDepthStencilTarget(DepthStencilTarget* target)
  170. {
  171. if (_depthStencilTarget == target)
  172. return;
  173. // Release our existing depth stencil target.
  174. SAFE_RELEASE(_depthStencilTarget);
  175. _depthStencilTarget = target;
  176. if (target)
  177. {
  178. // The FrameBuffer now owns this DepthStencilTarget.
  179. target->addRef();
  180. // Now set this target as the color attachment corresponding to index.
  181. GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, _handle) );
  182. // Attach the render buffer to the framebuffer
  183. GL_ASSERT( glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthStencilTarget->_renderBuffer) );
  184. if (target->getFormat() == DepthStencilTarget::DEPTH_STENCIL)
  185. {
  186. GL_ASSERT( glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _depthStencilTarget->_renderBuffer) );
  187. }
  188. // Check the framebuffer is good to go.
  189. GLenum fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
  190. if (fboStatus != GL_FRAMEBUFFER_COMPLETE)
  191. {
  192. GP_ERROR("Framebuffer status incomplete: 0x%x", fboStatus);
  193. }
  194. // Restore the FBO binding
  195. GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, __currentFrameBuffer->_handle) );
  196. }
  197. }
  198. DepthStencilTarget* FrameBuffer::getDepthStencilTarget() const
  199. {
  200. return _depthStencilTarget;
  201. }
  202. FrameBuffer* FrameBuffer::bind()
  203. {
  204. GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, _handle) );
  205. FrameBuffer* previousFrameBuffer = __currentFrameBuffer;
  206. __currentFrameBuffer = this;
  207. return previousFrameBuffer;
  208. }
  209. FrameBuffer* FrameBuffer::bindDefault()
  210. {
  211. GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, __defaultFrameBuffer->_handle) );
  212. __currentFrameBuffer = __defaultFrameBuffer;
  213. return __defaultFrameBuffer;
  214. }
  215. }