/*
Copyright (C) 1997-2001 Id Software, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/
// r_bloom.c: 2D lighting post process effect

#include "r_local.h"


/* 
============================================================================== 
 
						LIGHT BLOOMS
 
============================================================================== 
*/ 

static float Diamond8x[8][8] = { 
		0.0f, 0.0f, 0.0f, 0.1f, 0.1f, 0.0f, 0.0f, 0.0f, 
		0.0f, 0.0f, 0.2f, 0.3f, 0.3f, 0.2f, 0.0f, 0.0f, 
		0.0f, 0.2f, 0.4f, 0.6f, 0.6f, 0.4f, 0.2f, 0.0f, 
		0.1f, 0.3f, 0.6f, 0.9f, 0.9f, 0.6f, 0.3f, 0.1f, 
		0.1f, 0.3f, 0.6f, 0.9f, 0.9f, 0.6f, 0.3f, 0.1f, 
		0.0f, 0.2f, 0.4f, 0.6f, 0.6f, 0.4f, 0.2f, 0.0f, 
		0.0f, 0.0f, 0.2f, 0.3f, 0.3f, 0.2f, 0.0f, 0.0f, 
		0.0f, 0.0f, 0.0f, 0.1f, 0.1f, 0.0f, 0.0f, 0.0f };

static float Diamond6x[6][6] = { 
		0.0f, 0.0f, 0.1f, 0.1f, 0.0f, 0.0f, 
		0.0f, 0.3f, 0.5f, 0.5f, 0.3f, 0.0f,  
		0.1f, 0.5f, 0.9f, 0.9f, 0.5f, 0.1f, 
		0.1f, 0.5f, 0.9f, 0.9f, 0.5f, 0.1f, 
		0.0f, 0.3f, 0.5f, 0.5f, 0.3f, 0.0f, 
		0.0f, 0.0f, 0.1f, 0.1f, 0.0f, 0.0f };

static float Diamond4x[4][4] = {  
		0.3f, 0.4f, 0.4f, 0.3f,  
		0.4f, 0.9f, 0.9f, 0.4f, 
		0.4f, 0.9f, 0.9f, 0.4f, 
		0.3f, 0.4f, 0.4f, 0.3f };


static int		BLOOM_SIZE;

cvar_t		*r_bloom_alpha;
cvar_t		*r_bloom_diamond_size;
cvar_t		*r_bloom_intensity;
cvar_t		*r_bloom_threshold;
cvar_t		*r_bloom_darken;
cvar_t		*r_bloom_sample_size;
cvar_t		*r_bloom_fast_sample;

image_t		*r_bloomscreentexture;
image_t		*r_bloomeffecttexture;
image_t		*r_bloombackuptexture;
image_t		*r_bloomdownsamplingtexture;

static int		r_screendownsamplingtexture_size;
static int		screen_texture_width, screen_texture_height;
//static int		r_screenbackuptexture_size;
static int      r_screenbackuptexture_width, r_screenbackuptexture_height;

//current refdef size:
static int	curView_x;
static int	curView_y;
static int	curView_width;
static int	curView_height;

// texture coordinates of screen data inside screentexture
static float screenText_tcw;
static float screenText_tch;

static int	sample_width;
static int	sample_height;

// texture coordinates of adjusted textures
static float sampleText_tcw;
static float sampleText_tch;

// this macro is in sample size workspace coordinates
#define R_Bloom_DrawStart			\
	rb_vertex = rb_index = 0;

#define R_Bloom_DrawFinish			\
	RB_DrawArrays ();				\
	rb_vertex = rb_index = 0;

