mirror of
https://github.com/ReactionQuake3/reaction.git
synced 2025-01-23 01:50:41 +00:00
Overbright bits hack. FP16 FBO's with r_ext_framebuffer_object 2. Occlusion query for god rays.
This commit is contained in:
parent
3a6ad64407
commit
5df45cf52b
7 changed files with 211 additions and 46 deletions
|
@ -24,7 +24,11 @@
|
|||
HANDLE_EXT_FUNC( PFNGLGETQUERYOBJECTIVARBPROC, glGetQueryObjectivARB) \
|
||||
HANDLE_EXT_FUNC( PFNGLGETQUERYOBJECTUIVARBPROC, glGetQueryObjectuivARB) \
|
||||
|
||||
#define GL_MISSING_FUNCTIONS \
|
||||
HANDLE_EXT_FUNC( PFNGLBLENDEQUATIONPROC, glBlendEquation) \
|
||||
|
||||
#define GL_ARB_color_buffer_float_functions \
|
||||
HANDLE_EXT_FUNC( PFNGLCLAMPCOLORARBPROC, glClampColorARB) \
|
||||
|
||||
#ifndef GL_EXT_framebuffer_multisample
|
||||
#define GL_EXT_framebuffer_multisample 1
|
||||
|
@ -57,6 +61,7 @@
|
|||
GL_EXT_framebuffer_multisample_functions \
|
||||
GL_EXT_framebuffer_blit_functions \
|
||||
GL_ARB_occlusion_query_functions \
|
||||
|
||||
GL_ARB_color_buffer_float_functions \
|
||||
GL_MISSING_FUNCTIONS \
|
||||
|
||||
#endif
|
||||
|
|
|
@ -601,6 +601,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
|
|||
float originalTime;
|
||||
float depth[2];
|
||||
fbo_t* fbo = NULL;
|
||||
qboolean inQuery = qfalse;
|
||||
|
||||
// save original time for entity shader offsets
|
||||
originalTime = backEnd.refdef.floatTime;
|
||||
|
@ -665,6 +666,10 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
|
|||
{
|
||||
R_FBO_Bind(fbo);
|
||||
qglDepthRange(depth[0], depth[1]);
|
||||
if (inQuery) {
|
||||
inQuery = qfalse;
|
||||
qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
|
||||
}
|
||||
}
|
||||
|
||||
if ( entityNum != ENTITYNUM_WORLD ) {
|
||||
|
@ -687,11 +692,16 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
|
|||
// if we're rendering to a fbo
|
||||
if (fbo) {
|
||||
VectorCopy(backEnd.currentEntity->e.origin, backEnd.sunFlarePos);
|
||||
backEnd.hasSunFlare = qtrue;
|
||||
sunflare = qtrue;
|
||||
// switch FBO
|
||||
R_FBO_Bind(tr.fbo.fbos[1]);
|
||||
qglDepthRange(1.f, 1.f);
|
||||
if (glRefConfig.occlusionQuery && !inQuery && !backEnd.hasSunFlare) {
|
||||
inQuery = qtrue;
|
||||
tr.sunFlareQueryActive[tr.sunFlareQueryIndex] = qtrue;
|
||||
qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, tr.sunFlareQuery[tr.sunFlareQueryIndex]);
|
||||
}
|
||||
backEnd.hasSunFlare = qtrue;
|
||||
sunflare = qtrue;
|
||||
} else {
|
||||
depthRange = qtrue;
|
||||
}
|
||||
|
@ -785,6 +795,10 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
|
|||
}
|
||||
|
||||
R_FBO_Bind(fbo);
|
||||
if (inQuery) {
|
||||
inQuery = qfalse;
|
||||
qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
|
||||
}
|
||||
|
||||
// go back to the world modelview matrix
|
||||
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
#include "tr_local.h"
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
|
||||
#endif
|
||||
|
||||
#define MAX_FBO_COLOR_BUFFERS 8
|
||||
|
||||
/*
|
||||
|
@ -426,6 +422,18 @@ static void R_FBO_CreateDefaultBuffers(void)
|
|||
NULL,
|
||||
NULL);
|
||||
|
||||
tr.fbo.tiny[0] = R_FBO_CreateSimple(
|
||||
"tiny0",
|
||||
R_FBO_CreateColorBuffer("*tinyBuffer0", glConfig.vidWidth/4, glConfig.vidHeight/4, qfalse, qfalse, GL_CLAMP_TO_EDGE),
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
tr.fbo.tiny[1] = R_FBO_CreateSimple(
|
||||
"tiny1",
|
||||
R_FBO_CreateColorBuffer("*tinyBuffer1", glConfig.vidWidth/4, glConfig.vidHeight/4, qfalse, qfalse, GL_CLAMP_TO_EDGE),
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
ri.Printf(PRINT_DEVELOPER, "...created %d FBOs\n", tr.fbo.numFBOs);
|
||||
}
|
||||
|
||||
|
|
|
@ -501,11 +501,19 @@ static void Upload32( unsigned *data,
|
|||
GLenum internalFormat = GL_RGB;
|
||||
float rMax = 0, gMax = 0, bMax = 0;
|
||||
|
||||
// Makro - render target
|
||||
// Makro - no data, this must be a render target
|
||||
if (!data)
|
||||
{
|
||||
if (r_ext_framebuffer_object->integer >= 2 && glRefConfig.textureFloat)
|
||||
{
|
||||
internalFormat = GL_RGBA16F_ARB;
|
||||
qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, width, height, 0, GL_RGBA, GL_FLOAT, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
internalFormat = GL_RGBA8;
|
||||
qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
}
|
||||
GL_CheckErrors();
|
||||
*format = internalFormat;
|
||||
*pUploadWidth = width;
|
||||
|
@ -777,19 +785,45 @@ done:
|
|||
ri.Hunk_FreeTempMemory( resampledBuffer );
|
||||
}
|
||||
|
||||
static image_t *R_AllocImage(const char* name, int width, int height, qboolean mipmap, qboolean allowPicmip, int glWrapClampMode)
|
||||
{
|
||||
image_t *image;
|
||||
long hash;
|
||||
|
||||
image = tr.images[tr.numImages++] = ri.Hunk_Alloc( sizeof( image_t ), h_low );
|
||||
Com_Memset(image, 0, sizeof(*image));
|
||||
|
||||
image->texnum = 1024 + tr.numImages;
|
||||
image->mipmap = mipmap;
|
||||
image->allowPicmip = allowPicmip;
|
||||
|
||||
strcpy (image->imgName, name);
|
||||
|
||||
image->width = width;
|
||||
image->height = height;
|
||||
image->wrapClampMode = glWrapClampMode;
|
||||
|
||||
hash = generateHashValue(name);
|
||||
image->next = hashTable[hash];
|
||||
hashTable[hash] = image;
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
R_CreateImage
|
||||
|
||||
This is the only way any image_t are created
|
||||
|
||||
Makro - except maybe for render targets
|
||||
at some point in the near future...
|
||||
================
|
||||
*/
|
||||
image_t *R_CreateImage( const char *name, const byte *pic, int width, int height,
|
||||
qboolean mipmap, qboolean allowPicmip, int glWrapClampMode ) {
|
||||
image_t *image;
|
||||
qboolean isLightmap = qfalse;
|
||||
long hash;
|
||||
|
||||
if (strlen(name) >= MAX_QPATH ) {
|
||||
ri.Error (ERR_DROP, "R_CreateImage: \"%s\" is too long\n", name);
|
||||
|
@ -802,18 +836,7 @@ image_t *R_CreateImage( const char *name, const byte *pic, int width, int height
|
|||
ri.Error( ERR_DROP, "R_CreateImage: MAX_DRAWIMAGES hit\n");
|
||||
}
|
||||
|
||||
image = tr.images[tr.numImages] = ri.Hunk_Alloc( sizeof( image_t ), h_low );
|
||||
image->texnum = 1024 + tr.numImages;
|
||||
tr.numImages++;
|
||||
|
||||
image->mipmap = mipmap;
|
||||
image->allowPicmip = allowPicmip;
|
||||
|
||||
strcpy (image->imgName, name);
|
||||
|
||||
image->width = width;
|
||||
image->height = height;
|
||||
image->wrapClampMode = glWrapClampMode;
|
||||
image = R_AllocImage(name, width, height, mipmap, allowPicmip, glWrapClampMode);
|
||||
|
||||
// lightmaps are always allocated on TMU 1
|
||||
if ( qglActiveTextureARB && isLightmap ) {
|
||||
|
@ -845,10 +868,6 @@ image_t *R_CreateImage( const char *name, const byte *pic, int width, int height
|
|||
GL_SelectTexture( 0 );
|
||||
}
|
||||
|
||||
hash = generateHashValue(name);
|
||||
image->next = hashTable[hash];
|
||||
hashTable[hash] = image;
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
@ -1226,12 +1245,12 @@ void R_SetColorMappings( void ) {
|
|||
|
||||
// setup the overbright lighting
|
||||
tr.overbrightBits = r_overBrightBits->integer;
|
||||
if ( !glConfig.deviceSupportsGamma ) {
|
||||
if ( !glConfig.deviceSupportsGamma && !glRefConfig.glslOverbright ) {
|
||||
tr.overbrightBits = 0; // need hardware gamma for overbright
|
||||
}
|
||||
|
||||
// never overbright in windowed mode
|
||||
if ( !glConfig.isFullscreen )
|
||||
if ( !glConfig.isFullscreen && !glRefConfig.glslOverbright )
|
||||
{
|
||||
tr.overbrightBits = 0;
|
||||
}
|
||||
|
@ -1268,6 +1287,9 @@ void R_SetColorMappings( void ) {
|
|||
|
||||
shift = tr.overbrightBits;
|
||||
|
||||
if (glRefConfig.glslOverbright)
|
||||
shift = 0;
|
||||
|
||||
for ( i = 0; i < 256; i++ ) {
|
||||
if ( g == 1 ) {
|
||||
inf = i;
|
||||
|
|
|
@ -410,7 +410,7 @@ void RB_TakeScreenshotJPEG( int x, int y, int width, int height, char *fileName
|
|||
|
||||
buffer = ri.Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*4);
|
||||
|
||||
qglReadPixels( x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer );
|
||||
qglReadPixels( x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer );
|
||||
|
||||
// gamma correct
|
||||
if ( glConfig.deviceSupportsGamma ) {
|
||||
|
@ -430,6 +430,7 @@ RB_TakeScreenshotCmd
|
|||
*/
|
||||
const void *RB_TakeScreenshotCmd( const void *data ) {
|
||||
const screenshotCommand_t *cmd;
|
||||
fbo_t *fbo = R_FBO_Bind(NULL);
|
||||
|
||||
cmd = (const screenshotCommand_t *)data;
|
||||
|
||||
|
@ -438,6 +439,8 @@ const void *RB_TakeScreenshotCmd( const void *data ) {
|
|||
else
|
||||
RB_TakeScreenshot( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName);
|
||||
|
||||
R_FBO_Bind(fbo);
|
||||
|
||||
return (const void *)(cmd + 1);
|
||||
}
|
||||
|
||||
|
@ -710,12 +713,17 @@ const void *RB_TakeVideoFrameCmd( const void *data )
|
|||
const videoFrameCommand_t *cmd;
|
||||
int frameSize;
|
||||
int i;
|
||||
fbo_t *fbo;
|
||||
|
||||
cmd = (const videoFrameCommand_t *)data;
|
||||
|
||||
fbo = R_FBO_Bind(NULL);
|
||||
|
||||
qglReadPixels( 0, 0, cmd->width, cmd->height, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, cmd->captureBuffer );
|
||||
|
||||
R_FBO_Bind(fbo);
|
||||
|
||||
// gamma correct
|
||||
if( glConfig.deviceSupportsGamma )
|
||||
R_GammaCorrect( cmd->captureBuffer, cmd->width * cmd->height * 4 );
|
||||
|
@ -1070,12 +1078,16 @@ void R_InitQueries(void)
|
|||
{
|
||||
if (!glRefConfig.occlusionQuery)
|
||||
return;
|
||||
|
||||
qglGenQueriesARB(ARRAY_SIZE(tr.sunFlareQuery), tr.sunFlareQuery);
|
||||
}
|
||||
|
||||
void R_ShutDownQueries(void)
|
||||
{
|
||||
if (!glRefConfig.occlusionQuery)
|
||||
return;
|
||||
|
||||
qglDeleteQueriesARB(ARRAY_SIZE(tr.sunFlareQuery), tr.sunFlareQuery);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -43,6 +43,10 @@ long myftol( float f );
|
|||
|
||||
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
|
||||
#endif
|
||||
|
||||
// everything that is needed by the backend needs
|
||||
// to be double buffered to allow it to run in
|
||||
// parallel on a dual cpu machine
|
||||
|
@ -2166,6 +2170,11 @@ typedef struct {
|
|||
qboolean framebufferBlit;
|
||||
qboolean framebufferMultisample;
|
||||
|
||||
qboolean glslOverbright;
|
||||
|
||||
qboolean textureFloat;
|
||||
qboolean colorBufferFloat;
|
||||
|
||||
qboolean occlusionQuery;
|
||||
|
||||
// These next three are all required for one chunk of code, so glsl is
|
||||
|
@ -2229,6 +2238,7 @@ typedef struct {
|
|||
|
||||
fbo_t *full[2]; // full resolution, shared zbuffer
|
||||
fbo_t *quarter[2]; // quarter resolution, no zbuffer
|
||||
fbo_t *tiny[2]; // 1/16 resolution, no zbuffer
|
||||
|
||||
int numFBOs;
|
||||
fbo_t *fbos[1024];
|
||||
|
@ -2352,6 +2362,10 @@ typedef struct {
|
|||
int numSkins;
|
||||
skin_t *skins[MAX_SKINS];
|
||||
|
||||
GLuint sunFlareQuery[2];
|
||||
int sunFlareQueryIndex;
|
||||
qboolean sunFlareQueryActive[2];
|
||||
|
||||
float sinTable[FUNCTABLE_SIZE];
|
||||
float squareTable[FUNCTABLE_SIZE];
|
||||
float triangleTable[FUNCTABLE_SIZE];
|
||||
|
|
|
@ -158,6 +158,35 @@ static void RB_RadialBlur(int passes, float stretch, float x, float y, float w,
|
|||
RB_Color4f(1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
|
||||
static qboolean RB_UpdateSunFlareVis(void)
|
||||
{
|
||||
GLuint sampleCount = 0;
|
||||
if (!glRefConfig.occlusionQuery)
|
||||
return qtrue;
|
||||
|
||||
tr.sunFlareQueryIndex ^= 1;
|
||||
if (!tr.sunFlareQueryActive[tr.sunFlareQueryIndex])
|
||||
return qtrue;
|
||||
|
||||
/* debug code */
|
||||
if (0)
|
||||
{
|
||||
int iter;
|
||||
for (iter=0 ; ; ++iter)
|
||||
{
|
||||
GLint available = 0;
|
||||
qglGetQueryObjectivARB(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
|
||||
if (available)
|
||||
break;
|
||||
}
|
||||
|
||||
ri.Printf(PRINT_DEVELOPER, "Waited %d iterations\n", iter);
|
||||
}
|
||||
|
||||
qglGetQueryObjectuivARB(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT_ARB, &sampleCount);
|
||||
return sampleCount > 0;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
RB_GodRays
|
||||
|
@ -186,6 +215,9 @@ static void RB_GodRays(void)
|
|||
if (dot < cutoff)
|
||||
return;
|
||||
|
||||
if (!RB_UpdateSunFlareVis())
|
||||
return;
|
||||
|
||||
VectorCopy(backEnd.sunFlarePos, pos);
|
||||
pos[3] = 1.f;
|
||||
|
||||
|
@ -202,8 +234,8 @@ static void RB_GodRays(void)
|
|||
// viewport dimensions
|
||||
w = glConfig.vidWidth;
|
||||
h = glConfig.vidHeight;
|
||||
w2 = w * 0.5f;
|
||||
h2 = h * 0.5f;
|
||||
w2 = glConfig.vidWidth / 2;
|
||||
h2 = glConfig.vidHeight / 2;
|
||||
|
||||
// initialize quarter buffers
|
||||
{
|
||||
|
@ -212,7 +244,7 @@ static void RB_GodRays(void)
|
|||
RB_SetGL2D_Level(1);
|
||||
|
||||
GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
|
||||
RB_Color4f(1.f, 1.f, 1.f, 1.f);
|
||||
RB_Color4f(mul, mul, mul, 1.f);
|
||||
|
||||
// first, downsample the main framebuffers
|
||||
R_FBO_Bind(tr.fbo.quarter[0]);
|
||||
|
@ -245,15 +277,67 @@ static void RB_GodRays(void)
|
|||
|
||||
// add result back on top of the main buffer
|
||||
{
|
||||
float mul = 1.f;
|
||||
R_FBO_BindColorBuffer(R_FBO_Bind(tr.fbo.full[0]), 0);
|
||||
RB_SetGL2D_Level(0);
|
||||
GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
|
||||
|
||||
RB_Color4f(1.f, 1.f, 1.f, 1.f);
|
||||
RB_Color4f(mul, mul, mul, 1.f);
|
||||
RB_DrawQuad(0.f, 0.f, w, h, 0.f, 0.f, 1.f, 1.f);
|
||||
}
|
||||
}
|
||||
|
||||
static void RB_BlurAxis(float w, float h, qboolean horizontal)
|
||||
{
|
||||
float dx, dy;
|
||||
float xmul, ymul;
|
||||
float weights[3] = {
|
||||
0.316216216f,
|
||||
0.227027027f,
|
||||
0.070270270f,
|
||||
};
|
||||
float offsets[3] = {
|
||||
0.f,
|
||||
1.3846153846f,
|
||||
3.2307692308f,
|
||||
};
|
||||
|
||||
xmul = horizontal;
|
||||
ymul = 1.f - xmul;
|
||||
|
||||
xmul /= w;
|
||||
ymul /= h;
|
||||
|
||||
GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
|
||||
|
||||
RB_Color4f(weights[0], weights[0], weights[0], 1.f);
|
||||
RB_DrawQuad(0.f, 0.f, w, h, 0.f, 0.f, 1.f, 1.f);
|
||||
|
||||
GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
|
||||
|
||||
RB_Color4f(weights[1], weights[1], weights[1], 1.f);
|
||||
dx = offsets[1] * xmul;
|
||||
dy = offsets[1] * ymul;
|
||||
RB_DrawQuad(0.f, 0.f, w, h, dx, dy, 1.f+dx, 1.f+dy);
|
||||
RB_DrawQuad(0.f, 0.f, w, h, -dx, -dy, 1.f-dx, 1.f-dy);
|
||||
|
||||
RB_Color4f(weights[2], weights[2], weights[2], 1.f);
|
||||
dx = offsets[2] * xmul;
|
||||
dy = offsets[2] * ymul;
|
||||
RB_DrawQuad(0.f, 0.f, w, h, dx, dy, 1.f+dx, 1.f+dy);
|
||||
RB_DrawQuad(0.f, 0.f, w, h, -dx, -dy, 1.f-dx, 1.f-dy);
|
||||
}
|
||||
|
||||
static void RB_HBlur(float w, float h)
|
||||
{
|
||||
RB_BlurAxis(w, h, qtrue);
|
||||
}
|
||||
|
||||
static void RB_VBlur(float w, float h)
|
||||
{
|
||||
RB_BlurAxis(w, h, qfalse);
|
||||
}
|
||||
|
||||
void RB_FBO_Set2D(void)
|
||||
{
|
||||
RB_DrawQuad = NULL;
|
||||
|
@ -321,6 +405,12 @@ void RB_FBO_Blit(void)
|
|||
R_FBO_BindColorBuffer(fbo, 0);
|
||||
GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
|
||||
|
||||
if (glRefConfig.glslOverbright)
|
||||
{
|
||||
float mul = 1.f / tr.identityLight;
|
||||
RB_Color4f(mul, mul, mul, 1.f);
|
||||
}
|
||||
|
||||
RB_DrawQuad(0.f, 0.f, glConfig.vidWidth, glConfig.vidHeight, 0.f, 0.f, 1.f, 1.f);
|
||||
|
||||
R_FBO_Bind(fbo);
|
||||
|
@ -334,7 +424,7 @@ RB_PostProcess
|
|||
|
||||
void RB_PostProcess(void)
|
||||
{
|
||||
if (!glState.currentFBO)
|
||||
if (!glState.currentFBO || backEnd.refdef.rdflags & RDF_NOWORLDMODEL)
|
||||
return;
|
||||
|
||||
RB_FBO_Set2D();
|
||||
|
|
Loading…
Reference in a new issue