diff --git a/reaction/code/renderer/qglextensions.h b/reaction/code/renderer/qglextensions.h index e5123e77..575ab38c 100644 --- a/reaction/code/renderer/qglextensions.h +++ b/reaction/code/renderer/qglextensions.h @@ -14,17 +14,21 @@ HANDLE_EXT_FUNC( PFNGLRENDERBUFFERSTORAGEEXTPROC, glRenderbufferStorageEXT) \ HANDLE_EXT_FUNC( PFNGLBINDRENDERBUFFEREXTPROC, glBindRenderbufferEXT) \ -#define GL_ARB_occlusion_query_functions \ - HANDLE_EXT_FUNC( PFNGLGENQUERIESARBPROC, glGenQueriesARB) \ - HANDLE_EXT_FUNC( PFNGLDELETEQUERIESARBPROC, glDeleteQueriesARB) \ - HANDLE_EXT_FUNC( PFNGLISQUERYARBPROC, glIsQueryARB) \ - HANDLE_EXT_FUNC( PFNGLBEGINQUERYARBPROC, glBeginQueryARB) \ - HANDLE_EXT_FUNC( PFNGLENDQUERYARBPROC, glEndQueryARB) \ - HANDLE_EXT_FUNC( PFNGLGETQUERYIVARBPROC, glGetQueryivARB) \ - HANDLE_EXT_FUNC( PFNGLGETQUERYOBJECTIVARBPROC, glGetQueryObjectivARB) \ - HANDLE_EXT_FUNC( PFNGLGETQUERYOBJECTUIVARBPROC, glGetQueryObjectuivARB) \ +#define GL_ARB_occlusion_query_functions \ + HANDLE_EXT_FUNC( PFNGLGENQUERIESARBPROC, glGenQueriesARB) \ + HANDLE_EXT_FUNC( PFNGLDELETEQUERIESARBPROC, glDeleteQueriesARB) \ + HANDLE_EXT_FUNC( PFNGLISQUERYARBPROC, glIsQueryARB) \ + HANDLE_EXT_FUNC( PFNGLBEGINQUERYARBPROC, glBeginQueryARB) \ + HANDLE_EXT_FUNC( PFNGLENDQUERYARBPROC, glEndQueryARB) \ + HANDLE_EXT_FUNC( PFNGLGETQUERYIVARBPROC, glGetQueryivARB) \ + 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 diff --git a/reaction/code/renderer/tr_backend.c b/reaction/code/renderer/tr_backend.c index 2abefbae..1ac51990 100644 --- a/reaction/code/renderer/tr_backend.c +++ b/reaction/code/renderer/tr_backend.c @@ -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 diff --git a/reaction/code/renderer/tr_fbo.c b/reaction/code/renderer/tr_fbo.c index 93523e2e..75b96dcf 100644 --- a/reaction/code/renderer/tr_fbo.c +++ b/reaction/code/renderer/tr_fbo.c @@ -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); } diff --git a/reaction/code/renderer/tr_image.c b/reaction/code/renderer/tr_image.c index 431e2d4b..5d79f826 100644 --- a/reaction/code/renderer/tr_image.c +++ b/reaction/code/renderer/tr_image.c @@ -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) { - internalFormat = GL_RGBA8; - qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + 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; diff --git a/reaction/code/renderer/tr_init.c b/reaction/code/renderer/tr_init.c index e0482005..82dc451b 100644 --- a/reaction/code/renderer/tr_init.c +++ b/reaction/code/renderer/tr_init.c @@ -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; @@ -437,6 +438,8 @@ const void *RB_TakeScreenshotCmd( const void *data ) { RB_TakeScreenshotJPEG( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName); else RB_TakeScreenshot( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName); + + R_FBO_Bind(fbo); return (const void *)(cmd + 1); } @@ -708,14 +711,19 @@ RB_TakeVideoFrameCmd const void *RB_TakeVideoFrameCmd( const void *data ) { const videoFrameCommand_t *cmd; - int frameSize; - int i; + 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); } /* diff --git a/reaction/code/renderer/tr_local.h b/reaction/code/renderer/tr_local.h index 5876f3a1..51b7e814 100644 --- a/reaction/code/renderer/tr_local.h +++ b/reaction/code/renderer/tr_local.h @@ -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]; diff --git a/reaction/code/renderer/tr_postprocess.c b/reaction/code/renderer/tr_postprocess.c index a870d95e..1fce71ab 100644 --- a/reaction/code/renderer/tr_postprocess.c +++ b/reaction/code/renderer/tr_postprocess.c @@ -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();