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