#define R_Bloom_SamplePass( xpos, ypos, r, g, b, a )								\
	indexArray[rb_index++] = rb_vertex+0;											\
	indexArray[rb_index++] = rb_vertex+1;											\
	indexArray[rb_index++] = rb_vertex+2;											\
	indexArray[rb_index++] = rb_vertex+0;											\
	indexArray[rb_index++] = rb_vertex+2;											\
	indexArray[rb_index++] = rb_vertex+3;											\
	VA_SetElem2(texCoordArray[0][rb_vertex], 0, sampleText_tch);					\
	VA_SetElem3(vertexArray[rb_vertex], xpos, ypos, 0);								\
	VA_SetElem4(colorArray[rb_vertex], r, g, b, a);									\
	rb_vertex++;																	\
	VA_SetElem2(texCoordArray[0][rb_vertex], 0, 0);									\
	VA_SetElem3(vertexArray[rb_vertex], xpos, ypos+sample_height, 0);				\
	VA_SetElem4(colorArray[rb_vertex], r, g, b, a);									\
	rb_vertex++;																	\
	VA_SetElem2(texCoordArray[0][rb_vertex], sampleText_tcw, 0);					\
	VA_SetElem3(vertexArray[rb_vertex], xpos+sample_width, ypos+sample_height, 0);	\
	VA_SetElem4(colorArray[rb_vertex], r, g, b, a);									\
	rb_vertex++;																	\
	VA_SetElem2(texCoordArray[0][rb_vertex], sampleText_tcw, sampleText_tch);		\
	VA_SetElem3(vertexArray[rb_vertex], xpos+sample_width, ypos, 0);				\
	VA_SetElem4(colorArray[rb_vertex], r, g, b, a);									\
	rb_vertex++;
	
#define R_Bloom_Quad( x, y, width, height, textwidth, textheight, r, g, b, a )	\
	rb_vertex = rb_index = 0;													\
	indexArray[rb_index++] = rb_vertex+0;										\
	indexArray[rb_index++] = rb_vertex+1;										\
	indexArray[rb_index++] = rb_vertex+2;										\
	indexArray[rb_index++] = rb_vertex+0;										\
	indexArray[rb_index++] = rb_vertex+2;										\
	indexArray[rb_index++] = rb_vertex+3;										\
	VA_SetElem2(texCoordArray[0][rb_vertex], 0, textheight);					\
	VA_SetElem3(vertexArray[rb_vertex],	x, y, 0);								\
	VA_SetElem4(colorArray[rb_vertex], r, g, b, a);								\
	rb_vertex++;																\
	VA_SetElem2(texCoordArray[0][rb_vertex], 0,	0);								\
	VA_SetElem3(vertexArray[rb_vertex], x, y+height, 0);						\
	VA_SetElem4(colorArray[rb_vertex], r, g, b, a);								\
	rb_vertex++;																\
	VA_SetElem2(texCoordArray[0][rb_vertex], textwidth,	0);						\
	VA_SetElem3(vertexArray[rb_vertex], x+width, y+height, 0);					\
	VA_SetElem4(colorArray[rb_vertex], r, g, b, a);								\
	rb_vertex++;																\
	VA_SetElem2(texCoordArray[0][rb_vertex], textwidth,	textheight);			\
	VA_SetElem3(vertexArray[rb_vertex], x+width, y, 0);							\
	VA_SetElem4(colorArray[rb_vertex], r, g, b, a);								\
	rb_vertex++;																\
	RB_DrawArrays ();															\
	rb_vertex = rb_index = 0;


/*
=================
R_Bloom_InitBackUpTexture
=================
*/
void R_Bloom_InitBackUpTexture (int width, int height)
{
	byte	*data;
	
	data = malloc( width * height * 4 );
	memset( data, 0, width * height * 4 );

//	r_screenbackuptexture_size = width;
	r_screenbackuptexture_width = width;
	r_screenbackuptexture_height = height; 

	r_bloombackuptexture = R_LoadPic( "***r_bloombackuptexture***", (byte *)data, width, height, it_pic, 3 );
	
	free ( data );
}

