Not to my knowledge ?, i adapted the bloom code from kmquake2 cant remember if i ever used a version that relied on glReadPixels but i cant rule it out.
Its been some years since i last had a look at this code. Early versions might have used the glare code from tenebrae so in that case yes but i since moved on cause it was to freaking slow. Atm the it seems to use a lot of time inside Sys_DoubleTime not sure why it calls this function like 1000 times a frame but even stranger that it causes the engine to stall as much as it does the first 50 or so frames. After that it settles and runs fine, but definatly something i need to to look after a fix for.
I also started cutting down some fat on checking for leafs since i noticed i had quite a few superflous checks in place where they where not needed, the original code allready did a better job at that so total timewaster on my side. Doing that helped a bit but it still stalls a little.
The bloom code uses matrix operations but could have been better written, it does the job ok though (maybe a bit over the top at times) as i have it in my demonquake engine as well and im not suffering any slowdowns with that one so i guess i can rule out bloom to be the culprit here.
Code: Select all
/*
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
//http://www.quakesrc.org/forums/viewtopic.php?t=4340&start=0
#include "gl_state.h"
#include "glquake.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 = {"r_bloom", "1"};
cvar_t r_bloom_alpha = {"r_bloom_alpha", "0.2"};
cvar_t r_bloom_diamond_size = {"r_bloom_diamond_size", "8"};
cvar_t r_bloom_intensity = {"r_bloom_intensity", "2"};
cvar_t r_bloom_darken = {"r_bloom_darken", "4"};
cvar_t r_bloom_sample_size = {"r_bloom_sample_size", "32"};
cvar_t r_bloom_fast_sample = {"r_bloom_fast_sample", "0"};
static int r_bloomscreentexture;
static int r_bloomeffecttexture;
static int r_bloombackuptexture;
static int r_bloomdownsamplingtexture;
static int r_screendownsamplingtexture_size;
static int screen_texture_width, screen_texture_height;
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_SamplePass( xpos, ypos, r, g, b, a ) \
glColor4f( r, g, b, a ); \
glBegin(GL_QUADS); \
glTexCoord2f( 0, sampleText_tch); \
glVertex2f( xpos, ypos); \
glTexCoord2f( 0, 0); \
glVertex2f( xpos, ypos+sample_height); \
glTexCoord2f( sampleText_tcw, 0); \
glVertex2f( xpos+sample_width, ypos+sample_height); \
glTexCoord2f( sampleText_tcw, sampleText_tch); \
glVertex2f( xpos+sample_width, ypos); \
glEnd();
#define R_Bloom_Quad( x, y, width, height, textwidth, textheight, r, g, b, a ) \
glColor4f( r, g, b, a ); \
glBegin(GL_QUADS); \
glTexCoord2f( 0, textheight); \
glVertex2f( x, y); \
glTexCoord2f( 0, 0); \
glVertex2f( x, y+height); \
glTexCoord2f( textwidth, 0); \
glVertex2f( x+width, y+height); \
glTexCoord2f( textwidth, textheight); \
glVertex2f( x+width, y); \
glEnd();
/*
=================
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_width = width;
r_screenbackuptexture_height = height;
r_bloombackuptexture = GL_UploadTextureToOpenGL(data, width, height, TEX_NOCOMPRESS);
free(data);
}
/*
=================
R_Bloom_InitEffectTexture
=================
*/
void R_Bloom_InitEffectTexture(void)
{
byte *data;
float bloomsizecheck;
if(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 < 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 != 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 = GL_UploadTextureToOpenGL(data, BLOOM_SIZE, BLOOM_SIZE, TEX_NOCOMPRESS);
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 < glwidth; screen_texture_width *= 2);
for(screen_texture_height = 1; screen_texture_height < glheight; screen_texture_height *= 2);
//init the screen texture
size = screen_texture_width * screen_texture_height * 4;
data = malloc(size);
memset(data, 255, size);
r_bloomscreentexture = GL_UploadTextureToOpenGL(data, screen_texture_width, screen_texture_height, TEX_NOCOMPRESS);
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 = 0;
r_screendownsamplingtexture_size = 0;
if(glwidth > (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 = GL_UploadTextureToOpenGL(data, r_screendownsamplingtexture_size, r_screendownsamplingtexture_size, TEX_NOCOMPRESS);
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)
{
Cvar_RegisterVariable(&r_bloom);
Cvar_RegisterVariable(&r_bloom_alpha);
Cvar_RegisterVariable(&r_bloom_diamond_size);
Cvar_RegisterVariable(&r_bloom_intensity);
Cvar_RegisterVariable(&r_bloom_darken);
Cvar_RegisterVariable(&r_bloom_sample_size);
Cvar_RegisterVariable(&r_bloom_fast_sample);
BLOOM_SIZE = 0;
if(r_bloom.value)
{
r_bloomscreentexture = 0; //this came from a vid_restart, where none of the textures are valid any more.
R_Bloom_InitTextures();
}
}
/*
=================
R_Bloom_DrawEffect
=================
*/
void R_Bloom_DrawEffect(void)
{
glBindTexture(GL_TEXTURE_2D, r_bloomeffecttexture);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glColor4f(r_bloom_alpha.value, r_bloom_alpha.value, r_bloom_alpha.value, 1.0f);
glBegin(GL_QUADS);
glTexCoord2f(0, sampleText_tch);
glVertex2f(curView_x, curView_y);
glTexCoord2f(0, 0);
glVertex2f(curView_x, curView_y + curView_height);
glTexCoord2f(sampleText_tcw, 0);
glVertex2f(curView_x + curView_width, curView_y + curView_height);
glTexCoord2f(sampleText_tcw, sampleText_tch);
glVertex2f(curView_x + curView_width, curView_y);
glEnd();
glDisable(GL_BLEND);
}
/*
=================
R_Bloom_GeneratexDiamonds
=================
*/
void R_Bloom_GeneratexDiamonds(void)
{
int i, j;
static float intensity;
//set up sample size workspace
glViewport(0, 0, sample_width, sample_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, sample_width, sample_height, 0, -10, 100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//copy small scene into r_bloomeffecttexture
glBindTexture(GL_TEXTURE_2D, r_bloomeffecttexture);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height);
//start modifying the small scene corner
glEnable(GL_BLEND);
//darkening passes
if(r_bloom_darken.value)
{
glBlendFunc(GL_DST_COLOR, GL_ZERO);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
for(i = 0; i < r_bloom_darken.value ; i++)
{
R_Bloom_SamplePass(0, 0, 1.0f, 1.0f, 1.0f, 1.0f);
}
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height);
}
//bluring passes
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
if(r_bloom_diamond_size.value > 7 || r_bloom_diamond_size.value <= 3)
{
if(r_bloom_diamond_size.value != 8)
{
Cvar_SetValue("r_bloom_diamond_size", 8);
}
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 < 0.01f)
{
continue;
}
R_Bloom_SamplePass(i - 4, j - 4, intensity, intensity, intensity, 1.0);
}
}
}
else if(r_bloom_diamond_size.value > 5)
{
if(r_bloom_diamond_size.value != 6)
{
Cvar_SetValue("r_bloom_diamond_size", 6);
}
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 < 0.01f)
{
continue;
}
R_Bloom_SamplePass(i - 3, j - 3, intensity, intensity, intensity, 1.0);
}
}
}
else if(r_bloom_diamond_size.value > 3)
{
if(r_bloom_diamond_size.value != 4)
{
Cvar_SetValue("r_bloom_diamond_size", 4);
}
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 < 0.01f)
{
continue;
}
R_Bloom_SamplePass(i - 2, j - 2, intensity, intensity, intensity, 1.0);
}
}
}
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height);
//restore full screen workspace
glViewport(0, 0, glwidth, glheight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, glwidth, glheight, 0, -10, 100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
/*
=================
R_Bloom_DownsampleView
=================
*/
void R_Bloom_DownsampleView(void)
{
glDisable(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
glBindTexture(GL_TEXTURE_2D, r_bloomscreentexture);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, curView_x, glheight - (curView_y + curView_height), curView_width, curView_height);
R_Bloom_Quad(0, glheight - 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
glBindTexture(GL_TEXTURE_2D, r_bloomdownsamplingtexture);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, midsample_width, midsample_height);
//now draw again in bloom size
R_Bloom_Quad(0, glheight - 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)
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glBindTexture(GL_TEXTURE_2D, r_bloomscreentexture);
R_Bloom_Quad(0, glheight - sample_height, sample_width, sample_height, screenText_tcw, screenText_tch, 0.5f, 0.5f, 0.5f, 1.0f);
glDisable(GL_BLEND);
}
else
{
//downsample simple
glBindTexture(GL_TEXTURE_2D, r_bloomscreentexture);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, curView_x, glheight - (curView_y + curView_height), curView_width, curView_height);
R_Bloom_Quad(0, glheight - sample_height, sample_width, sample_height, screenText_tcw, screenText_tch, 1.0f, 1.0f, 1.0f, 1.0f);
}
}
/*
=================
R_BloomBlend
=================
*/
void R_BloomBlend(void)
{
// skip if no lightdata etc.
if(!r_bloom.value || !r_worldentity.model || !cl.worldmodel || !cl.worldmodel->lightdata)
{
return;
}
if(!BLOOM_SIZE || screen_texture_width < glwidth || screen_texture_height < glheight)
{
R_Bloom_InitTextures();
}
if(screen_texture_width < BLOOM_SIZE || screen_texture_height < BLOOM_SIZE)
{
return;
}
//set up full screen workspace
glViewport(0, 0, glwidth, glheight);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, glwidth, glheight, 0, -10, 100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDisable(GL_CULL_FACE);
glDisable(GL_BLEND);
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
//set up current sizes
curView_x = scr_vrect.x * ((float)glwidth / vid.width);
curView_y = scr_vrect.y * ((float)glheight / vid.height);
curView_width = scr_vrect.width * ((float)glwidth / vid.width);
curView_height = scr_vrect.height * ((float)glheight / vid.height);
screenText_tcw = ((float)curView_width / (float)screen_texture_width);
screenText_tch = ((float)curView_height / (float)screen_texture_height);
if(scr_vrect.height > scr_vrect.width)
{
sampleText_tcw = ((float)scr_vrect.width / (float)scr_vrect.height);
sampleText_tch = 1.0f;
}
else
{
sampleText_tcw = 1.0f;
sampleText_tch = ((float)scr_vrect.height / (float)scr_vrect.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
glBindTexture(GL_TEXTURE_2D, r_bloombackuptexture);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, r_screenbackuptexture_width, r_screenbackuptexture_height);
//create the bloom image
R_Bloom_DownsampleView();
R_Bloom_GeneratexDiamonds();
//restore the screen-backup to the screen
glDisable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, r_bloombackuptexture);
R_Bloom_Quad(0, glheight - r_screenbackuptexture_height, r_screenbackuptexture_width, r_screenbackuptexture_height, 1.0, 1.0, 1, 1, 1, 1);
R_Bloom_DrawEffect();
R_SetupGL();
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
}
Probably a better way to write this one (GLSL). Also its quite messy :/