00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "r_local.h"
00026 #include "r_framebuffer.h"
00027 #include "r_error.h"
00028
00029 #define MAX_FRAMEBUFFER_OBJECTS 64
00030
00031 static int frameBufferObjectCount;
00032 static r_framebuffer_t frameBufferObjects[MAX_FRAMEBUFFER_OBJECTS];
00033 static GLuint frameBufferTextures[TEXNUM_FRAMEBUFFER_TEXTURES];
00034
00035 static r_framebuffer_t screenBuffer;
00036 static GLenum *colorAttachments;
00037
00038 static GLuint R_GetFreeFBOTexture (void)
00039 {
00040 int i;
00041
00042 for (i = 0; i < TEXNUM_FRAMEBUFFER_TEXTURES; i++) {
00043 if (frameBufferTextures[i] == 0) {
00044 frameBufferTextures[i] = 1;
00045 return TEXNUM_FRAMEBUFFER_TEXTURES + i;
00046 }
00047 }
00048
00049 Com_Error(ERR_FATAL, "Exceeded max frame buffer textures");
00050 }
00051
00052 static void R_FreeFBOTexture (int texnum)
00053 {
00054 const int i = texnum - TEXNUM_FRAMEBUFFER_TEXTURES;
00055 assert(i >= 0);
00056 assert(i < TEXNUM_FRAMEBUFFER_TEXTURES);
00057 frameBufferTextures[i] = 0;
00058 glDeleteTextures(1, (GLuint *) &texnum);
00059 }
00060
00061 void R_InitFBObjects (void)
00062 {
00063 unsigned int filters[2];
00064 float scales[DOWNSAMPLE_PASSES];
00065 int i;
00066
00067 if (!r_config.frameBufferObject || !r_programs->integer)
00068 return;
00069
00070 frameBufferObjectCount = 0;
00071 memset(frameBufferObjects, 0, sizeof(frameBufferObjects));
00072 memset(frameBufferTextures, 0, sizeof(frameBufferTextures));
00073
00074 r_state.frameBufferObjectsInitialized = qtrue;
00075
00076 for (i = 0; i < DOWNSAMPLE_PASSES; i++)
00077 scales[i] = powf(DOWNSAMPLE_SCALE, i + 1);
00078
00079
00080 screenBuffer.fbo = 0;
00081 screenBuffer.depth = 0;
00082 screenBuffer.nTextures = 0;
00083 screenBuffer.width = viddef.width;
00084 screenBuffer.height = viddef.height;
00085 R_SetupViewport(&screenBuffer, 0, 0, viddef.width, viddef.height);
00086 Vector4Clear(screenBuffer.clearColor);
00087
00088 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
00089 r_state.activeFramebuffer = &screenBuffer;
00090
00091 colorAttachments = Mem_Alloc(sizeof(GLenum) * r_config.maxDrawBuffers);
00092 for (i = 0; i < r_config.maxDrawBuffers; i++)
00093 colorAttachments[i] = GL_COLOR_ATTACHMENT0_EXT + i;
00094
00095 filters[0] = GL_NEAREST;
00096 filters[1] = GL_LINEAR_MIPMAP_LINEAR;
00097
00098
00099 r_state.renderBuffer = R_CreateFramebuffer(viddef.width, viddef.height, 2, qtrue, qfalse, filters);
00100
00101
00102 fbo_bloom0 = R_CreateFramebuffer(viddef.width, viddef.height, 1, qfalse, qfalse, filters);
00103 fbo_bloom1 = R_CreateFramebuffer(viddef.width, viddef.height, 1, qfalse, qfalse, filters);
00104
00105 filters[0] = GL_LINEAR;
00106
00107 for (i = 0; i < DOWNSAMPLE_PASSES; i++) {
00108 const int h = (int)((float)viddef.height / scales[i]);
00109 const int w = (int)((float)viddef.width / scales[i]);
00110 r_state.buffers0[i] = R_CreateFramebuffer(w, h, 1, qfalse, qfalse, filters);
00111 r_state.buffers1[i] = R_CreateFramebuffer(w, h, 1, qfalse, qfalse, filters);
00112 r_state.buffers2[i] = R_CreateFramebuffer(w, h, 1, qfalse, qfalse, filters);
00113
00114 R_CheckError();
00115 }
00116 }
00117
00118
00122 void R_DeleteFBObject (r_framebuffer_t *buf)
00123 {
00124 if (buf->depth)
00125 qglDeleteRenderbuffersEXT(1, &buf->depth);
00126 buf->depth = 0;
00127
00128 if (buf->textures) {
00129 int i;
00130 for (i = 0; i < buf->nTextures; i++)
00131 R_FreeFBOTexture(buf->textures[i]);
00132 Mem_Free(buf->textures);
00133 }
00134 buf->textures = 0;
00135
00136 if (buf->fbo)
00137 qglDeleteFramebuffersEXT(1, &buf->fbo);
00138 buf->fbo = 0;
00139 }
00140
00141
00145 void R_ShutdownFBObjects (void)
00146 {
00147 int i;
00148
00149 if (!r_state.frameBufferObjectsInitialized)
00150 return;
00151
00152 for (i = 0; i < frameBufferObjectCount; i++)
00153 R_DeleteFBObject(&frameBufferObjects[i]);
00154
00155 R_UseFramebuffer(&screenBuffer);
00156
00157 frameBufferObjectCount = 0;
00158 memset(frameBufferObjects, 0, sizeof(frameBufferObjects));
00159 r_state.frameBufferObjectsInitialized = qfalse;
00160
00161 Mem_Free(colorAttachments);
00162 }
00163
00164
00174 r_framebuffer_t * R_CreateFramebuffer (int width, int height, int ntextures, qboolean depth, qboolean halfFloat, unsigned int *filters)
00175 {
00176 r_framebuffer_t *buf;
00177 int i;
00178
00179 if (!r_state.frameBufferObjectsInitialized) {
00180 Com_Printf("Warning: framebuffer creation failed; framebuffers not initialized!\n");
00181 return NULL;
00182 }
00183
00184 if (frameBufferObjectCount >= lengthof(frameBufferObjects)) {
00185 Com_Printf("Warning: framebuffer creation failed; already created too many framebuffers!\n");
00186 return NULL;
00187 }
00188
00189 buf = &frameBufferObjects[frameBufferObjectCount++];
00190
00191 if (ntextures > r_config.maxDrawBuffers) {
00192 Com_Printf("Couldn't allocate requested number of drawBuffers in R_SetupFramebuffer!\n");
00193 ntextures = r_config.maxDrawBuffers;
00194 }
00195
00196 Vector4Clear(buf->clearColor);
00197
00198 buf->width = width;
00199 buf->height = height;
00200 R_SetupViewport(buf, 0, 0, width, height);
00201
00202 buf->nTextures = ntextures;
00203 buf->textures = Mem_Alloc(sizeof(GLuint) * ntextures);
00204
00205 buf->pixelFormat = (halfFloat == qtrue) ? GL_RGBA16F_ARB : GL_RGBA8;
00206 buf->byteFormat = (halfFloat == qtrue) ? GL_HALF_FLOAT_ARB : GL_UNSIGNED_BYTE;
00207
00208 for (i = 0 ; i < buf->nTextures; i++) {
00209 buf->textures[i] = R_GetFreeFBOTexture();
00210 glBindTexture(GL_TEXTURE_2D, buf->textures[i]);
00211 glTexImage2D(GL_TEXTURE_2D, 0, buf->pixelFormat, buf->width, buf->height, 0, GL_RGBA, buf->byteFormat, 0);
00212
00213 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filters[i]);
00214 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00215 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
00216 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
00217 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
00218 qglGenerateMipmapEXT(GL_TEXTURE_2D);
00219 if (r_config.anisotropic)
00220 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, r_config.maxAnisotropic);
00221
00222 R_CheckError();
00223 }
00224
00225
00226 if (depth == qtrue) {
00227 qglGenRenderbuffersEXT(1, &buf->depth);
00228 qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, buf->depth);
00229 qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, buf->width, buf->height);
00230 R_CheckError();
00231 } else {
00232 buf->depth = 0;
00233 }
00234
00235 R_CheckError();
00236
00237
00238 qglGenFramebuffersEXT(1, &buf->fbo);
00239 R_CheckError();
00240 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buf->fbo);
00241
00242 for (i = 0; i < buf->nTextures; i++) {
00243 glBindTexture(GL_TEXTURE_2D, buf->textures[i]);
00244 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, colorAttachments[i], GL_TEXTURE_2D, buf->textures[i], 0);
00245 R_CheckError();
00246 }
00247
00248 glBindTexture(GL_TEXTURE_2D, 0);
00249 if (depth)
00250 qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, buf->depth);
00251
00252 R_CheckError();
00253
00254 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
00255
00256 return buf;
00257 }
00258
00263 void R_UseFramebuffer (const r_framebuffer_t *buf)
00264 {
00265 if (!r_config.frameBufferObject || !r_programs->integer || !r_postprocess->integer)
00266 return;
00267
00268 if (!r_state.frameBufferObjectsInitialized) {
00269 Com_Printf("Can't bind framebuffer: framebuffers not initialized\n");
00270 return;
00271 }
00272
00273 if (!buf)
00274 buf = &screenBuffer;
00275
00276
00277 if (buf == r_state.activeFramebuffer)
00278 return;
00279
00280 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buf->fbo);
00281
00282
00284 if (buf->nTextures > 0)
00285 qglDrawBuffers(buf->nTextures, colorAttachments);
00286
00287 glClearColor(r_state.activeFramebuffer->clearColor[0], r_state.activeFramebuffer->clearColor[1], r_state.activeFramebuffer->clearColor[2], r_state.activeFramebuffer->clearColor[3]);
00288 glClear(GL_COLOR_BUFFER_BIT | (buf->depth ? GL_DEPTH_BUFFER_BIT : 0));
00289
00290 r_state.activeFramebuffer = buf;
00291
00292 R_CheckError();
00293 }
00294
00300 void R_SetupViewport (r_framebuffer_t *buf, int x, int y, int width, int height)
00301 {
00302 if (!buf)
00303 buf = &screenBuffer;
00304
00305 buf->viewport.x = x;
00306 buf->viewport.y = y;
00307 buf->viewport.width = width;
00308 buf->viewport.height = height;
00309 }
00310
00316 void R_UseViewport (const r_framebuffer_t *buf)
00317 {
00318 if (!r_state.frameBufferObjectsInitialized || !r_config.frameBufferObject || !r_postprocess->integer || !r_programs->integer)
00319 return;
00320
00321 if (!buf)
00322 buf = &screenBuffer;
00323 glViewport(buf->viewport.x, buf->viewport.y, buf->viewport.width, buf->viewport.height);
00324 }
00325
00327 void R_DrawBuffers (int n)
00328 {
00329 R_BindColorAttachments(n, colorAttachments);
00330 }
00331
00332 void R_BindColorAttachments (int n, unsigned int *attachments)
00333 {
00334 if (!r_state.frameBufferObjectsInitialized || !r_config.frameBufferObject || !r_postprocess->integer || !r_programs->integer)
00335 return;
00336
00337 if (n >= r_config.maxDrawBuffers) {
00338 Com_DPrintf(DEBUG_RENDERER, "Max drawbuffers hit\n");
00339 n = r_config.maxDrawBuffers;
00340 }
00341
00342 if (r_state.activeFramebuffer && r_state.activeFramebuffer->nTextures > 0)
00343 qglDrawBuffers(n, attachments);
00344 }
00345
00346 qboolean R_EnableRenderbuffer (qboolean enable)
00347 {
00348 if (!r_state.frameBufferObjectsInitialized || !r_config.frameBufferObject || !r_postprocess->integer || !r_programs->integer)
00349 return qfalse;
00350
00351 if (enable != r_state.renderbuffer_enabled) {
00352 r_state.renderbuffer_enabled = enable;
00353 if (enable)
00354 R_UseFramebuffer(fbo_render);
00355 else
00356 R_UseFramebuffer(fbo_screen);
00357 }
00358
00359 R_DrawBuffers(1);
00360
00361 return qtrue;
00362 }
00363
00364 qboolean R_RenderbufferEnabled (void)
00365 {
00366 return r_state.renderbuffer_enabled;
00367 }
00368