fix nq bob (also fixes show_speed in nq)

tweaked waterwarp+bloom to use fbos. this fixes any issues with viewsize 10 or whatever, but depends upon npot.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4727 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2014-08-19 06:08:23 +00:00
parent 23b7a15980
commit 54c0810d41
11 changed files with 183 additions and 665 deletions

View File

@ -1561,7 +1561,7 @@ void CL_SendCmd (double frametime, qboolean mainloop)
CL_ProxyMenuHooks();
if (cls.demoplayback != DPB_NONE)
if (cls.demoplayback != DPB_NONE || cls.netchan.remote_address.type == NA_INVALID)
{
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
{

View File

@ -3373,6 +3373,7 @@ Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);
void CLNQ_ParseClientdata (void)
{
int i;
player_state_t *pl = &cl.inframes[cl.validsequence&UPDATE_MASK].playerstate[cl.playerview[0].playernum];
unsigned int bits;
@ -3393,7 +3394,6 @@ void CLNQ_ParseClientdata (void)
/*else
cl.idealpitch = 0;*/
// VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
for (i=0 ; i<3 ; i++)
{
if (bits & (SU_PUNCH1<<i) )
@ -3408,21 +3408,21 @@ void CLNQ_ParseClientdata (void)
// else
// cl.punchvector[i] = 0;
if (bits & (SU_VELOCITY1<<i) )
if (bits & (SU_VELOCITY1<<i))
{
if (CPNQ_IS_DP)
/*cl.simvel[0][i] =*/ MSG_ReadFloat();
pl->velocity[i] = MSG_ReadFloat();
else
/*cl.mvelocity[0][i] =*/ MSG_ReadChar()/**16*/;
pl->velocity[i] = MSG_ReadChar()*16;
}
// else
// cl.mvelocity[0][i] = 0;
else
pl->velocity[i] = 0;
}
if ((bits & SU_ITEMS) || cls.protocol_nq == CPNQ_ID) //hipnotic bug - hipnotic demos don't always have SU_ITEMS set, yet they update STAT_ITEMS anyway.
CL_SetStatInt(0, STAT_ITEMS, MSG_ReadLong());
// cl.onground = (bits & SU_ONGROUND) != 0;
pl->onground = (bits & SU_ONGROUND) != 0;
// cl.inwater = (bits & SU_INWATER) != 0;
if (cls.protocol_nq == CPNQ_DP5)

View File

@ -699,6 +699,9 @@ static void CL_EntStateToPlayerState(player_state_t *plstate, entity_state_t *st
{
vec3_t a;
int pmtype;
qboolean onground = plstate->onground;
vec3_t vel;
VectorCopy(plstate->velocity, vel);
memset(plstate, 0, sizeof(*plstate));
switch(state->u.q1.pmovetype)
{
@ -732,7 +735,13 @@ static void CL_EntStateToPlayerState(player_state_t *plstate, entity_state_t *st
plstate->pm_type = pmtype;
VectorCopy(state->origin, plstate->origin);
VectorScale(state->u.q1.velocity, 1/8.0, plstate->velocity);
if (cls.protocol == CP_NETQUAKE && !(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS))
{ //nq is annoying, this stuff wasn't part of the entity state, so don't break it
VectorCopy(vel, plstate->velocity);
plstate->onground = onground;
}
else
VectorScale(state->u.q1.velocity, 1/8.0, plstate->velocity);
VectorCopy(state->angles, plstate->viewangles);
plstate->viewangles[0] *= -3;
@ -1178,7 +1187,10 @@ void CL_PredictMovePNum (int seat)
}
}
}
CL_CatagorizePosition(pv, tostate->origin);
if (cls.protocol == CP_NETQUAKE && nopred)
pv->onground = tostate->onground;
else
CL_CatagorizePosition(pv, tostate->origin);
if (le)
{

View File

@ -1301,9 +1301,9 @@ texid_t R2D_RT_Configure(const char *id, int width, int height, uploadfmt_t rtfm
}
else
{
tid = R_FindTexture(id, IF_NOMIPMAP);
tid = R_FindTexture(id, IF_NOMIPMAP|IF_CLAMP|IF_LINEAR);
if (!TEXVALID(tid))
tid = R_AllocNewTexture(id, 0, 0, IF_NOMIPMAP);
tid = R_AllocNewTexture(id, 0, 0, IF_NOMIPMAP|IF_CLAMP|IF_LINEAR);
}
if (rtfmt)
{
@ -1317,7 +1317,7 @@ texid_t R2D_RT_Configure(const char *id, int width, int height, uploadfmt_t rtfm
case 6: rtfmt = TF_DEPTH32; break;
default:rtfmt = TF_INVALID; break;
}
R_Upload(tid, id, rtfmt, NULL, NULL, width, height, IF_NOMIPMAP);
R_Upload(tid, id, rtfmt, NULL, NULL, width, height, IF_NOMIPMAP|IF_CLAMP|IF_LINEAR);
tid.ref->width = width;
tid.ref->height = height;
}

View File

@ -1986,6 +1986,9 @@ void Surf_SetupFrame(void)
mleaf_t *leaf;
vec3_t temp, pvsorg;
if (!cl.worldmodel || (!cl.worldmodel->nodes && cl.worldmodel->type != mod_heightmap))
r_refdef.flags |= RDF_NOWORLDMODEL;
R_AnimateLight();
r_framecount++;

View File

@ -1153,13 +1153,19 @@ typedef struct q1usercmd_s
#define RF_FORCECOLOURMOD (1u<<22) //forces BEF_FORCECOLOURMOD
// player_state_t->refdef flags
#define Q2RDF_UNDERWATER 1 // warp the screen as apropriate
#define RDF_NOWORLDMODEL 2 // used for player configuration screen
#define RDF_UNDERWATER (1u<<0) // warp the screen as apropriate (fov trick)
#define RDF_NOWORLDMODEL (1u<<1) // used for player configuration screen
//ROGUE
#define Q2RDF_IRGOGGLES (1u<<2) //ents with Q2RF_IR_VISIBLE show up pure red.
#define Q2RDF_UVGOGGLES (1u<<3) //usused / reserved
//ROGUE
#define RDF_BLOOM (1u<<16)
#define RDF_FISHEYE (1u<<17)
#define RDF_WATERWARP (1u<<18)
#define RDF_CUSTOMPOSTPROC (1u<<19)
#define RDF_ALLPOSTPROC (RDF_BLOOM|RDF_FISHEYE|RDF_WATERWARP|RDF_CUSTOMPOSTPROC) //these flags require rendering to an fbo for the various different post-processing shaders.
//ROGUE
#define Q2RDF_IRGOGGLES 4 //ents with Q2RF_IR_VISIBLE show up pure red.
#define Q2RDF_UVGOGGLES 8 //usused / reserved
//ROGUE

View File

@ -53,7 +53,6 @@ static shader_t *bloomblur;
static shader_t *bloomfinal;
#define MAXLEVELS 3
texid_t scrtex;
texid_t pingtex[2][MAXLEVELS];
fbostate_t fbo_bloom;
static int scrwidth, scrheight;
@ -69,7 +68,6 @@ static void R_InitBloomTextures(void)
bloomfinal = NULL;
scrwidth = 0, scrheight = 0;
scrtex = r_nulltex;
for (i = 0; i < MAXLEVELS; i++)
{
pingtex[0][i] = r_nulltex;
@ -108,17 +106,6 @@ static void R_SetupBloomTextures(int w, int h)
texheight[i] = h;
}
/*we should be doing this outside of this code*/
if (!TEXVALID(scrtex))
scrtex = GL_AllocNewTexture("", scrwidth, scrheight, IF_NOMIPMAP|IF_NOPICMIP);
GL_MTBind(0, GL_TEXTURE_2D, scrtex);
qglTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, scrwidth, scrheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
/*top level uses nearest sampling*/
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
/*now create textures for each level*/
for (j = 0; j < MAXLEVELS; j++)
{
@ -127,7 +114,7 @@ static void R_SetupBloomTextures(int w, int h)
if (!TEXVALID(pingtex[i][j]))
{
sprintf(name, "***bloom*%c*%i***", 'a'+i, j);
TEXASSIGN(pingtex[i][j], GL_AllocNewTexture(name, texwidth[j], texheight[j], IF_NOMIPMAP|IF_NOPICMIP));
TEXASSIGN(pingtex[i][j], GL_AllocNewTexture(name, texwidth[j], texheight[j], IF_NOMIPMAP|IF_NOPICMIP|IF_LINEAR));
}
GL_MTBind(0, GL_TEXTURE_2D, pingtex[i][j]);
qglTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, texwidth[j], texheight[j], 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
@ -185,30 +172,31 @@ static void R_SetupBloomTextures(int w, int h)
bloomfinal->defaulttextures.loweroverlay = pingtex[0][1];
bloomfinal->defaulttextures.upperoverlay = pingtex[0][2];
}
void R_BloomBlend (void)
qboolean R_CanBloom(void)
{
if (!r_bloom.value)
return false;
if (!gl_config.ext_framebuffer_objects)
return false;
if (!gl_config.arb_shader_objects)
return false;
if (!r_config.texture_non_power_of_two)
return false;
return true;
}
void R_BloomBlend (texid_t source, int x, int y, int w, int h)
{
int i;
int oldfbo = 0;
if (!gl_config.ext_framebuffer_objects)
return;
if (!gl_config.arb_shader_objects)
return;
if (!r_config.texture_non_power_of_two)
return;
/*whu?*/
if (!r_refdef.pxrect.width || !r_refdef.pxrect.height)
if (!w || !h)
return;
/*update textures if we need to resize them*/
R_SetupBloomTextures(r_refdef.pxrect.width, r_refdef.pxrect.height);
/*grab the screen, because we failed to do it earlier*/
GL_MTBind(0, GL_TEXTURE_2D, scrtex);
qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.pxrect.x, r_refdef.pxrect.maxheight - (r_refdef.pxrect.y+r_refdef.pxrect.height), r_refdef.pxrect.width, r_refdef.pxrect.height);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
R_SetupBloomTextures(w, h);
for (i = 0; i < MAXLEVELS; i++)
{
@ -216,7 +204,7 @@ void R_BloomBlend (void)
{
/*filter the screen into a downscaled image*/
oldfbo = GLBE_FBO_Update(&fbo_bloom, 0, &pingtex[0][0], 1, r_nulltex, 0, 0);
GLBE_FBO_Sources(scrtex, r_nulltex);
GLBE_FBO_Sources(source, r_nulltex);
qglViewport (0, 0, texwidth[0], texheight[0]);
R2D_ScalePic(0, vid.height, vid.width, -(int)vid.height, bloomfilter);
}
@ -256,8 +244,8 @@ void R_BloomBlend (void)
/*combine them onto the screen*/
GLBE_FBO_Pop(oldfbo);
GLBE_FBO_Sources(scrtex, r_nulltex);
R2D_ScalePic(r_refdef.vrect.x, r_refdef.vrect.y + r_refdef.vrect.height, r_refdef.vrect.width, -r_refdef.vrect.height, bloomfinal);
GLBE_FBO_Sources(source, r_nulltex);
R2D_ScalePic(x, y + h, w, -h, bloomfinal);
}
void R_BloomShutdown(void)
{
@ -266,562 +254,4 @@ void R_BloomShutdown(void)
R_InitBloomTextures();
}
#elif defined(GLQUAKE)
#include "glquake.h"
/*
==============================================================================
LIGHT BLOOMS
==============================================================================
*/
cvar_t r_bloom = CVARAFD("r_bloom", "0", "gl_bloom", CVAR_ARCHIVE, "Enables bloom (light bleeding from bright objects)");
cvar_t r_bloom_alpha = CVAR("r_bloom_alpha", "0.5");
cvar_t r_bloom_diamond_size = CVAR("r_bloom_diamond_size", "8");
cvar_t r_bloom_intensity = CVAR("r_bloom_intensity", "1");
cvar_t r_bloom_darken = CVAR("r_bloom_darken", "3");
cvar_t r_bloom_sample_size = CVARF("r_bloom_sample_size", "256", CVAR_RENDERERLATCH);
cvar_t r_bloom_fast_sample = CVARF("r_bloom_fast_sample", "0", CVAR_RENDERERLATCH);
typedef struct {
//texture numbers
texid_t tx_screen; /*a copy of the screen*/
texid_t tx_effect; /*blured copy of bright pixels*/
texid_t tx_backup; /*a copy of the screen to replace the pixels that we'll clobber. FIXME: use a FBO instead*/
texid_t tx_downsample;
//the viewport dimensions
int vp_x;
int vp_y;
int vp_w;
int vp_h;
//texture coordinates of screen data inside screentexture
float scr_s;
float scr_t;
//dimensions of the screen texture (power of two)
int scr_w;
int scr_h;
//downsampled dimensions (will always be smaller than viewport)
int smp_w;
int smp_h;
//tex coords to be used for the sample
float smp_s;
float smp_t;
int size_downsample;
int size_backup;
int size_sample;
} bloomstate_t;
static bloomstate_t bs;
//this macro is in sample size workspace coordinates
#define R_Bloom_SamplePass( xpos, ypos ) \
qglBegin(GL_QUADS); \
qglTexCoord2f( 0, bs.smp_t); \
qglVertex2f( xpos, ypos); \
qglTexCoord2f( 0, 0); \
qglVertex2f( xpos, ypos+bs.smp_h); \
qglTexCoord2f( bs.smp_s, 0); \
qglVertex2f( xpos+bs.smp_w, ypos+bs.smp_h); \
qglTexCoord2f( bs.smp_s, bs.smp_t); \
qglVertex2f( xpos+bs.smp_w, ypos); \
qglEnd();
#define R_Bloom_Quad( x, y, width, height, textwidth, textheight ) \
qglBegin(GL_QUADS); \
qglTexCoord2f( 0, textheight); \
qglVertex2f( x, y); \
qglTexCoord2f( 0, 0); \
qglVertex2f( x, y+height); \
qglTexCoord2f( textwidth, 0); \
qglVertex2f( x+width, y+height); \
qglTexCoord2f( textwidth, textheight); \
qglVertex2f( x+width, y); \
qglEnd();
/*
=================
R_Bloom_InitBackUpTexture
=================
*/
void R_Bloom_InitBackUpTexture(int widthheight)
{
qbyte *data;
data = Z_Malloc(widthheight * widthheight * 4);
bs.size_backup = widthheight;
bs.tx_backup = GL_LoadTexture32("***bs.tx_backup***", bs.size_backup, bs.size_backup, (unsigned int*)data, IF_NOMIPMAP|IF_NOALPHA|IF_NOGAMMA);
Z_Free (data);
}
/*
=================
R_Bloom_InitEffectTexture
=================
*/
void R_Bloom_InitEffectTexture(void)
{
qbyte *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
bs.size_sample = min(r_bloom_sample_size.value, gl_max_size.value);
bloomsizecheck = (float)bs.size_sample;
while (bloomsizecheck > 1.0f) bloomsizecheck /= 2.0f;
if (bloomsizecheck != 1.0f)
{
bs.size_sample = 32;
while (bs.size_sample < r_bloom_sample_size.value)
bs.size_sample *= 2;
}
//make sure bloom size doesn't have stupid values
if (bs.size_sample > bs.scr_w ||
bs.size_sample > bs.scr_h)
bs.size_sample = min(bs.scr_w, bs.scr_h);
if (bs.size_sample != r_bloom_sample_size.value)
Cvar_SetValue (&r_bloom_sample_size, bs.size_sample);
data = Z_Malloc(bs.size_sample * bs.size_sample * 4);
bs.tx_effect = GL_LoadTexture32("***bs.tx_effect***", bs.size_sample, bs.size_sample, (unsigned int*)data, IF_NOMIPMAP|IF_NOALPHA|IF_NOGAMMA);
Z_Free (data);
}
/*
=================
R_Bloom_InitTextures
=================
*/
void R_Bloom_InitTextures(void)
{
qbyte *data;
int size;
int maxtexsize;
//find closer power of 2 to screen size
for (bs.scr_w = 1;bs.scr_w < vid.pixelwidth;bs.scr_w *= 2);
for (bs.scr_h = 1;bs.scr_h < vid.pixelheight;bs.scr_h *= 2);
//disable blooms if we can't handle a texture of that size
qglGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxtexsize);
if (bs.scr_w > maxtexsize ||
bs.scr_h > maxtexsize)
{
bs.scr_w = bs.scr_h = 0;
Cvar_SetValue (&r_bloom, 0);
Con_Printf("WARNING: 'R_InitBloomScreenTexture' too high resolution for Light Bloom. Effect disabled\n");
return;
}
//init the screen texture
size = bs.scr_w * bs.scr_h * 4;
data = Z_Malloc(size);
memset(data, 255, size);
if (!TEXVALID(bs.tx_screen))
bs.tx_screen = GL_AllocNewTexture("***bloom screen***", bs.scr_w, bs.scr_h);
GL_MTBind(0, GL_TEXTURE_2D, bs.tx_screen);
qglTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, bs.scr_w, bs.scr_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
Z_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
bs.tx_downsample = r_nulltex;
bs.size_downsample = 0;
if (vid.pixelwidth > (bs.size_sample * 2) && !r_bloom_fast_sample.value)
{
bs.size_downsample = (int)(bs.size_sample * 2);
data = Z_Malloc(bs.size_downsample * bs.size_downsample * 4);
bs.tx_downsample = GL_LoadTexture32("***bs.tx_downsample***", bs.size_downsample, bs.size_downsample, (unsigned int*)data, IF_NOMIPMAP|IF_NOALPHA|IF_NOGAMMA);
Z_Free (data);
}
//Init the screen backup texture
if (bs.size_downsample)
R_Bloom_InitBackUpTexture(bs.size_downsample);
else
R_Bloom_InitBackUpTexture(bs.size_sample);
}
void R_BloomRegister(void)
{
Cvar_Register (&r_bloom, "bloom");
Cvar_Register (&r_bloom_alpha, "bloom");
Cvar_Register (&r_bloom_diamond_size, "bloom");
Cvar_Register (&r_bloom_intensity, "bloom");
Cvar_Register (&r_bloom_darken, "bloom");
Cvar_Register (&r_bloom_sample_size, "bloom");
Cvar_Register (&r_bloom_fast_sample, "bloom");
}
/*
=================
R_InitBloomTextures
=================
*/
void R_InitBloomTextures(void)
{
bs.size_sample = 0;
if (!r_bloom.ival)
return;
bs.tx_screen = r_nulltex; //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)
{
GL_MTBind(0, GL_TEXTURE_2D, bs.tx_effect);
qglEnable(GL_BLEND);
qglBlendFunc(GL_ONE, GL_ONE);
qglColor4f(r_bloom_alpha.value, r_bloom_alpha.value, r_bloom_alpha.value, 1.0f);
GL_TexEnv(GL_MODULATE);
qglBegin(GL_QUADS);
qglTexCoord2f (0, bs.smp_t);
qglVertex2f (bs.vp_x, bs.vp_y);
qglTexCoord2f (0, 0);
qglVertex2f (bs.vp_x, bs.vp_y + bs.vp_h);
qglTexCoord2f (bs.smp_s, 0);
qglVertex2f (bs.vp_x + bs.vp_w, bs.vp_y + bs.vp_h);
qglTexCoord2f (bs.smp_s, bs.smp_t);
qglVertex2f (bs.vp_x + bs.vp_w, bs.vp_y);
qglEnd();
qglDisable(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, bs.smp_w, bs.smp_h );
qglMatrixMode( GL_PROJECTION );
qglLoadIdentity ();
qglOrtho(0, bs.smp_w, bs.smp_h, 0, -10, 100);
qglMatrixMode( GL_MODELVIEW );
qglLoadIdentity ();
//copy small scene into bs.tx_effect
GL_Bind(0, bs.tx_effect);
qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, bs.smp_w, bs.smp_h);
//start modifying the small scene corner
qglColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
qglEnable(GL_BLEND);
//darkening passes
if( r_bloom_darken.value )
{
qglBlendFunc(GL_DST_COLOR, GL_ZERO);
GL_TexEnv(GL_MODULATE);
for(i=0; i<r_bloom_darken->integer ;i++) {
R_Bloom_SamplePass( 0, 0 );
}
qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, bs.smp_w, bs.smp_h);
}
//bluring passes
if( BLOOM_BLUR_RADIUS ) {
qglBlendFunc(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
qglColor4f( 0.5f, 0.5f, 0.5f, 1.0);
R_Bloom_SamplePass( 1, 1 );
R_Bloom_SamplePass( -1, 1 );
R_Bloom_SamplePass( -1, -1 );
R_Bloom_SamplePass( 1, -1 );
qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, bs.smp_w, bs.smp_h);
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;
qglColor4f( intensity, intensity, intensity, 1.0f);
R_Bloom_SamplePass( i, 0 );
//R_Bloom_SamplePass( -i, 0 );
}
qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, bs.smp_w, bs.smp_h);
//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;
qglColor4f( intensity, intensity, intensity, 1.0f);
R_Bloom_SamplePass( 0, i );
//R_Bloom_SamplePass( 0, -i );
}
qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, bs.smp_w, bs.smp_h);
}
//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;
float intensity;
//set up sample size workspace
qglViewport(0, 0, bs.smp_w, bs.smp_h);
qglMatrixMode(GL_PROJECTION);
qglLoadIdentity();
qglOrtho(0, bs.smp_w, bs.smp_h, 0, -10, 100);
qglMatrixMode(GL_MODELVIEW);
qglLoadIdentity();
//copy small scene into bs.tx_effect
GL_MTBind(0, GL_TEXTURE_2D, bs.tx_effect);
qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, bs.smp_w, bs.smp_h);
//start modifying the small scene corner
qglColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
qglEnable(GL_BLEND);
//darkening passes
if (r_bloom_darken.value)
{
qglBlendFunc(GL_DST_COLOR, GL_ZERO);
GL_TexEnv(GL_MODULATE);
for (i=0; i<r_bloom_darken.value ;i++)
{
R_Bloom_SamplePass(0, 0);
}
qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, bs.smp_w, bs.smp_h);
}
//bluring passes
//qglBlendFunc(GL_ONE, GL_ONE);
qglBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
{
int size = r_bloom_diamond_size.value;
float rad = r_bloom_diamond_size.value / 2.0f;
float point = (r_bloom_diamond_size.value - 1) / 2.0f;
float mult = min(1.0f, r_bloom_intensity.value * 2.0f / rad);
for (i=0; i<size; i++)
{
for (j=0; j<size; j++)
{
float f = ((point + 1.0f) - (fabs(point - i) + fabs(point - j))) / (point + 1.0f);
//float f = 1.0f - (fabs(point - i) * fabs(point - j) / (point * point)); // circle/cross?
intensity = mult * f;
if (intensity < 0.005f)
continue;
qglColor4f(intensity, intensity, intensity, 1.0);
R_Bloom_SamplePass( i-rad, j-rad );
}
}
}
qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, bs.smp_w, bs.smp_h);
//restore full screen workspace
qglViewport(0, 0, vid.pixelwidth, vid.pixelheight);
qglMatrixMode(GL_PROJECTION);
qglLoadIdentity ();
qglOrtho(0, vid.pixelwidth, vid.pixelheight, 0, -10, 100);
qglMatrixMode(GL_MODELVIEW);
qglLoadIdentity ();
}
/*
=================
R_Bloom_DownsampleView
=================
*/
void R_Bloom_DownsampleView( void )
{
qglDisable(GL_BLEND);
qglColor4f(1.0f, 1.0f, 1.0f, 1.0f);
//stepped downsample
if (bs.size_downsample)
{
int midsample_width = bs.size_downsample * bs.smp_s;
int midsample_height = bs.size_downsample * bs.smp_t;
//copy the screen and draw resized
GL_MTBind(0, GL_TEXTURE_2D, bs.tx_screen);
qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bs.vp_x, vid.pixelheight - (bs.vp_y + bs.vp_h), bs.vp_w, bs.vp_h);
R_Bloom_Quad(0, vid.pixelheight-midsample_height, midsample_width, midsample_height, bs.scr_s, bs.scr_t);
//now copy into Downsampling (mid-sized) texture
GL_MTBind(0, GL_TEXTURE_2D, bs.tx_downsample);
qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, midsample_width, midsample_height);
//now draw again in bloom size
qglColor4f(0.5f, 0.5f, 0.5f, 1.0f);
R_Bloom_Quad(0, vid.pixelheight-bs.smp_h, bs.smp_w, bs.smp_h, bs.smp_s, bs.smp_t);
//now blend the big screen texture into the bloom generation space (hoping it adds some blur)
qglEnable(GL_BLEND);
qglBlendFunc(GL_ONE, GL_ONE);
qglColor4f(0.5f, 0.5f, 0.5f, 1.0f);
GL_MTBind(0, GL_TEXTURE_2D, bs.tx_screen);
R_Bloom_Quad(0, vid.pixelheight-bs.smp_h, bs.smp_w, bs.smp_h, bs.scr_s, bs.scr_t);
qglColor4f(1.0f, 1.0f, 1.0f, 1.0f);
qglDisable(GL_BLEND);
}
else
{ //downsample simple
GL_MTBind(0, GL_TEXTURE_2D, bs.tx_screen);
qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bs.vp_x, vid.pixelheight - (bs.vp_y + bs.vp_h), bs.vp_w, bs.vp_h);
R_Bloom_Quad(0, vid.pixelheight-bs.smp_h, bs.smp_w, bs.smp_h, bs.scr_s, bs.scr_t);
}
}
/*
=================
R_BloomBlend
=================
*/
void R_BloomBlend (void)
{
int buw, buh;
if (!bs.size_sample || bs.scr_w < vid.pixelwidth || bs.scr_h < vid.pixelheight)
R_Bloom_InitTextures();
if (bs.scr_w < bs.size_sample ||
bs.scr_h < bs.size_sample)
return;
PPL_RevertToKnownState();
#ifdef warningmsg
#pragma warningmsg("Note: Bloom doesn't use the backend.")
#endif
//set up full screen workspace
qglViewport(0, 0, vid.pixelwidth, vid.pixelheight);
qglDisable(GL_DEPTH_TEST);
qglMatrixMode(GL_PROJECTION);
qglLoadIdentity();
qglOrtho(0, vid.pixelwidth, vid.pixelheight, 0, -10, 100);
qglMatrixMode(GL_MODELVIEW);
qglLoadIdentity();
GL_CullFace(0);
qglDisable(GL_BLEND);
qglEnable(GL_TEXTURE_2D);
qglColor4f(1, 1, 1, 1);
//set up current sizes
bs.vp_x = r_refdef.pxrect.x;
bs.vp_y = vid.pixelheight - r_refdef.pxrect.y;
bs.vp_w = r_refdef.pxrect.width;
bs.vp_h = r_refdef.pxrect.height;
bs.scr_s = (float)bs.vp_w / (float)bs.scr_w;
bs.scr_t = (float)bs.vp_h / (float)bs.scr_h;
if (bs.vp_h > bs.vp_w)
{
bs.smp_s = (float)bs.vp_w / (float)bs.vp_h;
bs.smp_t = 1.0f;
}
else
{
bs.smp_s = 1.0f;
bs.smp_t = (float)bs.vp_h / (float)bs.vp_w;
}
bs.smp_w = bs.size_sample * bs.smp_s;
bs.smp_h = bs.size_sample * bs.smp_t;
bs.smp_s = (float)bs.smp_w/bs.size_sample;
bs.smp_t = (float)bs.smp_h/bs.size_sample;
buw = bs.size_backup * bs.smp_s;
buh = bs.size_backup * bs.smp_t;
//copy the screen space we'll use to work into the backup texture
GL_MTBind(0, GL_TEXTURE_2D, bs.tx_backup);
qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, buw, buh);
//create the bloom image
R_Bloom_DownsampleView();
R_Bloom_GeneratexDiamonds();
//R_Bloom_GeneratexCross();
//restore the screen-backup to the screen
qglDisable(GL_BLEND);
GL_MTBind(0, GL_TEXTURE_2D, bs.tx_backup);
qglColor4f(1, 1, 1, 1);
R_Bloom_Quad(0,
vid.pixelheight - (buh),
buw,
buh,
bs.smp_s,
bs.smp_t);
R_Bloom_DrawEffect();
qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
checkglerror();
PPL_RevertToKnownState();
}
#endif