/*
=================
R_Bloom_InitEffectTexture
=================
*/
void R_Bloom_InitEffectTexture (void)
{
	byte	*data;
	float	bloomsizecheck;
	
	if( (int)r_bloom_sample_size->value < 32 )
		Cvar_SetValue ("r_bloom_sample_size", 32);

	//make sure bloom size is a power of 2
	BLOOM_SIZE = (int)r_bloom_sample_size->value;
	bloomsizecheck = (float)BLOOM_SIZE;
	while(bloomsizecheck > 1.0f) bloomsizecheck /= 2.0f;
	if( bloomsizecheck != 1.0f )
	{
		BLOOM_SIZE = 32;
		while( BLOOM_SIZE < (int)r_bloom_sample_size->value )
			BLOOM_SIZE *= 2;
	}

	//make sure bloom size doesn't have stupid values
	if( BLOOM_SIZE > screen_texture_width ||
		BLOOM_SIZE > screen_texture_height )
		BLOOM_SIZE = min( screen_texture_width, screen_texture_height );

	if( BLOOM_SIZE != (int)r_bloom_sample_size->value )
		Cvar_SetValue ("r_bloom_sample_size", BLOOM_SIZE);

	data = malloc( BLOOM_SIZE * BLOOM_SIZE * 4 );
	memset( data, 0, BLOOM_SIZE * BLOOM_SIZE * 4 );

	r_bloomeffecttexture = R_LoadPic( "***r_bloomeffecttexture***", (byte *)data, BLOOM_SIZE, BLOOM_SIZE, it_pic, 3 );
	
	free ( data );
}

/*
=================
R_Bloom_InitTextures
=================
*/
void R_Bloom_InitTextures (void)
{
	byte	*data;
	int		size;

	//find closer power of 2 to screen size 
	for (screen_texture_width = 1; screen_texture_width < vid.width; screen_texture_width *= 2);
	for (screen_texture_height = 1; screen_texture_height < vid.height; screen_texture_height *= 2);

	//disable blooms if we can't handle a texture of that size
/*	if( screen_texture_width > glConfig.maxTextureSize ||
		screen_texture_height > glConfig.maxTextureSize ) {
		screen_texture_width = screen_texture_height = 0;
		Cvar_SetValue ("r_bloom", 0);
		Com_Printf( "WARNING: 'R_InitBloomScreenTexture' too high resolution for Light Bloom. Effect disabled\n" );
		return;
	}*/

	//init the screen texture
	size = screen_texture_width * screen_texture_height * 4;
	data = malloc( size );
	memset( data, 255, size );
	r_bloomscreentexture = R_LoadPic( "***r_bloomscreentexture***", (byte *)data, screen_texture_width, screen_texture_height, it_pic, 3 );
	free ( data );

	//validate bloom size and init the bloom effect texture
	R_Bloom_InitEffectTexture ();

	//if screensize is more than 2x the bloom effect texture, set up for stepped downsampling
	r_bloomdownsamplingtexture = NULL;
	r_screendownsamplingtexture_size = 0;
	if( vid.width > (BLOOM_SIZE * 2) && !r_bloom_fast_sample->value )
	{
		r_screendownsamplingtexture_size = (int)(BLOOM_SIZE * 2);
		data = malloc( r_screendownsamplingtexture_size * r_screendownsamplingtexture_size * 4 );
		memset( data, 0, r_screendownsamplingtexture_size * r_screendownsamplingtexture_size * 4 );
		r_bloomdownsamplingtexture = R_LoadPic( "***r_bloomdownsamplingtexture***", (byte *)data, r_screendownsamplingtexture_size, r_screendownsamplingtexture_size, it_pic, 3 );
		free ( data );
	}

	//Init the screen backup texture
	if( r_screendownsamplingtexture_size )
		R_Bloom_InitBackUpTexture( r_screendownsamplingtexture_size, r_screendownsamplingtexture_size );
	else
		R_Bloom_InitBackUpTexture( BLOOM_SIZE, BLOOM_SIZE );
	
}

