FrameBuffer.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  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. static FrameBufferHandle __defaultHandle = 0;
  11. FrameBuffer::FrameBuffer(const char* id, unsigned int width, unsigned int height) :
  12. _id(id ? id : ""), _width(width), _height(height), _handle(0),
  13. _renderTargets(NULL), _depthStencilTarget(NULL)
  14. {
  15. }
  16. FrameBuffer::~FrameBuffer()
  17. {
  18. if (_renderTargets)
  19. {
  20. for (unsigned int i = 0; i < __maxRenderTargets; ++i)
  21. {
  22. if (_renderTargets[i])
  23. {
  24. SAFE_RELEASE(_renderTargets[i]);
  25. }
  26. }
  27. SAFE_DELETE_ARRAY(_renderTargets);
  28. }
  29. if (_depthStencilTarget)
  30. {
  31. SAFE_RELEASE(_depthStencilTarget);
  32. }
  33. // Release GL resource.
  34. if (_handle)
  35. {
  36. GL_ASSERT( glDeleteFramebuffers(1, &_handle) );
  37. }
  38. // Remove self from vector.
  39. std::vector<FrameBuffer*>::iterator it = std::find(__frameBuffers.begin(), __frameBuffers.end(), this);
  40. if (it != __frameBuffers.end())
  41. {
  42. __frameBuffers.erase(it);
  43. }
  44. }
  45. void FrameBuffer::initialize()
  46. {
  47. GLint fbo;
  48. glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);
  49. __defaultHandle = (FrameBufferHandle)fbo;
  50. }
  51. FrameBuffer* FrameBuffer::create(const char* id, unsigned int width, unsigned int height)
  52. {
  53. if (!isPowerOfTwo(width) | !isPowerOfTwo(height))
  54. {
  55. GP_ERROR("Failed to create render target for frame buffer. Width and Height must be a power of 2.");
  56. return NULL;
  57. }
  58. // Call getMaxRenderTargets() to force __maxRenderTargets to be set
  59. getMaxRenderTargets();
  60. // Create RenderTarget with same ID.
  61. RenderTarget* renderTarget = NULL;
  62. renderTarget = RenderTarget::create(id, width, height);
  63. if (renderTarget == NULL)
  64. {
  65. GP_ERROR("Failed to create render target for frame buffer.");
  66. return NULL;
  67. }
  68. // Create the frame buffer
  69. GLuint handle = 0;
  70. GL_ASSERT( glGenFramebuffers(1, &handle) );
  71. FrameBuffer* frameBuffer = new FrameBuffer(id, width, height);
  72. frameBuffer->_handle = handle;
  73. // Create the render target array for the new frame buffer
  74. RenderTarget** renderTargets = new RenderTarget*[__maxRenderTargets];
  75. memset(renderTargets, 0, sizeof(RenderTarget*) * __maxRenderTargets);
  76. frameBuffer->_renderTargets = renderTargets;
  77. frameBuffer->setRenderTarget(renderTarget, 0);
  78. SAFE_RELEASE(renderTarget);
  79. __frameBuffers.push_back(frameBuffer);
  80. return frameBuffer;
  81. }
  82. FrameBuffer* FrameBuffer::getFrameBuffer(const char* id)
  83. {
  84. GP_ASSERT(id);
  85. // Search the vector for a matching ID.
  86. std::vector<FrameBuffer*>::const_iterator it;
  87. for (it = __frameBuffers.begin(); it < __frameBuffers.end(); it++)
  88. {
  89. FrameBuffer* fb = *it;
  90. GP_ASSERT(fb);
  91. if (strcmp(id, fb->getId()) == 0)
  92. {
  93. return fb;
  94. }
  95. }
  96. return NULL;
  97. }
  98. const char* FrameBuffer::getId() const
  99. {
  100. return _id.c_str();
  101. }
  102. unsigned int FrameBuffer::getWidth() const
  103. {
  104. return _width;
  105. }
  106. unsigned int FrameBuffer::getHeight() const
  107. {
  108. return _height;
  109. }
  110. unsigned int FrameBuffer::getMaxRenderTargets()
  111. {
  112. if (__maxRenderTargets == 0)
  113. {
  114. #ifdef GL_MAX_COLOR_ATTACHMENTS
  115. GLint val;
  116. GL_ASSERT( glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &val) );
  117. __maxRenderTargets = (unsigned int) val;
  118. #else
  119. __maxRenderTargets = 1;
  120. #endif
  121. }
  122. return __maxRenderTargets;
  123. }
  124. void FrameBuffer::setRenderTarget(RenderTarget* target, unsigned int index)
  125. {
  126. GP_ASSERT(index < __maxRenderTargets);
  127. GP_ASSERT(_renderTargets);
  128. if (_renderTargets[index] == target)
  129. {
  130. // No change.
  131. return;
  132. }
  133. // Release our reference to the current RenderTarget at this index.
  134. SAFE_RELEASE(_renderTargets[index]);
  135. _renderTargets[index] = target;
  136. if (target)
  137. {
  138. // This FrameBuffer now references the RenderTarget.
  139. target->addRef();
  140. // Store the current FBO binding so we can restore it
  141. GLint currentFbo;
  142. GL_ASSERT( glGetIntegerv(GL_FRAMEBUFFER_BINDING, &currentFbo) );
  143. // Now set this target as the color attachment corresponding to index.
  144. GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, _handle) );
  145. GL_ASSERT( glBindTexture(GL_TEXTURE_2D, _renderTargets[index]->getTexture()->getHandle()) );
  146. GL_ASSERT( glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) );
  147. GL_ASSERT( glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) );
  148. GL_ASSERT( glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) );
  149. GL_ASSERT( glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) );
  150. GL_ASSERT( glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _width, _height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL) );
  151. GLenum attachment = GL_COLOR_ATTACHMENT0 + index;
  152. GP_ASSERT( _renderTargets[index]->getTexture() );
  153. GL_ASSERT( glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, _renderTargets[index]->getTexture()->getHandle(), 0) );
  154. GLenum fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
  155. if (fboStatus != GL_FRAMEBUFFER_COMPLETE)
  156. {
  157. GP_ERROR("Framebuffer status incompleted: 0x%x", fboStatus);
  158. }
  159. // Restore the FBO binding
  160. GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, currentFbo) );
  161. }
  162. }
  163. RenderTarget* FrameBuffer::getRenderTarget(unsigned int index) const
  164. {
  165. GP_ASSERT(_renderTargets);
  166. if (index < __maxRenderTargets)
  167. {
  168. return _renderTargets[index];
  169. }
  170. return NULL;
  171. }
  172. void FrameBuffer::setDepthStencilTarget(DepthStencilTarget* target)
  173. {
  174. if (_depthStencilTarget == target)
  175. return;
  176. // Release our existing depth stencil target.
  177. SAFE_RELEASE(_depthStencilTarget);
  178. _depthStencilTarget = target;
  179. if (target)
  180. {
  181. // The FrameBuffer now owns this DepthStencilTarget.
  182. target->addRef();
  183. // Store the current FBO binding so we can restore it.
  184. GLint currentFbo;
  185. GL_ASSERT( glGetIntegerv(GL_FRAMEBUFFER_BINDING, &currentFbo) );
  186. // Now set this target as the color attachment corresponding to index.
  187. GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, _handle) );
  188. // Create a render buffer
  189. RenderBufferHandle renderBuffer = 0;
  190. GL_ASSERT( glGenRenderbuffers(1, &renderBuffer) );
  191. GL_ASSERT( glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer) );
  192. GL_ASSERT( glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, _width, _height) );
  193. GL_ASSERT( glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderBuffer) );
  194. // Attach the
  195. if (target->getFormat() == DepthStencilTarget::DEPTH_STENCIL)
  196. {
  197. GL_ASSERT( glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderBuffer) );
  198. }
  199. // Check the framebuffer is good to go.
  200. GLenum fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
  201. if (fboStatus != GL_FRAMEBUFFER_COMPLETE)
  202. {
  203. GP_ERROR("Framebuffer status incompleted: 0x%x", fboStatus);
  204. }
  205. _depthStencilTarget->_renderBuffer = renderBuffer;
  206. // Restore the FBO binding
  207. GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, currentFbo) );
  208. }
  209. }
  210. DepthStencilTarget* FrameBuffer::getDepthStencilTarget() const
  211. {
  212. return _depthStencilTarget;
  213. }
  214. void FrameBuffer::bind()
  215. {
  216. // Bind this FrameBuffer for rendering.
  217. GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, _handle) );
  218. }
  219. void FrameBuffer::bindDefault()
  220. {
  221. GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, __defaultHandle) );
  222. }
  223. bool FrameBuffer::isPowerOfTwo(unsigned int value)
  224. {
  225. return (value != 0) && ((value & (value - 1)) == 0);
  226. }
  227. }