FrameBuffer.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /**
  2. * FrameBuffer.cpp
  3. */
  4. #include "Base.h"
  5. #include "FrameBuffer.h"
  6. namespace gameplay
  7. {
  8. static unsigned int __maxRenderTargets = 0;
  9. static std::vector<FrameBuffer*> __frameBuffers;
  10. FrameBuffer::FrameBuffer(const char* id) :
  11. _id(id ? id : ""), _handle(0), _renderTargets(NULL), _depthStencilTarget(NULL)
  12. {
  13. }
  14. FrameBuffer::~FrameBuffer()
  15. {
  16. if (_renderTargets)
  17. {
  18. for (unsigned int i = 0; i < __maxRenderTargets; ++i)
  19. {
  20. SAFE_RELEASE(_renderTargets[i]);
  21. }
  22. SAFE_DELETE_ARRAY(_renderTargets);
  23. }
  24. // Release GL resource.
  25. if (_handle)
  26. {
  27. GL_ASSERT( glDeleteFramebuffers(1, &_handle) );
  28. }
  29. // Remove self from vector.
  30. std::vector<FrameBuffer*>::iterator it = std::find(__frameBuffers.begin(), __frameBuffers.end(), this);
  31. if (it != __frameBuffers.end())
  32. {
  33. __frameBuffers.erase(it);
  34. }
  35. }
  36. FrameBuffer* FrameBuffer::create(const char* id)
  37. {
  38. // Create GL FBO resource.
  39. GLuint handle = 0;
  40. GL_ASSERT( glGenFramebuffers(1, &handle) );
  41. // Call getMaxRenderTargets() to force __maxRenderTargets to be set
  42. getMaxRenderTargets();
  43. // Create the render target array for the new frame buffer
  44. RenderTarget** renderTargets = new RenderTarget*[__maxRenderTargets];
  45. memset(renderTargets, 0, sizeof(RenderTarget*) * __maxRenderTargets);
  46. // Create the new frame buffer
  47. FrameBuffer* frameBuffer = new FrameBuffer(id);
  48. frameBuffer->_handle = handle;
  49. frameBuffer->_renderTargets = renderTargets;
  50. // Add to the global list of managed frame buffers
  51. __frameBuffers.push_back(frameBuffer);
  52. return frameBuffer;
  53. }
  54. FrameBuffer* FrameBuffer::create(const char* id, unsigned int width, unsigned int height)
  55. {
  56. // Create RenderTarget with same ID.
  57. RenderTarget* renderTarget = RenderTarget::create(id, width, height);
  58. if (renderTarget == NULL)
  59. {
  60. GP_ERROR("Failed to create render target for frame buffer.");
  61. return NULL;
  62. }
  63. // Create the frame buffer.
  64. FrameBuffer* frameBuffer = create(id);
  65. if (frameBuffer == NULL)
  66. {
  67. GP_ERROR("Failed to create frame buffer.");
  68. return NULL;
  69. }
  70. // Add the render target as the first color attachment.
  71. frameBuffer->setRenderTarget(renderTarget);
  72. SAFE_RELEASE(renderTarget);
  73. return frameBuffer;
  74. }
  75. FrameBuffer* FrameBuffer::getFrameBuffer(const char* id)
  76. {
  77. GP_ASSERT(id);
  78. // Search the vector for a matching ID.
  79. std::vector<FrameBuffer*>::const_iterator it;
  80. for (it = __frameBuffers.begin(); it < __frameBuffers.end(); it++)
  81. {
  82. FrameBuffer* fb = *it;
  83. GP_ASSERT(fb);
  84. if (strcmp(id, fb->getID()) == 0)
  85. {
  86. return fb;
  87. }
  88. }
  89. return NULL;
  90. }
  91. const char* FrameBuffer::getID() const
  92. {
  93. return _id.c_str();
  94. }
  95. unsigned int FrameBuffer::getMaxRenderTargets()
  96. {
  97. if (__maxRenderTargets == 0)
  98. {
  99. #ifdef GL_MAX_COLOR_ATTACHMENTS
  100. GLint val;
  101. GL_ASSERT( glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &val) );
  102. __maxRenderTargets = (unsigned int) val;
  103. #else
  104. __maxRenderTargets = 1;
  105. #endif
  106. }
  107. return __maxRenderTargets;
  108. }
  109. void FrameBuffer::setRenderTarget(RenderTarget* target, unsigned int index)
  110. {
  111. GP_ASSERT(index < __maxRenderTargets);
  112. GP_ASSERT(_renderTargets);
  113. if (_renderTargets[index] == target)
  114. {
  115. // No change.
  116. return;
  117. }
  118. // Release our reference to the current RenderTarget at this index.
  119. SAFE_RELEASE(_renderTargets[index]);
  120. _renderTargets[index] = target;
  121. if (target)
  122. {
  123. // This FrameBuffer now references the RenderTarget.
  124. target->addRef();
  125. // Store the current FBO binding so we can restore it
  126. GLint currentFbo;
  127. GL_ASSERT( glGetIntegerv(GL_FRAMEBUFFER_BINDING, &currentFbo) );
  128. // Now set this target as the color attachment corresponding to index.
  129. GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, _handle) );
  130. GLenum attachment = GL_COLOR_ATTACHMENT0 + index;
  131. GP_ASSERT(_renderTargets[index]->getTexture());
  132. GL_ASSERT( glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, _renderTargets[index]->getTexture()->getHandle(), 0) );
  133. // Restore the FBO binding
  134. GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, currentFbo) );
  135. }
  136. }
  137. RenderTarget* FrameBuffer::getRenderTarget(unsigned int index) const
  138. {
  139. GP_ASSERT(_renderTargets);
  140. if (index < __maxRenderTargets)
  141. {
  142. return _renderTargets[index];
  143. }
  144. return NULL;
  145. }
  146. void FrameBuffer::setDepthStencilTarget(DepthStencilTarget* target)
  147. {
  148. if (_depthStencilTarget == target)
  149. {
  150. return; // No change
  151. }
  152. // Release our existing depth stencil target.
  153. SAFE_RELEASE(_depthStencilTarget);
  154. _depthStencilTarget = target;
  155. if (target)
  156. {
  157. // The FrameBuffer now owns this DepthStencilTarget.
  158. target->addRef();
  159. // Store the current FBO binding so we can restore it.
  160. GLint currentFbo;
  161. GL_ASSERT( glGetIntegerv(GL_FRAMEBUFFER_BINDING, &currentFbo) );
  162. // Now set this target as the color attachment corresponding to index.
  163. GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, _handle) );
  164. // Bind the depth texture.
  165. GP_ASSERT(_depthStencilTarget);
  166. GP_ASSERT(_depthStencilTarget->getTexture());
  167. GL_ASSERT( glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _depthStencilTarget->getTexture()->getHandle(), 0) );
  168. // If the taget has a stencil buffer, bind that as well
  169. if (target->getFormat() == DepthStencilTarget::DEPTH24_STENCIL8)
  170. {
  171. GL_ASSERT( glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _depthStencilTarget->_stencilBuffer) );
  172. }
  173. // Restore the FBO binding
  174. GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, currentFbo) );
  175. }
  176. }
  177. DepthStencilTarget* FrameBuffer::getDepthStencilTarget() const
  178. {
  179. return _depthStencilTarget;
  180. }
  181. void FrameBuffer::bind()
  182. {
  183. // Bind this FrameBuffer for rendering.
  184. GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, _handle) );
  185. }
  186. void FrameBuffer::bindDefault()
  187. {
  188. GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, 0) );
  189. }
  190. }