/*
=================
R_InitBloomTextures
=================
*/
void R_InitBloomTextures (void)
{

	//r_bloom = Cvar_Get( "r_bloom", "0", CVAR_ARCHIVE );
	r_bloom_alpha = Cvar_Get( "r_bloom_alpha", "0.25", CVAR_ARCHIVE );			// was 0.33
	r_bloom_diamond_size = Cvar_Get( "r_bloom_diamond_size", "8", CVAR_ARCHIVE );
	r_bloom_intensity = Cvar_Get( "r_bloom_intensity", "2.5", CVAR_ARCHIVE );	// was 0.6
	r_bloom_threshold = Cvar_Get( "r_bloom_threshold", "0.68", CVAR_ARCHIVE );	// was 0.08
	r_bloom_darken = Cvar_Get( "r_bloom_darken", "5", CVAR_ARCHIVE );			// was 4
	r_bloom_sample_size = Cvar_Get( "r_bloom_sample_size", "256", CVAR_ARCHIVE );	// was 128
	r_bloom_fast_sample = Cvar_Get( "r_bloom_fast_sample", "0", CVAR_ARCHIVE );

	BLOOM_SIZE = 0;
	if (!r_bloom->value)
		return;

	R_Bloom_InitTextures ();
}

 
/*
=================
R_Bloom_DrawEffect
=================
*/
void R_Bloom_DrawEffect (void)
{
	GL_Bind(r_bloomeffecttexture->texnum);  
	GL_Enable(GL_BLEND);
	GL_BlendFunc(GL_ONE, GL_ONE);
	GL_TexEnv(GL_MODULATE);

	rb_vertex = rb_index = 0;
	indexArray[rb_index++] = rb_vertex+0;
	indexArray[rb_index++] = rb_vertex+1;
	indexArray[rb_index++] = rb_vertex+2;
	indexArray[rb_index++] = rb_vertex+0;
	indexArray[rb_index++] = rb_vertex+2;
	indexArray[rb_index++] = rb_vertex+3;
	VA_SetElem2(texCoordArray[0][rb_vertex], 0, sampleText_tch);
	VA_SetElem3(vertexArray[rb_vertex],	curView_x, curView_y, 0);
	VA_SetElem4(colorArray[rb_vertex], r_bloom_alpha->value, r_bloom_alpha->value, r_bloom_alpha->value, 1.0f);
	rb_vertex++;
	VA_SetElem2(texCoordArray[0][rb_vertex], 0,	0);
	VA_SetElem3(vertexArray[rb_vertex], curView_x, curView_y + curView_height, 0);
	VA_SetElem4(colorArray[rb_vertex], r_bloom_alpha->value, r_bloom_alpha->value, r_bloom_alpha->value, 1.0f);
	rb_vertex++;
	VA_SetElem2(texCoordArray[0][rb_vertex], sampleText_tcw, 0);
	VA_SetElem3(vertexArray[rb_vertex], curView_x + curView_width, curView_y + curView_height, 0);
	VA_SetElem4(colorArray[rb_vertex], r_bloom_alpha->value, r_bloom_alpha->value, r_bloom_alpha->value, 1.0f);
	rb_vertex++;
	VA_SetElem2(texCoordArray[0][rb_vertex], sampleText_tcw, sampleText_tch);
	VA_SetElem3(vertexArray[rb_vertex], curView_x + curView_width, curView_y, 0);
	VA_SetElem4(colorArray[rb_vertex], r_bloom_alpha->value, r_bloom_alpha->value, r_bloom_alpha->value, 1.0f);
	rb_vertex++;
	RB_DrawArrays ();
	rb_vertex = rb_index = 0;

	GL_Disable (GL_BLEND);
}