View File

@ -98,6 +98,7 @@ texid_t scenepp_postproc_cube;
int scenepp_postproc_cube_size;
fbostate_t fbo_gameview;
fbostate_t fbo_postproc;
// KrimZon - init post processing - called in GL_CheckExtensions, when they're called
// I put it here so that only this file need be changed when messing with the post
@ -111,7 +112,7 @@ void GL_InitSceneProcessingShaders_WaterWarp (void)
"{\n"
"program underwaterwarp\n"
"{\n"
"map $currentrender\n"
"map $sourcecolour\n"
"}\n"
"{\n"
"map $upperoverlay\n"
@ -129,6 +130,7 @@ void GL_InitSceneProcessingShaders_WaterWarp (void)
void GL_ShutdownPostProcessing(void)
{
GLBE_FBO_Destroy(&fbo_gameview);
GLBE_FBO_Destroy(&fbo_postproc);
R_BloomShutdown();
}
@ -388,7 +390,16 @@ void R_SetupGL (float stereooffset)
//
// set up viewpoint
//
if (*r_refdef.rt_destcolour[0].texname)
if (r_refdef.flags & (RDF_ALLPOSTPROC))
{
//with fbo postprocessing, we disable all viewport.
r_refdef.pxrect.x = 0;
r_refdef.pxrect.y = 0;
r_refdef.pxrect.width = vid.fbpwidth;
r_refdef.pxrect.height = vid.fbpheight;
r_refdef.pxrect.maxheight = vid.fbpheight;
}
else if (*r_refdef.rt_destcolour[0].texname)
{
//with fbo rendering, we disable all virtual scaling.
x = r_refdef.vrect.x;
@ -407,18 +418,18 @@ void R_SetupGL (float stereooffset)
}
else
{
x = r_refdef.vrect.x * (int)vid.pixelwidth/(int)vid.width;
x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * (int)vid.pixelwidth/(int)vid.width;
y = (r_refdef.vrect.y) * (int)vid.pixelheight/(int)vid.height;
y2 = (r_refdef.vrect.y + r_refdef.vrect.height) * (int)vid.pixelheight/(int)vid.height;
x = r_refdef.vrect.x * (int)vid.fbpwidth/(int)vid.width;
x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * (int)vid.fbpwidth/(int)vid.width;
y = (r_refdef.vrect.y) * (int)vid.fbpheight/(int)vid.height;
y2 = (r_refdef.vrect.y + r_refdef.vrect.height) * (int)vid.fbpheight/(int)vid.height;
// fudge around because of frac screen scale
if (x > 0)
x--;
if (x2 < vid.pixelwidth)
if (x2 < vid.fbpwidth)
x2++;
if (y2 < vid.pixelheight)
if (y2 < vid.fbpheight)
y2++;
if (y > 0)
y--;
@ -430,21 +441,21 @@ void R_SetupGL (float stereooffset)
{
w /= 2;
if (stereooffset > 0)
x += vid.pixelwidth/2;
x += vid.fbpwidth/2;
}
r_refdef.pxrect.x = x;
r_refdef.pxrect.y = y;
r_refdef.pxrect.width = w;
r_refdef.pxrect.height = h;
r_refdef.pxrect.maxheight = vid.pixelheight;
r_refdef.pxrect.maxheight = vid.fbpheight;
}
fov_x = r_refdef.fov_x;//+sin(cl.time)*5;
fov_y = r_refdef.fov_y;//-sin(cl.time+1)*5;
GL_ViewportUpdate();
if ((r_waterwarp.value<0 || (r_waterwarp.value && !R_GameRectIsFullscreen())) && (r_viewcontents & FTECONTENTS_FLUID))
if ((r_refdef.flags & RDF_UNDERWATER) && !(r_refdef.flags & RDF_WATERWARP))
{
fov_x *= 1 + (((sin(cl.time * 4.7) + 1) * 0.015) * r_waterwarp.value);
fov_y *= 1 + (((sin(cl.time * 3.0) + 1) * 0.015) * r_waterwarp.value);
@ -510,6 +521,7 @@ void R_SetupGL (float stereooffset)
}
void Surf_SetupFrame(void);
/*
================
R_RenderScene
@ -524,8 +536,6 @@ void R_RenderScene (void)
int stereomode;
int i;
int tmpvisents = cl_numvisedicts; /*world rendering is allowed to add additional ents, but we don't want to keep them for recursive views*/
if (!cl.worldmodel || (!cl.worldmodel->nodes && cl.worldmodel->type != mod_heightmap))
r_refdef.flags |= RDF_NOWORLDMODEL;
stereomode = r_stereo_method.ival;
if (stereomode == 1)
@ -569,7 +579,7 @@ void R_RenderScene (void)
qglDrawBuffer(GL_BACK_RIGHT);
break;
#endif
case 2: //red/cyan
case 2: //red/cyan(green+blue)
if (stereooffset[i] < 0)
qglColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE);
else
@ -593,8 +603,6 @@ void R_RenderScene (void)
if (i)
qglClear (GL_DEPTH_BUFFER_BIT);
Surf_SetupFrame();
TRACE(("dbg: calling R_SetupGL\n"));
R_SetupGL (stereooffset[i]);
@ -1320,6 +1328,7 @@ static void R_RenderMotionBlur(void)
#endif
}
#if 0
/*FIXME: we could use geometry shaders to draw to all 6 faces at once*/
qboolean R_RenderScene_Cubemap(void)
{
@ -1490,6 +1499,34 @@ qboolean R_RenderScene_Cubemap(void)
*/
return true;
}
#endif
texid_t R_RenderPostProcess (texid_t sourcetex, int type, shader_t *shader, char *restexname)
{
if (r_refdef.flags & type)
{
r_refdef.flags &= ~type;
GLBE_FBO_Sources(sourcetex, r_nulltex);
if (r_refdef.flags & RDF_ALLPOSTPROC)
{ //there's other post-processing passes that still need to be applied.
//thus we need to write this output to a texture.
int w = (r_refdef.vrect.width * vid.pixelwidth) / vid.width;
int h = (r_refdef.vrect.height * vid.pixelheight) / vid.height;
sourcetex = R2D_RT_Configure(restexname, w, h, TF_RGBA32);
GLBE_FBO_Update(&fbo_postproc, 0, &sourcetex, 1, r_nulltex, w, h);
R2D_ScalePic(0, vid.pixelheight-r_refdef.vrect.height, r_refdef.vrect.width, r_refdef.vrect.height, scenepp_waterwarp);
GLBE_RenderToTextureUpdate2d(true);
}
else
{ //yay, dump it to the screen
//update stuff now that we're not rendering the 3d scene
R2D_ScalePic(r_refdef.vrect.x, r_refdef.vrect.y, r_refdef.vrect.width, r_refdef.vrect.height, scenepp_waterwarp);
}
}
return sourcetex;
}
/*
================
@ -1502,12 +1539,16 @@ void GLR_RenderView (void)
{
int dofbo = *r_refdef.rt_destcolour[0].texname || *r_refdef.rt_depth.texname;
double time1 = 0, time2;
texid_t sourcetex = r_nulltex;
shader_t *custompostproc = NULL;
checkglerror();
if (r_norefresh.value || !vid.pixelwidth || !vid.pixelheight)
return;
//when loading/bugged, its possible that the world is still loading.
//in this case, don't act as a wallhack (unless the world is meant to be hidden anyway)
if (!(r_refdef.flags & RDF_NOWORLDMODEL))
{
//FIXME: fbo stuff
@ -1522,6 +1563,43 @@ void GLR_RenderView (void)
// Sys_Error ("R_RenderView: NULL worldmodel");
}
//check if we're underwater (this also limits damage from stereo wallhacks).
Surf_SetupFrame();
r_refdef.flags &= ~RDF_ALLPOSTPROC;
//if bloom is
if (R_CanBloom())
r_refdef.flags |= RDF_BLOOM;
//check if we can do underwater warp
if (cls.protocol != CP_QUAKE2) //quake2 tells us directly
{
if (r_viewcontents & FTECONTENTS_FLUID)
r_refdef.flags |= RDF_UNDERWATER;
else
r_refdef.flags &= ~RDF_UNDERWATER;
}
if (r_refdef.flags & RDF_UNDERWATER)
{
if (!r_waterwarp.value)
r_refdef.flags &= ~RDF_UNDERWATER; //no warp at all
else if (r_waterwarp.value > 0 && scenepp_waterwarp)
r_refdef.flags |= RDF_WATERWARP; //try fullscreen warp instead if we can
}
//
if (*r_postprocshader.string)
{
custompostproc = R_RegisterCustom(r_postprocshader.string, SUF_NONE, NULL, NULL);
if (custompostproc)
r_refdef.flags |= RDF_CUSTOMPOSTPROC;
}
//disable stuff if its simply not supported.
if (dofbo || !gl_config.arb_shader_objects || !gl_config.ext_framebuffer_objects || !r_config.texture_non_power_of_two)
r_refdef.flags &= ~(RDF_ALLPOSTPROC); //block all of this stuff
BE_Scissor(NULL);
if (dofbo)
{
@ -1569,7 +1647,18 @@ void GLR_RenderView (void)
flags |= FBO_RB_DEPTH;
GLBE_FBO_Update(&fbo_gameview, flags, col, mrt, depth, vid.fbpwidth, vid.fbpheight);
}
else
else if (r_refdef.flags & (RDF_ALLPOSTPROC))
{
//the game needs to be drawn to a texture for post processing
vid.fbvwidth = vid.fbpwidth = (r_refdef.vrect.width * vid.pixelwidth) / vid.width;
vid.fbvheight = vid.fbpheight = (r_refdef.vrect.height * vid.pixelheight) / vid.height;
sourcetex = R2D_RT_Configure("rt/$lastgameview", vid.fbpwidth, vid.fbpheight, TF_RGBA32);
GLBE_FBO_Update(&fbo_gameview, FBO_RB_DEPTH, &sourcetex, 1, r_nulltex, vid.fbpwidth, vid.fbpheight);
dofbo = true;
}
else
{
vid.fbvwidth = vid.width;
vid.fbvheight = vid.height;
@ -1604,11 +1693,11 @@ void GLR_RenderView (void)
time1 = Sys_DoubleTime ();
}
if (!dofbo && !(r_refdef.flags & RDF_NOWORLDMODEL) && R_RenderScene_Cubemap())
{
}
else
// if (!dofbo && !(r_refdef.flags & RDF_NOWORLDMODEL) && R_RenderScene_Cubemap())
// {
//
// }
// else
{
GL_SetShaderState2D(false);
@ -1643,40 +1732,17 @@ void GLR_RenderView (void)
GL_Set2D (false);
}
//FIXME: support bloom+waterwarp even when drawing to an fbo?
//FIXME: force waterwarp to a temp fbo always
if ((r_refdef.flags & RDF_NOWORLDMODEL) || dofbo)
return;
if (!R_GameRectIsFullscreen())
return;
if (r_bloom.value)
R_BloomBlend();
// SCENE POST PROCESSING
// we check if we need to use any shaders - currently it's just waterwarp
if ((r_waterwarp.value>0 && (r_viewcontents & FTECONTENTS_WATER)))
{
if (scenepp_waterwarp)
{
R2D_ScalePic(0, 0, vid.width, vid.height, scenepp_waterwarp);
}
}
sourcetex = R_RenderPostProcess (sourcetex, RDF_WATERWARP, scenepp_waterwarp, "rt/$waterwarped");
sourcetex = R_RenderPostProcess (sourcetex, RDF_CUSTOMPOSTPROC, custompostproc, "rt/$postproced");
if (r_refdef.flags & RDF_BLOOM)
R_BloomBlend(sourcetex, r_refdef.vrect.x, r_refdef.vrect.y, r_refdef.vrect.width, r_refdef.vrect.height);
GLBE_FBO_Sources(r_nulltex, r_nulltex);
if (gl_motionblur.value>0 && gl_motionblur.value < 1 && qglCopyTexImage2D)
R_RenderMotionBlur();
if (*r_postprocshader.string)
{
shader_t *postproc = R_RegisterCustom(r_postprocshader.string, SUF_NONE, NULL, NULL);
if (postproc)
{
R2D_ScalePic(0, 0, vid.width, vid.height, postproc);
}
}
// if (gl_motionblur.value>0 && gl_motionblur.value < 1 && qglCopyTexImage2D)
// R_RenderMotionBlur();
checkglerror();
}

View File

@ -423,7 +423,8 @@ void D3_GenerateAreas(model_t *mod);
//gl_bloom.c
#ifdef GLQUAKE
void R_BloomRegister(void);
void R_BloomBlend(void);
qboolean R_CanBloom(void);
void R_BloomBlend (texid_t source, int x, int y, int w, int h);
void R_BloomShutdown(void);
#endif

View File

@ -2291,7 +2291,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"void main ()\n"
"{\n"
"gl_Position = ftetransform();\n"
"v_stc = (1.0+(gl_Position.xy / gl_Position.w))/2.0;\n"
"v_stc = vec2(v_texcoord.x, 1.0-v_texcoord.y);\n"
"v_warp.s = e_time * 0.25 + v_texcoord.s;\n"
"v_warp.t = e_time * 0.25 + v_texcoord.t;\n"
"v_edge = v_texcoord.xy;\n"

View File

@ -12,7 +12,7 @@ uniform float e_time;
void main ()
{
gl_Position = ftetransform();
v_stc = (1.0+(gl_Position.xy / gl_Position.w))/2.0;
v_stc = vec2(v_texcoord.x, 1.0-v_texcoord.y);
v_warp.s = e_time * 0.25 + v_texcoord.s;
v_warp.t = e_time * 0.25 + v_texcoord.t;
v_edge = v_texcoord.xy;