#include "FrameBufferObject.h" #include "glInterface.h" #include #ifdef _CRT_SET #define _CRTDBG_MAP_ALLOC #include #include // redefine new operator #define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) #define new DEBUG_NEW #endif using namespace std; namespace CHCDemoEngine { int FrameBufferObject::sCurrentFbo = -1; void PrintFBOStatus(GLenum status) { switch(status) { case GL_FRAMEBUFFER_COMPLETE_EXT: //cout << "frame buffer object complete" << endl; break; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: cerr << "incomplete attachment" << endl; break; case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: cerr << "missing attachment" << endl; break; case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: cerr << "incomplete dimensions" << endl; break; case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: cerr << "incomplete formats" << endl; break; case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: cerr << "incomplete draw buffer" << endl; break; case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: cerr << "incomplete read buffer" << endl; break; case GL_FRAMEBUFFER_UNSUPPORTED_EXT: cerr << "framebuffer unsupported" << endl; break; default: cerr << "unknown status code " << status << endl; } } ColorBufferObject::ColorBufferObject(int w, int h, int attachment_idx, FORMAT format, WRAP_TYPE wrapType, FILTER_TYPE filterType, FILTER_TYPE filterTypeMipMap ) { Init(w, h, attachment_idx, format, wrapType, filterType, true, filterTypeMipMap); } ColorBufferObject::ColorBufferObject(int w, int h, int attachment_idx, FORMAT format, WRAP_TYPE wrapType, FILTER_TYPE filterType ) { Init(w, h, attachment_idx, format, wrapType, filterType, false, FILTER_NEAREST); } ColorBufferObject::~ColorBufferObject() { glDeleteRenderbuffersEXT(1, &mId); glDeleteTextures(1, &mTexId); } void ColorBufferObject::Init(int w, int h, int attachment_idx, FORMAT format, WRAP_TYPE wrapType, FILTER_TYPE filterType, bool useMipMap, FILTER_TYPE filterTypeMipMap ) { mWidth = w; mHeight = h; int components = GL_RGBA; switch (format) { case RGB_UBYTE: mGlFormat = GL_UNSIGNED_BYTE; mInternalFormat = GL_RGB8; components = GL_RGB; break; case RGBA_UBYTE: mGlFormat = GL_UNSIGNED_BYTE; mInternalFormat = GL_RGBA8; break; case RGB_FLOAT_32: mGlFormat = GL_FLOAT; mInternalFormat = GL_RGB16F_ARB; components = GL_RGB; break; case RGBA_FLOAT_16: mGlFormat = GL_FLOAT; mInternalFormat = GL_RGBA16F_ARB; break; case RGB_FLOAT_16: mGlFormat = GL_FLOAT; mInternalFormat = GL_RGB32F_ARB; components = GL_RGB; break; case RGBA_FLOAT_32: mGlFormat = GL_FLOAT; mInternalFormat = GL_RGBA32F_ARB; break; default: mGlFormat = GL_UNSIGNED_BYTE; mInternalFormat = GL_RGBA8; cerr << "should not come here" << endl; } glGenRenderbuffersEXT(1, &mId); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mId); glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, mInternalFormat, w, h); glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, mrt[attachment_idx], GL_RENDERBUFFER_EXT, mId); glGenTextures(1, &mTexId); glBindTexture(GL_TEXTURE_2D, mTexId); glTexImage2D(GL_TEXTURE_2D, 0, mInternalFormat, w, h, 0, components, mGlFormat, NULL); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, mrt[attachment_idx], GL_TEXTURE_2D, mTexId, 0); GLuint minfilterParam; GLuint magfilterParam; if (filterType == FILTER_NEAREST) magfilterParam = GL_NEAREST; else // FILTER_LINEAR magfilterParam = GL_LINEAR; if (!useMipMap) { if (filterType == FILTER_NEAREST) minfilterParam = GL_NEAREST; else // FILTER_LINEAR minfilterParam = GL_LINEAR; } else { if (filterType == FILTER_NEAREST) { if (filterTypeMipMap == FILTER_NEAREST) minfilterParam = GL_NEAREST_MIPMAP_NEAREST; else // FILTER_LINEAR minfilterParam = GL_NEAREST_MIPMAP_LINEAR; } else // FILTER_LINEAR { if (filterTypeMipMap == FILTER_NEAREST) minfilterParam = GL_LINEAR_MIPMAP_NEAREST; else // FILTER_LINEAR minfilterParam = GL_LINEAR_MIPMAP_LINEAR; } } GLuint wrapParam; switch (wrapType) { case WRAP_REPEAT: wrapParam = GL_REPEAT; break; case WRAP_CLAMP_TO_EDGE: wrapParam = GL_CLAMP_TO_EDGE; break; case WRAP_CLAMP_TO_BORDER: wrapParam = GL_MIRROR_CLAMP_TO_EDGE_EXT; break; } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magfilterParam); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minfilterParam); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapParam); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapParam); if (useMipMap) { glGenerateMipmapEXT(GL_TEXTURE_2D); } // print status PrintFBOStatus(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT)); } void *ColorBufferObject::ReadTexture() const { int bytes = 0; switch (mInternalFormat) { case GL_RGB8: bytes = 3; break; case GL_RGBA8: bytes = 4; break; case GL_RGBA16F_ARB: bytes = 16; break; case GL_RGB32F_ARB: bytes = 24; break; case GL_RGBA32F_ARB: bytes = 32; break; default: cerr << "should not come here" << endl; } glBindTexture(GL_TEXTURE_2D, mTexId); unsigned char *data = new unsigned char[bytes * 4 * mWidth * mHeight]; glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, data); glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); return data; } /*****************************************************************/ /* FrameBufferObject implementation */ /*****************************************************************/ FrameBufferObject::FrameBufferObject(int w, int h, DEPTH_FORMAT d, bool useDepthTex) : mWidth(w), mHeight(h), mDepthTexId(0) { glGenFramebuffersEXT(1, &mId); Bind(); /////////// //-- create depth buffer if (d != DEPTH_NONE) { glGenRenderbuffersEXT(1, &mDepthId); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mDepthId); GLuint depthFormat; switch (d) { case DEPTH_16: depthFormat = GL_DEPTH_COMPONENT16; break; case DEPTH_24: depthFormat = GL_DEPTH_COMPONENT24; break; case DEPTH_32: depthFormat = GL_DEPTH_COMPONENT32; break; default: cerr << "should not come here" << endl; } glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, depthFormat, w, h); glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepthId); if (useDepthTex) { glGenTextures(1, &mDepthTexId); glBindTexture(GL_TEXTURE_2D, mDepthTexId); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexImage2D(GL_TEXTURE_2D, 0, depthFormat, mWidth, mHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, mDepthTexId, 0); } } Release(); } FrameBufferObject::~FrameBufferObject() { glDeleteFramebuffersEXT(1, &mId); glDeleteRenderbuffersEXT(1, &mDepthId); if (mDepthTexId) glDeleteTextures(1, &mDepthTexId); CLEAR_CONTAINER(mColorBuffers); } int FrameBufferObject::AddColorBuffer(ColorBufferObject::FORMAT col, ColorBufferObject::WRAP_TYPE wrapType, ColorBufferObject::FILTER_TYPE filterType, ColorBufferObject::FILTER_TYPE filterTypeMipMap) { Bind(); const int idx = (int)mColorBuffers.size(); ColorBufferObject *colorBuf = new ColorBufferObject(mWidth, mHeight, idx, col, wrapType, filterType, filterTypeMipMap); mColorBuffers.push_back(colorBuf); Release(); return idx; } int FrameBufferObject::AddColorBuffer(ColorBufferObject::FORMAT col, ColorBufferObject::WRAP_TYPE wrapType, ColorBufferObject::FILTER_TYPE filterType) { Bind(); const int idx = (int)mColorBuffers.size(); ColorBufferObject *colorBuf = new ColorBufferObject(mWidth, mHeight, idx, col, wrapType, filterType); mColorBuffers.push_back(colorBuf); Release(); return idx; } void FrameBufferObject::Bind() const { if (sCurrentFbo != mId) { sCurrentFbo = mId; glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mId); } } void FrameBufferObject::Release() { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); sCurrentFbo = -1; } void FrameBufferObject::InitBuffer(FrameBufferObject *fbo, int index) { // read the second buffer, write to the first buffer fbo->Bind(); glDrawBuffers(1, mrt + index); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); FrameBufferObject::Release(); } } // namespace