#if 0
/*
=================
R_Bloom_GeneratexCross - alternative bluring method
=================
*/
void R_Bloom_GeneratexCross (void)
{
	int				i;
	static int		BLOOM_BLUR_RADIUS = 8;
	//static float	BLOOM_BLUR_INTENSITY = 2.5f;
	float			BLOOM_BLUR_INTENSITY;
	static float	intensity;
	static float	range;

	// set up sample size workspace
	qglViewport( 0, 0, sample_width, sample_height );
	qglMatrixMode( GL_PROJECTION );
    qglLoadIdentity ();
	qglOrtho(0, sample_width, sample_height, 0, -10, 100);
	qglMatrixMode( GL_MODELVIEW );
    qglLoadIdentity ();

	// copy small scene into r_bloomeffecttexture
	GL_Bind(0, r_bloomeffecttexture);
	qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height);

	// start modifying the small scene corner
	GL_Enable(GL_BLEND);

	// darkening passes
	if (r_bloom_darken->value)
	{
		GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
		GL_TexEnv(GL_MODULATE);

		R_Bloom_DrawStart
		for(i=0; i<r_bloom_darken->value ;i++) {
			R_Bloom_SamplePass( 0, 0, 1.0f, 1.0f, 1.0f, 1.0f );
		}
		R_Bloom_DrawFinish
		qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height);
	}

	// bluring passes
	if ( BLOOM_BLUR_RADIUS )
	{
		
		GL_BlendFunc(GL_ONE, GL_ONE);

		range = (float)BLOOM_BLUR_RADIUS;

		BLOOM_BLUR_INTENSITY = r_bloom_intensity->value;
		//diagonal-cross draw 4 passes to add initial smooth
		R_Bloom_DrawStart
		R_Bloom_SamplePass( 1, 1, 0.5f, 0.5f, 0.5f, 1.0 );
		R_Bloom_SamplePass( -1, 1, 0.5f, 0.5f, 0.5f, 1.0 );
		R_Bloom_SamplePass( -1, -1, 0.5f, 0.5f, 0.5f, 1.0 );
		R_Bloom_SamplePass( 1, -1, 0.5f, 0.5f, 0.5f, 1.0 );
		R_Bloom_DrawFinish
		qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height);

		R_Bloom_DrawStart
		for(i=-(BLOOM_BLUR_RADIUS+1);i<BLOOM_BLUR_RADIUS;i++) {
			intensity = BLOOM_BLUR_INTENSITY/(range*2+1)*(1 - fabs(i*i)/(float)(range*range));
			if( intensity < 0.05f ) continue;
			R_Bloom_SamplePass( i, 0, intensity, intensity, intensity, 1.0f );
			//R_Bloom_SamplePass( -i, 0 );
		}
		R_Bloom_DrawFinish

		qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height);

		R_Bloom_DrawStart
		//for(i=0;i<BLOOM_BLUR_RADIUS;i++) {
		for(i=-(BLOOM_BLUR_RADIUS+1);i<BLOOM_BLUR_RADIUS;i++) {
			intensity = BLOOM_BLUR_INTENSITY/(range*2+1)*(1 - fabs(i*i)/(float)(range*range));
			if( intensity < 0.05f ) continue;
			R_Bloom_SamplePass( 0, i, intensity, intensity, intensity, 1.0f );
			//R_Bloom_SamplePass( 0, -i );
		}
		R_Bloom_DrawFinish

		qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height);
	}
	
	// restore full screen workspace
	qglViewport( 0, 0, glState.width, glState.height );
	qglMatrixMode( GL_PROJECTION );
    qglLoadIdentity ();
	qglOrtho(0, glState.width, glState.height, 0, -10, 100);
	qglMatrixMode( GL_MODELVIEW );
    qglLoadIdentity ();
}
#endif


