1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20 // r_bloom.c: 2D lighting post process effect
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "r_local.h"
27
28 /*
29 ==============================================================================
30
31 LIGHT BLOOMS
32
33 ==============================================================================
34 */
35
36 static float Diamond8x[8][8] = {
37 {0.0f, 0.0f, 0.0f, 0.1f, 0.1f, 0.0f, 0.0f, 0.0f},
38 {0.0f, 0.0f, 0.2f, 0.3f, 0.3f, 0.2f, 0.0f, 0.0f},
39 {0.0f, 0.2f, 0.4f, 0.6f, 0.6f, 0.4f, 0.2f, 0.0f},
40 {0.1f, 0.3f, 0.6f, 0.9f, 0.9f, 0.6f, 0.3f, 0.1f},
41 {0.1f, 0.3f, 0.6f, 0.9f, 0.9f, 0.6f, 0.3f, 0.1f},
42 {0.0f, 0.2f, 0.4f, 0.6f, 0.6f, 0.4f, 0.2f, 0.0f},
43 {0.0f, 0.0f, 0.2f, 0.3f, 0.3f, 0.2f, 0.0f, 0.0f},
44 {0.0f, 0.0f, 0.0f, 0.1f, 0.1f, 0.0f, 0.0f, 0.0f} };
45
46 static float Diamond6x[6][6] = {
47 {0.0f, 0.0f, 0.1f, 0.1f, 0.0f, 0.0f},
48 {0.0f, 0.3f, 0.5f, 0.5f, 0.3f, 0.0f},
49 {0.1f, 0.5f, 0.9f, 0.9f, 0.5f, 0.1f},
50 {0.1f, 0.5f, 0.9f, 0.9f, 0.5f, 0.1f},
51 {0.0f, 0.3f, 0.5f, 0.5f, 0.3f, 0.0f},
52 {0.0f, 0.0f, 0.1f, 0.1f, 0.0f, 0.0f} };
53
54 static float Diamond4x[4][4] = {
55 {0.3f, 0.4f, 0.4f, 0.3f},
56 {0.4f, 0.9f, 0.9f, 0.4f},
57 {0.4f, 0.9f, 0.9f, 0.4f},
58 {0.3f, 0.4f, 0.4f, 0.3f} };
59
60
61 static int BLOOM_SIZE;
62
63 cvar_t *r_bloom_alpha;
64 cvar_t *r_bloom_diamond_size;
65 cvar_t *r_bloom_intensity;
66 cvar_t *r_bloom_darken;
67 cvar_t *r_bloom_sample_size;
68 cvar_t *r_bloom_fast_sample;
69
70 image_t *r_bloomscratchtexture;
71 image_t *r_bloomeffecttexture;
72 image_t *r_midsizetexture;
73 static GLuint bloomscratchFBO, midsizeFBO, bloomeffectFBO;
74 static GLuint bloom_fullsize_downsampling_rbo_FBO;
75 static GLuint bloom_fullsize_downsampling_RBO;
76
77 static int r_midsizetexture_size;
78 static int screen_texture_width, screen_texture_height;
79
80 GLint MultiSampleEnabled = 0; //1 if MSAA is enabled
81
82 //current refdef size:
83 static int curView_x;
84 static int curView_y;
85 static int curView_width;
86 static int curView_height;
87
88 #define R_Bloom_Quad( x, y, width, height ) \
89 qglBegin(GL_QUADS); \
90 qglTexCoord2f( 0, 1.0); \
91 qglVertex2f( x, y); \
92 qglTexCoord2f( 0, 0); \
93 qglVertex2f( x, y+height); \
94 qglTexCoord2f( 1.0, 0); \
95 qglVertex2f( x+width, y+height); \
96 qglTexCoord2f( 1.0, 1.0); \
97 qglVertex2f( x+width, y); \
98 qglEnd();
99
100 #define R_Bloom_SamplePass( xpos, ypos ) R_Bloom_Quad ( xpos, ypos, BLOOM_SIZE, BLOOM_SIZE)
101
102
103
104 /*
105 =================
106 R_Bloom_AllocFBOTexture
107
108 Create a 24-bit square texture with specified size and attach it to an FBO
109 =================
110 */
R_Bloom_AllocFBOTexture(char * name,int size_side,GLuint * FBO)111 image_t *R_Bloom_AllocFBOTexture (char *name, int size_side, GLuint *FBO)
112 {
113 byte *data;
114 int size;
115 image_t *image;
116
117 size = size_side*size_side*3;
118 data = malloc (size);
119 memset (data, 0, size);
120
121 // create the texture
122 image = GL_FindFreeImage (name, size_side, size_side, it_pic);
123 GL_Bind (image->texnum);
124 qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
125 qglTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, size_side, size_side, 0, GL_RGB, GL_UNSIGNED_BYTE, (byte*)data);
126
127 // create up the FBO
128 qglGenFramebuffersEXT(1, FBO);
129 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT,*FBO);
130
131 // bind the texture to it
132 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, image->texnum, 0);
133
134 // clean up
135 free (data);
136 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);
137
138 return image;
139 }
140
141
142
143 /*
144 =================
145 R_Bloom_AllocRBO
146
147 Create a 24-bit square RBO with specified size and attach it to an FBO
148 =================
149 */
R_Bloom_AllocRBO(int width,int height,GLuint * RBO,GLuint * FBO)150 void R_Bloom_AllocRBO (int width, int height, GLuint *RBO, GLuint *FBO)
151 {
152 // create the RBO
153 qglGenRenderbuffersEXT(1, RBO);
154 qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, *RBO);
155 qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, width, height);
156 qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
157
158 // create up the FBO
159 qglGenFramebuffersEXT(1, FBO);
160 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, *FBO);
161
162 // bind the RBO to it
163 qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, *RBO);
164
165 //clean up
166 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
167 }
168
169
170
171 /*
172 =================
173 R_Bloom_InitEffectTexture
174 =================
175 */
R_Bloom_InitEffectTexture(void)176 void R_Bloom_InitEffectTexture( void )
177 {
178 float bloomsizecheck;
179
180 if( r_bloom_sample_size->integer < 32 )
181 Cvar_SetValue ("r_bloom_sample_size", 32);
182
183 //make sure bloom size is a power of 2
184 BLOOM_SIZE = r_bloom_sample_size->integer;
185 bloomsizecheck = (float)BLOOM_SIZE;
186 while(bloomsizecheck > 1.0f) bloomsizecheck /= 2.0f;
187 if( bloomsizecheck != 1.0f )
188 {
189 BLOOM_SIZE = 32;
190 while( BLOOM_SIZE < r_bloom_sample_size->integer )
191 BLOOM_SIZE *= 2;
192 }
193
194 //make sure bloom size doesn't have stupid values
195 if( BLOOM_SIZE > screen_texture_width ||
196 BLOOM_SIZE > screen_texture_height )
197 BLOOM_SIZE = min( screen_texture_width, screen_texture_height );
198
199 if( BLOOM_SIZE != r_bloom_sample_size->integer )
200 Cvar_SetValue ("r_bloom_sample_size", BLOOM_SIZE);
201
202 r_bloomeffecttexture = R_Bloom_AllocFBOTexture ("***r_bloomeffecttexture***", BLOOM_SIZE, &bloomeffectFBO);
203 }
204
205 /*
206 =================
207 R_Bloom_InitTextures
208 =================
209 */
210 void checkFBOExtensions (void);
R_Bloom_InitTextures(void)211 void R_Bloom_InitTextures( void )
212 {
213 if (!gl_state.fbo || !gl_state.hasFBOblit)
214 {
215 Com_Printf ("FBO Failed, disabling bloom.\n");
216 Cvar_SetValue ("r_bloom", 0);
217 return;
218 }
219
220 qglGetError ();
221
222 qglGetIntegerv(GL_SAMPLE_BUFFERS, &MultiSampleEnabled);
223
224 //find closer power of 2 to screen size
225 for (screen_texture_width = 1;screen_texture_width < viddef.width;screen_texture_width *= 2);
226 for (screen_texture_height = 1;screen_texture_height < viddef.height;screen_texture_height *= 2);
227
228 //validate bloom size and init the bloom effect texture
229 R_Bloom_InitEffectTexture();
230
231 //init the "scratch" texture
232 r_bloomscratchtexture = R_Bloom_AllocFBOTexture ("***r_bloomscratchtexture***", BLOOM_SIZE, &bloomscratchFBO);
233
234 //init the screen-size RBO
235 R_Bloom_AllocRBO (viddef.width, viddef.height, &bloom_fullsize_downsampling_RBO, &bloom_fullsize_downsampling_rbo_FBO);
236
237 //if screensize is more than 2x the bloom effect texture, set up for stepped downsampling
238 r_midsizetexture = NULL;
239 r_midsizetexture_size = 0;
240 if( viddef.width > (BLOOM_SIZE * 2) && !r_bloom_fast_sample->integer )
241 {
242 r_midsizetexture_size = (int)(BLOOM_SIZE * 2);
243 // mid-size texture
244 r_midsizetexture = R_Bloom_AllocFBOTexture ("***r_midsizetexture***", r_midsizetexture_size, &midsizeFBO);
245 }
246
247 }
248
249 /*
250 =================
251 R_InitBloomTextures
252 =================
253 */
R_InitBloomTextures(void)254 void R_InitBloomTextures( void )
255 {
256
257 r_bloom = Cvar_Get( "r_bloom", "0", CVAR_ARCHIVE );
258 r_bloom_alpha = Cvar_Get( "r_bloom_alpha", "0.2", CVAR_ARCHIVE );
259 r_bloom_diamond_size = Cvar_Get( "r_bloom_diamond_size", "8", CVAR_ARCHIVE );
260 r_bloom_intensity = Cvar_Get( "r_bloom_intensity", "0.5", CVAR_ARCHIVE );
261 r_bloom_darken = Cvar_Get( "r_bloom_darken", "8", CVAR_ARCHIVE );
262 r_bloom_sample_size = Cvar_Get( "r_bloom_sample_size", "128", CVAR_ARCHIVE );
263 r_bloom_fast_sample = Cvar_Get( "r_bloom_fast_sample", "0", CVAR_ARCHIVE );
264
265 BLOOM_SIZE = 0;
266 if( !r_bloom->integer )
267 return;
268
269 R_Bloom_InitTextures ();
270 }
271
272
273 /*
274 =================
275 R_Bloom_DrawEffect
276 =================
277 */
R_Bloom_DrawEffect(void)278 void R_Bloom_DrawEffect( void )
279 {
280 GL_Bind(r_bloomeffecttexture->texnum);
281 qglEnable(GL_BLEND);
282 qglBlendFunc(GL_ONE, GL_ONE);
283 qglColor4f(r_bloom_alpha->value, r_bloom_alpha->value, r_bloom_alpha->value, 1.0f);
284 GL_TexEnv(GL_MODULATE);
285 qglBegin(GL_QUADS);
286 qglTexCoord2f( 0, 1.0 );
287 qglVertex2f( curView_x, curView_y );
288 qglTexCoord2f( 0, 0 );
289 qglVertex2f( curView_x, curView_y + curView_height );
290 qglTexCoord2f( 1.0, 0 );
291 qglVertex2f( curView_x + curView_width, curView_y + curView_height );
292 qglTexCoord2f( 1.0, 1.0 );
293 qglVertex2f( curView_x + curView_width, curView_y );
294 qglEnd();
295
296 qglDisable(GL_BLEND);
297 }
298
299
300 /*
301 =================
302 R_Bloom_GeneratexDiamonds
303 =================
304 */
R_Bloom_GeneratexDiamonds(void)305 void R_Bloom_GeneratexDiamonds( void )
306 {
307 int i, j;
308 static float intensity;
309
310 //set up sample size workspace
311 qglViewport( 0, 0, BLOOM_SIZE, BLOOM_SIZE );
312 qglMatrixMode( GL_PROJECTION );
313 qglLoadIdentity ();
314 qglOrtho(0, BLOOM_SIZE, BLOOM_SIZE, 0, -10, 100);
315 qglMatrixMode( GL_MODELVIEW );
316
317 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, bloomscratchFBO);
318 GL_Bind(r_bloomeffecttexture->texnum);
319
320 //start modifying the small scene corner
321 qglColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
322 qglEnable(GL_BLEND);
323
324 //darkening passes
325 if( r_bloom_darken->integer )
326 {
327 qglBlendFunc(GL_DST_COLOR, GL_ZERO);
328 GL_TexEnv(GL_MODULATE);
329
330 for(i=0; i<r_bloom_darken->integer ;i++) {
331 R_Bloom_SamplePass( 0, 0 );
332 }
333
334 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, BLOOM_SIZE, BLOOM_SIZE);
335 }
336
337 //bluring passes
338 //qglBlendFunc(GL_ONE, GL_ONE);
339 qglBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
340
341 if( r_bloom_diamond_size->integer > 7 || r_bloom_diamond_size->integer <= 3)
342 {
343 if( r_bloom_diamond_size->integer != 8 ) Cvar_SetValue( "r_bloom_diamond_size", 8 );
344
345 for(i=0; i<r_bloom_diamond_size->integer; i++) {
346 for(j=0; j<r_bloom_diamond_size->integer; j++) {
347 intensity = r_bloom_intensity->value * 0.3 * Diamond8x[i][j];
348 if( intensity < 0.01f ) continue;
349 qglColor4f( intensity, intensity, intensity, 1.0);
350 R_Bloom_SamplePass( i-4, j-4 );
351 }
352 }
353 } else if( r_bloom_diamond_size->integer > 5 ) {
354
355 if( r_bloom_diamond_size->integer != 6 ) Cvar_SetValue( "r_bloom_diamond_size", 6 );
356
357 for(i=0; i<r_bloom_diamond_size->integer; i++) {
358 for(j=0; j<r_bloom_diamond_size->integer; j++) {
359 intensity = r_bloom_intensity->value * 0.5 * Diamond6x[i][j];
360 if( intensity < 0.01f ) continue;
361 qglColor4f( intensity, intensity, intensity, 1.0);
362 R_Bloom_SamplePass( i-3, j-3 );
363 }
364 }
365 } else if( r_bloom_diamond_size->integer > 3 ) {
366
367 if( r_bloom_diamond_size->integer != 4 ) Cvar_SetValue( "r_bloom_diamond_size", 4 );
368
369 for(i=0; i<r_bloom_diamond_size->integer; i++) {
370 for(j=0; j<r_bloom_diamond_size->integer; j++) {
371 intensity = r_bloom_intensity->value * 0.8f * Diamond4x[i][j];
372 if( intensity < 0.01f ) continue;
373 qglColor4f( intensity, intensity, intensity, 1.0);
374 R_Bloom_SamplePass( i-2, j-2 );
375 }
376 }
377 }
378
379 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, BLOOM_SIZE, BLOOM_SIZE);
380
381 //restore full screen workspace
382 qglViewport( 0, 0, viddef.width, viddef.height );
383 qglMatrixMode( GL_PROJECTION );
384 qglLoadIdentity ();
385 qglOrtho(0, viddef.width, viddef.height, 0, -10, 100);
386 qglMatrixMode( GL_MODELVIEW );
387 qglLoadIdentity ();
388
389 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
390 }
391
392 /*
393 =================
394 R_Bloom_FullsizeRBOUpdate
395
396 This updates the full size RBO from the screen. The whole thing is guaranteed
397 to be updated 60 times a second, but it does it a 1/4 of the screen at a time
398 if the framerate is high enough. It does it in horizontal slices instead of
399 quadrants because that way the GPU doesn't have to skip over part of each row
400 of pixels. Tearing isn't an issue because it'll just be blurred to mush
401 anyway.
402 =================
403 */
R_Bloom_FullsizeRBOUpdate(void)404 void R_Bloom_FullsizeRBOUpdate (void)
405 {
406 static int cur_section = 0;
407 static int last_time = 0;
408 int i, num_sections, cur_time;
409 int y;
410
411 cur_time = Sys_Milliseconds();
412 num_sections = (cur_time-last_time+2)/4;
413 if (num_sections > 4) num_sections = 4;
414 if (num_sections == 0) return;
415
416 for (i = 0; i < num_sections; i++)
417 {
418 y = cur_section*(vid.height/4);
419 qglBlitFramebufferEXT(0, y, vid.width, y+vid.height/4, 0, y, vid.width, y+vid.height/4,
420 GL_COLOR_BUFFER_BIT, GL_LINEAR);
421 cur_section = (cur_section + 1) % 4;
422 }
423 last_time = cur_time;
424 }
425
426 /*
427 =================
428 R_Bloom_DownsampleView
429
430 Creates a downscaled, blurred version of the screen, leaving it in the
431 "scratch" and "effect" textures (identical in both.) This function is name is
432 a bit confusing, because "downsampling" means two things here:
433 1) Creating a scaled-down version of an image
434 2) Converting a multisampled image to a non-multisampled image the same size,
435 which is necessary if MSAA is enabled in the graphics driver settings
436 The function name uses meaning 1.
437 =================
438 */
R_Bloom_DownsampleView(void)439 void R_Bloom_DownsampleView( void )
440 {
441 qglDisable( GL_BLEND );
442 qglColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
443
444 GL_SelectTexture (GL_TEXTURE0);
445 // FIXME: OH FFS this is so stupid: tell the GL_Bind batching mechanism
446 // that texture unit 0 has been re-bound, as it most certainly has been.
447 gl_state.currenttextures[gl_state.currenttmu] = -1;
448
449 if (MultiSampleEnabled != 0)
450 {
451 // If MSAA is enabled, the FBO blitting needs an extra step.
452 // Copy onto full-screen sized RBO first, to go from the multisample
453 // format of the screen to a non-multisampled format.
454 qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, bloom_fullsize_downsampling_rbo_FBO);
455 R_Bloom_FullsizeRBOUpdate ();
456 // Set the downsampled RBO as the read framebuffer, then run the rest
457 // of the code as normal.
458 qglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, bloom_fullsize_downsampling_rbo_FBO);
459 }
460
461 //stepped downsample
462 if( r_midsizetexture_size )
463 {
464 // copy into small sized FBO (equivalent to copying into full screen
465 // sized FBO and then drawing that onto the small sized FBO later.)
466 qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, bloomscratchFBO);
467 qglBlitFramebufferEXT(0, 0, vid.width, vid.height, 0, 0, BLOOM_SIZE, BLOOM_SIZE,
468 GL_COLOR_BUFFER_BIT, GL_LINEAR);
469 // copy into downsampling (mid-sized) FBO
470 qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, midsizeFBO);
471 qglBlitFramebufferEXT(0, 0, vid.width, vid.height, 0, 0, r_midsizetexture_size, r_midsizetexture_size,
472 GL_COLOR_BUFFER_BIT, GL_LINEAR);
473
474
475 // create the finished downsampled version of the texture by blending
476 // the small-sized FBO and the mid-sized FBO onto a small-sized FBO,
477 // hoping it adds some blur.
478
479 // Store first of all in the bloom effect texture, since we don't want
480 // to draw the scratch texture onto itself.
481 qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, bloomeffectFBO);
482
483 // mid-size
484 GL_Bind(r_midsizetexture->texnum);
485 qglColor4f( 0.5f, 0.5f, 0.5f, 1.0f );
486 R_Bloom_Quad( 0, viddef.height-BLOOM_SIZE, BLOOM_SIZE, BLOOM_SIZE);
487 // small-size
488 qglEnable( GL_BLEND );
489 qglBlendFunc(GL_ONE, GL_ONE);
490 qglColor4f( 0.5f, 0.5f, 0.5f, 1.0f );
491 GL_Bind(r_bloomscratchtexture->texnum);
492 R_Bloom_Quad( 0, viddef.height-BLOOM_SIZE, BLOOM_SIZE, BLOOM_SIZE );
493 qglColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
494 qglDisable( GL_BLEND );
495
496 } else { //downsample simple
497
498 qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, bloomeffectFBO);
499 qglBlitFramebufferEXT(0, 0, vid.width, vid.height, 0, 0, BLOOM_SIZE, BLOOM_SIZE,
500 GL_COLOR_BUFFER_BIT, GL_LINEAR);
501
502 }
503
504 // Blit the finished downsampled texture onto a second FBO. We end up with
505 // with two copies, which GenerateDiamonds will take advantage of.
506 qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, bloomscratchFBO);
507 qglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, bloomeffectFBO);
508 qglBlitFramebufferEXT(0, 0, BLOOM_SIZE, BLOOM_SIZE, 0, 0, BLOOM_SIZE, BLOOM_SIZE,
509 GL_COLOR_BUFFER_BIT, GL_NEAREST);
510
511 qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
512 qglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
513 }
514
515 /*
516 =================
517 R_BloomBlend
518 =================
519 */
R_BloomBlend(refdef_t * fd)520 void R_BloomBlend ( refdef_t *fd )
521 {
522
523 if( !(fd->rdflags & RDF_BLOOM) || !r_bloom->integer )
524 return;
525
526 if( !BLOOM_SIZE )
527 R_Bloom_InitTextures();
528
529 // previous function can set this if there's no FBO
530 if (!r_bloom->integer)
531 return;
532
533 if( screen_texture_width < BLOOM_SIZE ||
534 screen_texture_height < BLOOM_SIZE )
535 return;
536
537 //set up full screen workspace
538 qglViewport( 0, 0, viddef.width, viddef.height );
539 qglDisable( GL_DEPTH_TEST );
540 qglMatrixMode( GL_PROJECTION );
541 qglLoadIdentity ();
542 qglOrtho(0, viddef.width, viddef.height, 0, -10, 100);
543 qglMatrixMode( GL_MODELVIEW );
544 qglLoadIdentity ();
545 qglDisable(GL_CULL_FACE);
546
547 qglDisable( GL_BLEND );
548 qglEnable( GL_TEXTURE_2D );
549
550 qglColor4f( 1, 1, 1, 1 );
551
552 //set up current sizes
553 // TODO: get rid of these nasty globals
554 curView_x = fd->x;
555 curView_y = fd->y;
556 curView_width = fd->width;
557 curView_height = fd->height;
558
559 //create the bloom image
560 R_Bloom_DownsampleView();
561 R_Bloom_GeneratexDiamonds();
562
563 R_Bloom_DrawEffect();
564
565 qglColor3f (1,1,1);
566 qglDisable (GL_BLEND);
567 qglEnable (GL_TEXTURE_2D);
568 qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
569 qglDepthMask (1);
570 }
571
572