前面介绍了类LLRenderTarget的声明,并且大体地说明了每个函数的作用,但没有仔细地看到它是怎么样实现的,现在就来分析具体的实现细节。它的实现代码如下:
#001 BOOL LLRenderTarget::sUseFBO = FALSE;
#002
下面是构造函数初始化成员变量。
#003 LLRenderTarget::LLRenderTarget()
#004 {
#005 mResX = mResY = mTex = mFBO = mDepth = 0;
#006 mUseDepth = FALSE;
#007 mUsage = GL_TEXTURE_2D;
#008 }
#009
下面是析构函数释放资源。
#010 LLRenderTarget::~LLRenderTarget()
#011 {
#012 release();
#013 }
#014
#015 void LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, U32 usage, BOOL force_fbo)
#016 {
分配区域的大小。
#017 mResX = resx;
#018 mResY = resy;
#019
使用离屏对象。
#020 mUsage = usage;
使用深度对象。
#021 mUseDepth = depth;
释放以前分配的资源。
#022 release();
#023
生成纹理。
#024 glGenTextures(1, (GLuint *) &mTex);
绑定纹理。
#025 glBindTexture(mUsage, mTex);
创建2D纹理。
#026 glTexImage2D(mUsage, 0, color_fmt, mResX, mResY, 0, color_fmt, GL_UNSIGNED_BYTE, NULL);
#027
设置纹理大小缩放的采样方式。
#028 glTexParameteri(mUsage, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
#029 glTexParameteri(mUsage, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
#030
设置纹理环绕。
#031 if (mUsage != GL_TEXTURE_RECTANGLE_ARB)
#032 {
#033 glTexParameteri(mUsage, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
#034 glTexParameteri(mUsage, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
#035 }
#036 else
#037 {
#038 // ATI doesn't support mirrored repeat for rectangular textures.
#039 glTexParameteri(mUsage, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
#040 glTexParameteri(mUsage, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#041 }
#042
#043 stop_glerror();
#044
判断是否使用FBO对象。
#045 if (sUseFBO || force_fbo)
#046 {
生成深度离屏对象。
#047 if (depth)
#048 {
#049 glGenRenderbuffersEXT(1, (GLuint *) &mDepth);
#050 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mDepth);
#051 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,GL_DEPTH_COMPONENT,mResX,mResY);
#052 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
#053 }
#054
生成一般的离屏对象mFBO。
#055 glGenFramebuffersEXT(1, (GLuint *) &mFBO);
#056 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
#057
#058 if (mDepth)
#059 {
#060 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
#061
#062 GL_RENDERBUFFER_EXT, mDepth);
#063 }
添加纹理对象。
#064 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
#065 mUsage, mTex, 0);
#066
#067
#068 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
#069 }
#070 }
#071
#072 void LLRenderTarget::release()
#073 {
#074 if (mFBO)
#075 {
删除离屏对象。
#076 glDeleteFramebuffersEXT(1, (GLuint *) &mFBO);
#077 mFBO = 0;
#078 }
#079
#080 if (mTex)
#081 {
删除离屏纹理对象。
#082 glDeleteTextures(1, (GLuint *) &mTex);
#083 mTex = 0;
#084 }
#085
#086 if (mDepth)
#087 {
删除深度离屏对象。
#088 glDeleteRenderbuffersEXT(1, (GLuint *) &mDepth);
#089 mDepth = 0;
#090 }
#091 }
#092
#093 void LLRenderTarget::bindTarget()
#094 {
#095 if (mFBO)
#096 {
绑定离屏对象。
#097 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
#098 }
#099
设置视口的大小。
#100 glViewport(0, 0, mResX, mResY);
#101 }
#102
#103 void LLRenderTarget::clear()
#104 {
#105 U32 mask = GL_COLOR_BUFFER_BIT;
#106 if (mUseDepth)
#107 {
#108 mask |= GL_DEPTH_BUFFER_BIT;
#109 }
清除离屏对象。
#110 if (mFBO)
#111 {
#112 glClear(mask);
#113 }
#114 else
#115 {
#116 LLGLEnable scissor(GL_SCISSOR_TEST);
#117 glScissor(0, 0, mResX, mResY);
#118 glClear(mask);
#119 }
#120 }
#121
#122 void LLRenderTarget::bindTexture()
#123 {
#124 glBindTexture(mUsage, mTex);
#125 }
#126
#127 void LLRenderTarget::flush()
#128 {
调用OPENGL函数显示。
#129 gGL.flush();
#130 if (!mFBO)
#131 {
#132 bindTexture();
#133 glCopyTexSubImage2D(mUsage, 0, 0, 0, 0, 0, mResX, mResY);
#134 }
#135 }
#136
#137 BOOL LLRenderTarget::isComplete() const
#138 {
#139 return (mTex || mDepth) ? TRUE : FALSE;
#140 }
#141
#142 void LLRenderTarget::getViewport(S32* viewport)
#143 {
#144 viewport[0] = 0;
#145 viewport[1] = 0;
#146 viewport[2] = mResX;
#147 viewport[3] = mResY;
#148 }
#149
使用glGenFramebuffersEXT函数来创建离屏对象,glDeleteFramebuffersEXT函数来删除对象,使用glBindFramebufferEXT绑定当前使用的FrameBuffer对象。使用glFramebufferTexture2DEXT函数来指定纹理。使用函数glRenderbufferStorageEXT来指定离屏的大小。这些函数都是OPENGL比较新的API扩展,因此使用这些功能就需要检查OPENGL是否支持这些功能,才能使用它,否则会出错的。