/*
=================
R_Bloom_GeneratexDiamonds
=================
*/
void R_Bloom_GeneratexDiamonds (void)
{
	int				i, j;
	static float	intensity;

	// set up sample size workspace
	qglViewport( 0, 0, sample_width, sample_height );
	qglMatrixMode( GL_PROJECTION );
    qglLoadIdentity ();
	qglOrtho(0, sample_width, sample_height, 0, -10, 100);
	qglMatrixMode( GL_MODELVIEW );
    qglLoadIdentity ();

	// copy small scene into r_bloomeffecttexture
	GL_Bind(r_bloomeffecttexture->texnum);
	qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height);

	// start modifying the small scene corner
	GL_Enable(GL_BLEND);

	// darkening passes
	if ( r_bloom_darken->value )
	{
		GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
		GL_TexEnv(GL_MODULATE);
		
		R_Bloom_DrawStart
		for (i=0; i<r_bloom_darken->value; i++) {
			R_Bloom_SamplePass( 0, 0, 1.0f, 1.0f, 1.0f, 1.0f );
		}
		R_Bloom_DrawFinish
		qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height);
	}

	// bluring passes
	// GL_BlendFunc(GL_ONE, GL_ONE);
	GL_BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
	
	if ( r_bloom_diamond_size->value > 7 || r_bloom_diamond_size->value <= 3)
	{
		if ( (int)r_bloom_diamond_size->value != 8 ) Cvar_SetValue( "r_bloom_diamond_size", 8 );

		R_Bloom_DrawStart
		for (i=0; i<r_bloom_diamond_size->value; i++) {
			for (j=0; j<r_bloom_diamond_size->value; j++) {
				intensity = r_bloom_intensity->value * 0.3 * Diamond8x[i][j];
				if ( intensity < r_bloom_threshold->value ) continue;
				R_Bloom_SamplePass( i-4, j-4, intensity, intensity, intensity, 1.0 );
			}
		}
		R_Bloom_DrawFinish			
	}
	else if ( r_bloom_diamond_size->value > 5 )
	{
		if ( r_bloom_diamond_size->value != 6 ) Cvar_SetValue( "r_bloom_diamond_size", 6 );

		R_Bloom_DrawStart
		for (i=0; i<r_bloom_diamond_size->value; i++) {
			for (j=0; j<r_bloom_diamond_size->value; j++) {
				intensity = r_bloom_intensity->value * 0.5 * Diamond6x[i][j];
				if ( intensity < r_bloom_threshold->value ) continue;
				R_Bloom_SamplePass( i-3, j-3, intensity, intensity, intensity, 1.0 );
			}
		}
		R_Bloom_DrawFinish			
	}
	else if ( r_bloom_diamond_size->value > 3 )
	{
		if ( (int)r_bloom_diamond_size->value != 4 ) Cvar_SetValue( "r_bloom_diamond_size", 4 );

		R_Bloom_DrawStart
		for (i=0; i<r_bloom_diamond_size->value; i++) {
			for (j=0; j<r_bloom_diamond_size->value; j++) {
				intensity = r_bloom_intensity->value * 0.8f * Diamond4x[i][j];
				if ( intensity < r_bloom_threshold->value ) continue;
				R_Bloom_SamplePass( i-2, j-2, intensity, intensity, intensity, 1.0 );
			}
		}
		R_Bloom_DrawFinish			
	}
	
	qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height);

	//restore full screen workspace
	qglViewport( 0, 0, vid.width, vid.height );
	qglMatrixMode( GL_PROJECTION );
    qglLoadIdentity ();
	qglOrtho(0, vid.width, vid.height, 0, -10, 100);
	qglMatrixMode( GL_MODELVIEW );
    qglLoadIdentity ();
}											

/*
=================
R_Bloom_DownsampleView
=================
*/
void R_Bloom_DownsampleView (void)
{
	GL_Disable( GL_BLEND );

	// stepped downsample
	if ( r_screendownsamplingtexture_size )
	{
		int		midsample_width = r_screendownsamplingtexture_size * sampleText_tcw;
		int		midsample_height = r_screendownsamplingtexture_size * sampleText_tch;
		
		// copy the screen and draw resized
		GL_Bind(r_bloomscreentexture->texnum);
		qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, curView_x, vid.height - (curView_y + curView_height), curView_width, curView_height);
		R_Bloom_Quad( 0,  vid.height-midsample_height, midsample_width, midsample_height, screenText_tcw, screenText_tch,  1.0f, 1.0f, 1.0f, 1.0f );
		
		// now copy into Downsampling (mid-sized) texture
		GL_Bind(r_bloomdownsamplingtexture->texnum);
		qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, midsample_width, midsample_height);

		// now draw again in bloom size
		R_Bloom_Quad( 0,  vid.height-sample_height, sample_width, sample_height, sampleText_tcw, sampleText_tch, 0.5f, 0.5f, 0.5f, 1.0f );
		
		// now blend the big screen texture into the bloom generation space (hoping it adds some blur)
		GL_Enable( GL_BLEND );
		GL_BlendFunc(GL_ONE, GL_ONE);
		GL_Bind(r_bloomscreentexture->texnum);
		R_Bloom_Quad( 0,  vid.height-sample_height, sample_width, sample_height, screenText_tcw, screenText_tch, 0.5f, 0.5f, 0.5f, 1.0f );
		GL_Disable( GL_BLEND );

	}
	else // downsample simple
	{	
		GL_Bind(r_bloomscreentexture->texnum);
		qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, curView_x, vid.height - (curView_y + curView_height), curView_width, curView_height);
		R_Bloom_Quad( 0, vid.height-sample_height, sample_width, sample_height, screenText_tcw, screenText_tch, 1.0f, 1.0f, 1.0f, 1.0f );
	}
}

/*
=================
R_BloomBlend
=================
*/
void R_SetupGL (void);
void R_BloomBlend ( refdef_t *fd )
{
	if ( (fd->rdflags & RDF_NOWORLDMODEL) || !r_bloom->value || r_showtris->value )
		return;

	if ( !BLOOM_SIZE )
		R_Bloom_InitTextures();

	if ( screen_texture_width < BLOOM_SIZE ||
		screen_texture_height < BLOOM_SIZE )
		return;
	
	// set up full screen workspace
	qglViewport ( 0, 0, vid.width, vid.height );
	GL_TexEnv (GL_REPLACE); // Knightmare added
	GL_Disable (GL_DEPTH_TEST);
	qglMatrixMode (GL_PROJECTION);
    qglLoadIdentity ();
	qglOrtho(0, vid.width, vid.height, 0, -10, 100);
	qglMatrixMode (GL_MODELVIEW);
    qglLoadIdentity ();
	GL_Disable (GL_CULL_FACE);

	GL_Disable (GL_BLEND);
	GL_EnableTexture (0);

	// set up current sizes
	curView_x = fd->x;
	curView_y = fd->y;
	curView_width = fd->width;
	curView_height = fd->height;
	screenText_tcw = ((float)fd->width / (float)screen_texture_width);
	screenText_tch = ((float)fd->height / (float)screen_texture_height);
	if ( fd->height > fd->width ) {
		sampleText_tcw = ((float)fd->width / (float)fd->height);
		sampleText_tch = 1.0f;
	} else {
		sampleText_tcw = 1.0f;
		sampleText_tch = ((float)fd->height / (float)fd->width);
	}
	sample_width = BLOOM_SIZE * sampleText_tcw;
	sample_height = BLOOM_SIZE * sampleText_tch;
	
	// copy the screen space we'll use to work into the backup texture
	GL_Bind(r_bloombackuptexture->texnum);
//	qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, r_screenbackuptexture_size * sampleText_tcw, r_screenbackuptexture_size * sampleText_tch);
	qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, r_screenbackuptexture_width, r_screenbackuptexture_height);

	// create the bloom image
	R_Bloom_DownsampleView();
	R_Bloom_GeneratexDiamonds();
	//R_Bloom_GeneratexCross();

	// restore the screen-backup to the screen
	GL_Disable(GL_BLEND);
	GL_Bind(r_bloombackuptexture->texnum);
	/*R_Bloom_Quad( 0, 
		vid.height - (r_screenbackuptexture_size * sampleText_tch),
		r_screenbackuptexture_size * sampleText_tcw,
		r_screenbackuptexture_size * sampleText_tch,
		sampleText_tcw,
		sampleText_tch, 1, 1, 1, 1 );*/
	R_Bloom_Quad( 0, vid.height - r_screenbackuptexture_height,
		r_screenbackuptexture_width,
		r_screenbackuptexture_height, 1.0, 1.0, 1, 1, 1, 1 );

	R_Bloom_DrawEffect();

	// Knightmare added
	R_SetupGL ();
	GL_BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	GL_EnableTexture (0);
	//qglColor4f(1,1,1,1);
}
