diff --git a/neo/renderer/RenderSystem_init.cpp b/neo/renderer/RenderSystem_init.cpp index e60bf952..0b3df948 100644 --- a/neo/renderer/RenderSystem_init.cpp +++ b/neo/renderer/RenderSystem_init.cpp @@ -49,7 +49,7 @@ If you have questions concerning this license or the applicable additional terms glconfig_t glConfig; -const char *r_rendererArgs[] = { "best", "arb", "arb2", "exp", "nv10", "nv20", "r200", NULL }; +const char *r_rendererArgs[] = { "best", "arb", "arb2", "nv10", "nv20", "r200", NULL }; idCVar r_inhibitFragmentProgram( "r_inhibitFragmentProgram", "0", CVAR_RENDERER | CVAR_BOOL, "ignore the fragment program extension" ); idCVar r_useLightPortalFlow( "r_useLightPortalFlow", "1", CVAR_RENDERER | CVAR_BOOL, "use a more precise area reference determination" ); diff --git a/neo/renderer/draw_exp.cpp b/neo/renderer/draw_exp.cpp deleted file mode 100644 index 812aab72..00000000 --- a/neo/renderer/draw_exp.cpp +++ /dev/null @@ -1,2652 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code 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 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code 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 Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "sys/win32/win_local.h" - -#include "renderer/tr_local.h" - -/* - -strictly experimental / research codepaths - -!!!if we use front facing occluders, we can portal flow from light centers - -try depth_component_16 rendering - -do we care about portals from light perspective? back / front face issues. - -how do we do weapon depth hacks with shadow buffers? - distort their world space vertexes instead of offsetting their depth? - -jittering off the side of a projection will give wrong shadows - -really huge lights, like sunlight, are going to be problematic with fixed projections - we could tile the projections and let the auto-resize cut them down as necessary - -It sucks that depth buffers are non-linear, because the bias and compares change with distance - -polygon offset factor causes occasional texture holes from highly angled textures - -*/ - -// WGL_ARB_pixel_format -static PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB; - -// WGL_ARB_pixel_format -static PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB; -static PFNWGLGETPIXELFORMATATTRIBFVARBPROC wglGetPixelFormatAttribfvARB; - -// WGL_ARB_pbuffer -static PFNWGLCREATEPBUFFERARBPROC wglCreatePbufferARB; -static PFNWGLGETPBUFFERDCARBPROC wglGetPbufferDCARB; -static PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB; -static PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB; -static PFNWGLQUERYPBUFFERARBPROC wglQueryPbufferARB; - -// WGL_ARB_render_texture -static PFNWGLBINDTEXIMAGEARBPROC wglBindTexImageARB; -static PFNWGLRELEASETEXIMAGEARBPROC wglReleaseTexImageARB; -static PFNWGLSETPBUFFERATTRIBARBPROC wglSetPbufferAttribARB; - -static bool initialized; - -static int lightBufferSize = 1024; -static int maxLightBufferSize = 1024; -static float lightBufferSizeFraction = 0.5; - -static int viewBufferSize = 1024; -static int viewBufferHeight = 768; -static int maxViewBufferSize = 1024; -static float viewBufferSizeFraction = 0.5; -static float viewBufferHeightFraction = 0.5; -static bool nativeViewBuffer = false; // true if viewBufferSize is the viewport width - -static HPBUFFERARB floatPbuffer; -static HDC floatPbufferDC; -static idImage *floatPbufferImage; - -static HPBUFFERARB floatPbuffer2; -static HDC floatPbuffer2DC; -static idImage *floatPbuffer2Image; - -static HPBUFFERARB floatPbufferQuarter; -static HDC floatPbufferQuarterDC; -static idImage *floatPbufferQuarterImage; - -static HGLRC floatContext; - -static HPBUFFERARB shadowPbuffer; -static HDC shadowPbufferDC; - -static HPBUFFERARB viewPbuffer; -static HDC viewPbufferDC; - -static idImage *shadowImage[3]; - -static idImage *viewDepthImage; -static idImage *viewAlphaImage; - -static idImage *viewShadowImage; - -static idImage *jitterImage16; -static idImage *jitterImage4; -static idImage *jitterImage1; - -static idImage *random256Image; - -static int shadowVertexProgram; -static int shadowFragmentProgram16; -static int shadowFragmentProgram4; -static int shadowFragmentProgram1; -static int shadowFragmentProgram0; - -static int screenSpaceShadowVertexProgram; -static int screenSpaceShadowFragmentProgram16; -static int screenSpaceShadowFragmentProgram4; -static int screenSpaceShadowFragmentProgram1; -static int screenSpaceShadowFragmentProgram0; - -static int depthMidpointVertexProgram; -static int depthMidpointFragmentProgram; - -static int shadowResampleVertexProgram; -static int shadowResampleFragmentProgram; - -static int gammaDitherVertexProgram; -static int gammaDitherFragmentProgram; - -static int downSampleVertexProgram; -static int downSampleFragmentProgram; - -static int bloomVertexProgram; -static int bloomFragmentProgram; - -static float viewLightAxialSize; - -idCVar r_sb_lightResolution( "r_sb_lightResolution", "1024", CVAR_RENDERER | CVAR_INTEGER, "Pixel dimensions for each shadow buffer, 64 - 2048" ); -idCVar r_sb_viewResolution( "r_sb_viewResolution", "1024", CVAR_RENDERER | CVAR_INTEGER, "Width of screen space shadow sampling" ); -idCVar r_sb_noShadows( "r_sb_noShadows", "0", CVAR_RENDERER | CVAR_BOOL, "don't draw any occluders" ); -idCVar r_sb_usePbuffer( "r_sb_usePbuffer", "1", CVAR_RENDERER | CVAR_BOOL, "draw offscreen" ); -idCVar r_sb_jitterScale( "r_sb_jitterScale", "0.006", CVAR_RENDERER | CVAR_FLOAT, "scale factor for jitter offset" ); -idCVar r_sb_biasScale( "r_sb_biasScale", "0.0001", CVAR_RENDERER | CVAR_FLOAT, "scale factor for jitter bias" ); -idCVar r_sb_samples( "r_sb_samples", "4", CVAR_RENDERER | CVAR_INTEGER, "0, 1, 4, or 16" ); -idCVar r_sb_randomize( "r_sb_randomize", "1", CVAR_RENDERER | CVAR_BOOL, "randomly offset jitter texture each draw" ); -// polyOfsFactor causes holes in low res images -idCVar r_sb_polyOfsFactor( "r_sb_polyOfsFactor", "2", CVAR_RENDERER | CVAR_FLOAT, "polygonOffset factor for drawing shadow buffer" ); -idCVar r_sb_polyOfsUnits( "r_sb_polyOfsUnits", "3000", CVAR_RENDERER | CVAR_FLOAT, "polygonOffset units for drawing shadow buffer" ); -idCVar r_sb_occluderFacing( "r_sb_occluderFacing", "0", CVAR_RENDERER | CVAR_INTEGER, "0 = front faces, 1 = back faces, 2 = midway between" ); -// r_sb_randomizeBufferOrientation? - -idCVar r_sb_frustomFOV( "r_sb_frustomFOV", "92", CVAR_RENDERER | CVAR_FLOAT, "oversize FOV for point light side matching" ); -idCVar r_sb_showFrustumPixels( "r_sb_showFrustumPixels", "0", CVAR_RENDERER | CVAR_BOOL, "color the pixels contained in the frustum" ); -idCVar r_sb_singleSide( "r_sb_singleSide", "-1", CVAR_RENDERER | CVAR_INTEGER, "only draw a single side (0-5) of point lights" ); -idCVar r_sb_useCulling( "r_sb_useCulling", "1", CVAR_RENDERER | CVAR_BOOL, "cull geometry to individual side frustums" ); -idCVar r_sb_linearFilter( "r_sb_linearFilter", "1", CVAR_RENDERER | CVAR_BOOL, "use GL_LINEAR instead of GL_NEAREST on shadow maps" ); - -idCVar r_sb_screenSpaceShadow( "r_sb_screenSpaceShadow", "1", CVAR_RENDERER | CVAR_BOOL, "build shadows in screen space instead of on surfaces" ); - -idCVar r_hdr_useFloats( "r_hdr_useFloats", "0", CVAR_RENDERER | CVAR_BOOL, "use a floating point rendering buffer" ); -idCVar r_hdr_exposure( "r_hdr_exposure", "1.0", CVAR_RENDERER | CVAR_FLOAT, "maximum light scale" ); -idCVar r_hdr_bloomFraction( "r_hdr_bloomFraction", "0.1", CVAR_RENDERER | CVAR_FLOAT, "fraction to smear across neighbors" ); -idCVar r_hdr_gamma( "r_hdr_gamma", "1", CVAR_RENDERER | CVAR_FLOAT, "monitor gamma power" ); -idCVar r_hdr_monitorDither( "r_hdr_monitorDither", "0.01", CVAR_RENDERER | CVAR_FLOAT, "random dither in monitor space" ); - -// from world space to light origin, looking down the X axis -static float unflippedLightMatrix[16]; - -// from world space to OpenGL view space, looking down the negative Z axis -static float lightMatrix[16]; - -// from OpenGL view space to OpenGL NDC ( -1 : 1 in XYZ ) -static float lightProjectionMatrix[16]; - - -void RB_ARB2_DrawInteraction( const drawInteraction_t *din ); - -typedef struct { - const char *name; - int num; -} wglString_t; - -wglString_t wglString[] = { -{ "WGL_NUMBER_PIXEL_FORMATS_ARB", 0x2000 }, -{ "WGL_DRAW_TO_WINDOW_ARB", 0x2001 }, -{ "WGL_DRAW_TO_BITMAP_ARB", 0x2002 }, -{ "WGL_ACCELERATION_ARB", 0x2003 }, -{ "WGL_NEED_PALETTE_ARB", 0x2004 }, -{ "WGL_NEED_SYSTEM_PALETTE_ARB", 0x2005 }, -{ "WGL_SWAP_LAYER_BUFFERS_ARB", 0x2006 }, -{ "WGL_SWAP_METHOD_ARB", 0x2007 }, -{ "WGL_NUMBER_OVERLAYS_ARB", 0x2008 }, -{ "WGL_NUMBER_UNDERLAYS_ARB", 0x2009 }, -{ "WGL_TRANSPARENT_ARB", 0x200A }, -{ "WGL_TRANSPARENT_RED_VALUE_ARB", 0x2037 }, -{ "WGL_TRANSPARENT_GREEN_VALUE_ARB", 0x2038 }, -{ "WGL_TRANSPARENT_BLUE_VALUE_ARB", 0x2039 }, -{ "WGL_TRANSPARENT_ALPHA_VALUE_ARB", 0x203A }, -{ "WGL_TRANSPARENT_INDEX_VALUE_ARB", 0x203B }, -{ "WGL_SHARE_DEPTH_ARB", 0x200C }, -{ "WGL_SHARE_STENCIL_ARB", 0x200D }, -{ "WGL_SHARE_ACCUM_ARB", 0x200E }, -{ "WGL_SUPPORT_GDI_ARB", 0x200F }, -{ "WGL_SUPPORT_OPENGL_ARB", 0x2010 }, -{ "WGL_DOUBLE_BUFFER_ARB", 0x2011 }, -{ "WGL_STEREO_ARB", 0x2012 }, -{ "WGL_PIXEL_TYPE_ARB", 0x2013 }, -{ "WGL_COLOR_BITS_ARB", 0x2014 }, -{ "WGL_RED_BITS_ARB", 0x2015 }, -{ "WGL_RED_SHIFT_ARB", 0x2016 }, -{ "WGL_GREEN_BITS_ARB", 0x2017 }, -{ "WGL_GREEN_SHIFT_ARB", 0x2018 }, -{ "WGL_BLUE_BITS_ARB", 0x2019 }, -{ "WGL_BLUE_SHIFT_ARB", 0x201A }, -{ "WGL_ALPHA_BITS_ARB", 0x201B }, -{ "WGL_ALPHA_SHIFT_ARB", 0x201C }, -{ "WGL_ACCUM_BITS_ARB", 0x201D }, -{ "WGL_ACCUM_RED_BITS_ARB", 0x201E }, -{ "WGL_ACCUM_GREEN_BITS_ARB", 0x201F }, -{ "WGL_ACCUM_BLUE_BITS_ARB", 0x2020 }, -{ "WGL_ACCUM_ALPHA_BITS_ARB", 0x2021 }, -{ "WGL_DEPTH_BITS_ARB", 0x2022 }, -{ "WGL_STENCIL_BITS_ARB", 0x2023 }, -{ "WGL_AUX_BUFFERS_ARB", 0x2024 }, - -{ "WGL_NO_ACCELERATION_ARB", 0x2025 }, -{ "WGL_GENERIC_ACCELERATION_ARB", 0x2026 }, -{ "WGL_FULL_ACCELERATION_ARB", 0x2027 }, - -{ "WGL_SWAP_EXCHANGE_ARB", 0x2028 }, -{ "WGL_SWAP_COPY_ARB", 0x2029 }, -{ "WGL_SWAP_UNDEFINED_ARB", 0x202A }, - -{ "WGL_TYPE_RGBA_ARB", 0x202B }, -{ "WGL_TYPE_COLORINDEX_ARB", 0x202C }, -}; - -static const int NUM_WGL_STRINGS = sizeof( wglString ) / sizeof( wglString[0] ); - -static void R_CheckWglErrors( void ) { - int err = GetLastError(); - char *name; - -#if 0 - LPVOID lpMsgBuf; - FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - err, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPTSTR) &lpMsgBuf, - 0, - NULL - ); -#endif - err &= 0xffff; - switch ( err ) { - case 13: name = "ERROR_INVALID_DATA"; break; - case 6: name = "ERROR_INVALID_HANDLE"; break; - case 4317: name = "ERROR_INVALID_OPERATION"; break; - default: name = va( "code %i", err ); break; - } - - common->Printf( "GetLastError: %s\n", name ); -} - -static void R_MakeCurrent( HDC dc, HGLRC context, HPBUFFERARB pbuffer ) { - if ( pbuffer ) { - if ( !wglReleaseTexImageARB( pbuffer, WGL_FRONT_LEFT_ARB ) ) { - R_CheckWglErrors(); - common->Error( "wglReleaseTexImageARB failed" ); - } - } - if ( !qwglMakeCurrent( dc, context ) ) { - R_CheckWglErrors(); - common->FatalError( "qwglMakeCurrent failed" ); - } -} - -static void R_BindTexImage( HPBUFFERARB pbuffer ) { - if ( !wglReleaseTexImageARB( pbuffer, WGL_FRONT_LEFT_ARB ) ) { - R_CheckWglErrors(); - common->Error( "wglReleaseTexImageARB failed" ); - } - if ( !wglBindTexImageARB( pbuffer, WGL_FRONT_LEFT_ARB ) ) { - R_CheckWglErrors(); - common->Error( "failed wglBindTexImageARB" ); - } -} - -static void R_ReportTextureParms( void ) { - int parms[8]; - -// q glGetTexParameteriv( GL_TEXTURE_RECTANGLE_NV, - qglGetIntegerv( GL_TEXTURE_BINDING_RECTANGLE_NV, parms ); - -} - -/* -==================== -RB_CreateBloomTable -==================== -*/ -static const int BLOOM_RADIUS = 8; -static void RB_CreateBloomTable( void ) { - float bloom[BLOOM_RADIUS]; - float total = 0; - - // gaussian - float stdDev = 2.0; - for ( int i = 0 ; i < BLOOM_RADIUS ; i++ ) { - float f = (float)i / stdDev; - bloom[i] = exp( -0.5 * f * f ); - total += bloom[i]; - } - - total = ( total - bloom[0] ) * 2 + bloom[0]; - - // normalize to 1.0 contribution, so a full row or column will equal 1.0 - for ( int i = 0 ; i < BLOOM_RADIUS ; i++ ) { - bloom[i] *= 1.0 / total; - common->Printf( "PARAM bloom%i = { %f };\n", i, bloom[i] ); - } - -} - -/* -==================== -GL_SelectTextureNoClient -==================== -*/ -static void GL_SelectTextureNoClient( int unit ) { - backEnd.glState.currenttmu = unit; - qglActiveTextureARB( GL_TEXTURE0_ARB + unit ); -} - - -/* -================ -R_CreateShadowBufferImage - -================ -*/ -static void R_CreateShadowBufferImage( idImage *image ) { - byte *data = (byte *)Mem_Alloc( lightBufferSize*lightBufferSize ); - - memset( data, 0, lightBufferSize*lightBufferSize ); - - image->GenerateImage( (byte *)data, 4, 4, - TF_LINEAR, false, TR_CLAMP_TO_BORDER, TD_HIGH_QUALITY ); - - // now reset it to a shadow depth image - GL_CheckErrors(); - image->uploadWidth = image->uploadHeight = lightBufferSize; - qglTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24_ARB, lightBufferSize, lightBufferSize, - 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, data ); - - qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE ); -// qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE ); - qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL ); - - // explicit zero depth border - float color[4]; - color[0] = color[1] = color[2] = color[3] = 0; - qglTexParameterfv( GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color ); - - GL_CheckErrors(); - - Mem_Free( data ); -} - -static void R_CreateViewAlphaImage( idImage *image ) { - int c = viewBufferSize*viewBufferSize*4; - byte *data = (byte *)Mem_Alloc( c ); - - // don't let it pick an intensity format - for ( int i = 0 ; i < c ; i++ ) { - data[i] = i; - } - memset( data, 0, viewBufferSize*viewBufferSize ); - - image->GenerateImage( (byte *)data, viewBufferSize, viewBufferSize, - TF_LINEAR, false, TR_CLAMP, TD_HIGH_QUALITY ); -} - -static void R_CreateStubImage( idImage *image ) { - float data[3][4][4]; - - // generate the texture number - qglGenTextures( 1, &image->texnum ); - qglBindTexture( GL_TEXTURE_RECTANGLE_NV, image->texnum ); - memset( data, 0, sizeof( data ) ); - glTexImage2D( GL_TEXTURE_RECTANGLE_NV, 0, GL_FLOAT_RGBA16_NV, 4, 3, 0, GL_RGBA, GL_FLOAT, &data ); -} - -/* -================ -R_CreateJitterImage - -================ -*/ -const static int JITTER_SIZE = 128; -static void R_CreateJitterImage16( idImage *image ) { - byte data[JITTER_SIZE][JITTER_SIZE*16][4]; - - for ( int i = 0 ; i < JITTER_SIZE ; i++ ) { - for ( int s = 0 ; s < 16 ; s++ ) { - int sOfs = 64 * ( s & 3 ); - int tOfs = 64 * ( ( s >> 2 ) & 3 ); - - for ( int j = 0 ; j < JITTER_SIZE ; j++ ) { - data[i][s*JITTER_SIZE+j][0] = (rand() & 63 ) | sOfs; - data[i][s*JITTER_SIZE+j][1] = (rand() & 63 ) | tOfs; - data[i][s*JITTER_SIZE+j][2] = rand(); - data[i][s*JITTER_SIZE+j][3] = 0; - } - } - } - - image->GenerateImage( (byte *)data, JITTER_SIZE*16, JITTER_SIZE, - TF_NEAREST, false, TR_REPEAT, TD_HIGH_QUALITY ); -} - -static void R_CreateJitterImage4( idImage *image ) { - byte data[JITTER_SIZE][JITTER_SIZE*4][4]; - - for ( int i = 0 ; i < JITTER_SIZE ; i++ ) { - for ( int s = 0 ; s < 4 ; s++ ) { - int sOfs = 128 * ( s & 1 ); - int tOfs = 128 * ( ( s >> 1 ) & 1 ); - - for ( int j = 0 ; j < JITTER_SIZE ; j++ ) { - data[i][s*JITTER_SIZE+j][0] = (rand() & 127 ) | sOfs; - data[i][s*JITTER_SIZE+j][1] = (rand() & 127 ) | tOfs; - data[i][s*JITTER_SIZE+j][2] = rand(); - data[i][s*JITTER_SIZE+j][3] = 0; - } - } - } - - image->GenerateImage( (byte *)data, JITTER_SIZE*4, JITTER_SIZE, - TF_NEAREST, false, TR_REPEAT, TD_HIGH_QUALITY ); -} - -static void R_CreateJitterImage1( idImage *image ) { - byte data[JITTER_SIZE][JITTER_SIZE][4]; - - for ( int i = 0 ; i < JITTER_SIZE ; i++ ) { - for ( int j = 0 ; j < JITTER_SIZE ; j++ ) { - data[i][j][0] = rand(); - data[i][j][1] = rand(); - data[i][j][2] = rand(); - data[i][j][3] = 0; - } - } - - image->GenerateImage( (byte *)data, JITTER_SIZE, JITTER_SIZE, - TF_NEAREST, false, TR_REPEAT, TD_HIGH_QUALITY ); -} - -static void R_CreateRandom256Image( idImage *image ) { - byte data[256][256][4]; - - for ( int i = 0 ; i < 256 ; i++ ) { - for ( int j = 0 ; j < 256 ; j++ ) { - data[i][j][0] = rand(); - data[i][j][1] = rand(); - data[i][j][2] = rand(); - data[i][j][3] = rand(); - } - } - - image->GenerateImage( (byte *)data, 256, 256, - TF_NEAREST, false, TR_REPEAT, TD_HIGH_QUALITY ); -} - - -/* -================== -R_PrintPixelFormat -================== -*/ -void R_PrintPixelFormat( int pixelFormat ) { - int res; - int iAttribute; - int iValue; - - common->Printf( "----- pixelFormat %i -----\n", pixelFormat ); - - for ( int i = 1 ; i < NUM_WGL_STRINGS ; i++ ) { - iAttribute = wglString[i].num; - res = wglGetPixelFormatAttribivARB( win32.hDC, pixelFormat, 0, 1, &iAttribute, &iValue ); - if ( res && iValue ) { - common->Printf( "%s : %i\n", wglString[i].name, iValue ); - } - } -} - - -/* -================== -R_Exp_Allocate -================== -*/ -void R_Exp_Allocate( void ) { - // find a pixel format for our floating point pbuffer - int iAttributes[NUM_WGL_STRINGS*2], *atr_p; - FLOAT fAttributes[] = {0, 0}; - UINT numFormats; - int pixelformats[1024]; - int ret; - int pbiAttributes[] = {0, 0}; - - initialized = true; - - // WGL_ARB_pixel_format - wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)GLimp_ExtensionPointer("wglChoosePixelFormatARB"); - - // WGL_ARB_pixel_format - wglGetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)GLimp_ExtensionPointer("wglGetPixelFormatAttribivARB"); - wglGetPixelFormatAttribfvARB = (PFNWGLGETPIXELFORMATATTRIBFVARBPROC)GLimp_ExtensionPointer("wglGetPixelFormatAttribfvARB"); - - // WGL_ARB_pbuffer - wglCreatePbufferARB = (PFNWGLCREATEPBUFFERARBPROC)GLimp_ExtensionPointer("wglCreatePbufferARB"); - wglGetPbufferDCARB = (PFNWGLGETPBUFFERDCARBPROC)GLimp_ExtensionPointer("wglGetPbufferDCARB"); - wglReleasePbufferDCARB = (PFNWGLRELEASEPBUFFERDCARBPROC)GLimp_ExtensionPointer("wglReleasePbufferDCARB"); - wglDestroyPbufferARB = (PFNWGLDESTROYPBUFFERARBPROC)GLimp_ExtensionPointer("wglDestroyPbufferARB"); - wglQueryPbufferARB = (PFNWGLQUERYPBUFFERARBPROC)GLimp_ExtensionPointer("wglQueryPbufferARB"); - - // WGL_ARB_render_texture - wglBindTexImageARB = (PFNWGLBINDTEXIMAGEARBPROC)GLimp_ExtensionPointer("wglBindTexImageARB"); - wglReleaseTexImageARB = (PFNWGLRELEASETEXIMAGEARBPROC)GLimp_ExtensionPointer("wglReleaseTexImageARB"); - wglSetPbufferAttribARB = (PFNWGLSETPBUFFERATTRIBARBPROC)GLimp_ExtensionPointer("wglSetPbufferAttribARB"); - -#if 1 - // - // allocate the floating point rendering buffer - // - atr_p = iAttributes; - - *atr_p++ = WGL_DRAW_TO_PBUFFER_ARB; - *atr_p++ = TRUE; - *atr_p++ = WGL_FLOAT_COMPONENTS_NV; - *atr_p++ = TRUE; - *atr_p++ = WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV; - *atr_p++ = TRUE; -// *atr_p++ = WGL_BIND_TO_TEXTURE_RGBA_ARB; -// *atr_p++ = TRUE; - *atr_p++ = WGL_DEPTH_BITS_ARB; - *atr_p++ = 24; - *atr_p++ = WGL_STENCIL_BITS_ARB; - *atr_p++ = 8; - *atr_p++ = 0; - *atr_p++ = 0; - - ret = wglChoosePixelFormatARB( win32.hDC, iAttributes, fAttributes, - sizeof( pixelformats ) / sizeof( pixelformats[0] ), pixelformats, &numFormats ); - -#if 0 - for ( int i = 0 ; i < (int)numFormats ; i++ ) { - R_PrintPixelFormat( pixelformats[i] ); - } -#endif - common->Printf( "\nfloatPbuffer:\n" ); - R_PrintPixelFormat( pixelformats[0] ); - - // allocate a pbuffer with this pixel format - int pbiAttributesTexture[] = { - WGL_TEXTURE_FORMAT_ARB, WGL_TEXTURE_FLOAT_RGBA_NV, - WGL_TEXTURE_TARGET_ARB, WGL_TEXTURE_RECTANGLE_NV, // WGL_TEXTURE_2D_ARB, - 0, 0}; - - floatPbuffer = wglCreatePbufferARB( win32.hDC, pixelformats[0], glConfig.vidWidth, - glConfig.vidHeight, pbiAttributesTexture ); - if ( !floatPbuffer ) { - common->Printf( "failed to create floatPbuffer.\n" ); - GL_CheckErrors(); - } - floatPbufferDC = wglGetPbufferDCARB( floatPbuffer ); - floatPbufferImage = globalImages->ImageFromFunction( "_floatPbuffer", R_CreateStubImage ); - - // create a second buffer for ping-pong operations - floatPbuffer2 = wglCreatePbufferARB( win32.hDC, pixelformats[0], glConfig.vidWidth, - glConfig.vidHeight, pbiAttributesTexture ); - if ( !floatPbuffer2 ) { - common->Printf( "failed to create floatPbuffer.\n" ); - GL_CheckErrors(); - } - floatPbuffer2DC = wglGetPbufferDCARB( floatPbuffer2 ); - floatPbuffer2Image = globalImages->ImageFromFunction( "_floatPbuffer2", R_CreateStubImage ); - - // create a third buffer for down sampling operations - floatPbufferQuarter = wglCreatePbufferARB( win32.hDC, pixelformats[0], glConfig.vidWidth / 4, - glConfig.vidHeight / 4, pbiAttributesTexture ); - if ( !floatPbufferQuarter ) { - common->Printf( "failed to create floatPbuffer.\n" ); - GL_CheckErrors(); - } - floatPbufferQuarterDC = wglGetPbufferDCARB( floatPbufferQuarter ); - floatPbufferQuarterImage = globalImages->ImageFromFunction( "floatPbufferQuarter", R_CreateStubImage ); - - // create a new GL context for this pixel format and share textures - floatContext = wglCreateContext( floatPbufferDC ); - if ( !floatContext ) { - common->Printf( "failed to create context for floatPbufferDC.\n" ); - GL_CheckErrors(); - } - - if ( !wglShareLists( floatContext, win32.hGLRC ) ) { - common->Printf( "failed to share lists.\n" ); - } - - // create a rendering context for this pixel format and share textures - - // allocate a texture for the rendering - -#endif - - //================================================================================= - - // - // allocate the shadow pbuffer - // - atr_p = iAttributes; - - *atr_p++ = WGL_DRAW_TO_PBUFFER_ARB; - *atr_p++ = TRUE; - *atr_p++ = WGL_RED_BITS_ARB; - *atr_p++ = 8; - *atr_p++ = WGL_GREEN_BITS_ARB; - *atr_p++ = 8; - *atr_p++ = WGL_BLUE_BITS_ARB; - *atr_p++ = 8; - *atr_p++ = WGL_ALPHA_BITS_ARB; - *atr_p++ = 8; - *atr_p++ = WGL_DEPTH_BITS_ARB; - *atr_p++ = 24; - *atr_p++ = WGL_STENCIL_BITS_ARB; - *atr_p++ = 8; - *atr_p++ = 0; - *atr_p++ = 0; - - ret = wglChoosePixelFormatARB( win32.hDC, iAttributes, fAttributes, - sizeof( pixelformats ) / sizeof( pixelformats[0] ), pixelformats, &numFormats ); -#if 0 - for ( int i = 0 ; i < (int)numFormats ; i++ ) { - R_PrintPixelFormat( pixelformats[i] ); - } -#endif - common->Printf( "\nshadowPbuffer:\n" ); - R_PrintPixelFormat( pixelformats[0] ); - -pixelformats[0] = win32.pixelformat; // forced to do this by wgl... - - //----------------------------------- - - lightBufferSize = maxLightBufferSize; - - // allocate a pbuffer with this pixel format - shadowPbuffer = wglCreatePbufferARB( win32.hDC, pixelformats[0], lightBufferSize, - lightBufferSize, pbiAttributes ); - - // allocate a rendering context for the pbuffer - shadowPbufferDC = wglGetPbufferDCARB( shadowPbuffer ); - - // generate the texture number - shadowImage[0] = globalImages->ImageFromFunction( va("_shadowBuffer%i_0",lightBufferSize), R_CreateShadowBufferImage ); - shadowImage[1] = globalImages->ImageFromFunction( va("_shadowBuffer%i_1",lightBufferSize), R_CreateShadowBufferImage ); - shadowImage[2] = globalImages->ImageFromFunction( va("_shadowBuffer%i_2",lightBufferSize), R_CreateShadowBufferImage ); - - //----------------------------------- - - lightBufferSize = maxViewBufferSize; - - // allocate a pbuffer with this pixel format - viewPbuffer = wglCreatePbufferARB( win32.hDC, pixelformats[0], maxViewBufferSize, - maxViewBufferSize, pbiAttributes ); - - // allocate a rendering context for the pbuffer - viewPbufferDC = wglGetPbufferDCARB( viewPbuffer ); - - // create the image space depth buffer for image-space shadow trnasforms - viewDepthImage = globalImages->ImageFromFunction("_viewDepth", R_CreateShadowBufferImage ); - - // create the image space shadow alpha buffer for subsampling the shadow calculation - viewAlphaImage = globalImages->ImageFromFunction("_viewAlpha", R_CreateViewAlphaImage ); - - //----------------------------------- - - // generate the jitter image - jitterImage16 = globalImages->ImageFromFunction( "_jitter16", R_CreateJitterImage16 ); - jitterImage4 = globalImages->ImageFromFunction( "_jitter4", R_CreateJitterImage4 ); - jitterImage1 = globalImages->ImageFromFunction( "_jitter1", R_CreateJitterImage1 ); - - depthMidpointVertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "depthMidpoint.vfp" ); - depthMidpointFragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "depthMidpoint.vfp" ); - - shadowResampleVertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "shadowResample.vfp" ); - shadowResampleFragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "shadowResample.vfp" ); - - screenSpaceShadowVertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "screenSpaceShadow1.vfp" ); - - screenSpaceShadowFragmentProgram0 = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "screenSpaceShadow0.vfp" ); - screenSpaceShadowFragmentProgram1 = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "screenSpaceShadow1.vfp" ); - screenSpaceShadowFragmentProgram4 = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "screenSpaceShadow4.vfp" ); - screenSpaceShadowFragmentProgram16 = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "screenSpaceShadow16.vfp" ); - - shadowVertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "shadowBufferInteraction1.vfp" ); - - shadowFragmentProgram0 = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "shadowBufferInteraction0.vfp" ); - shadowFragmentProgram1 = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "shadowBufferInteraction1.vfp" ); - shadowFragmentProgram4 = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "shadowBufferInteraction4.vfp" ); - shadowFragmentProgram16 = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "shadowBufferInteraction16.vfp" ); - - gammaDitherVertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "gammaDither.vfp" ); - gammaDitherFragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "gammaDither.vfp" ); - - downSampleVertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "downSample.vfp" ); - downSampleFragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "downSample.vfp" ); - - bloomVertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "bloom.vfp" ); - bloomFragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "bloom.vfp" ); - - random256Image = globalImages->ImageFromFunction( "_random256", R_CreateRandom256Image ); -} - -//=========================================================================================== - -static const int CULL_RECEIVER = 1; // still draw occluder, but it is out of the view -static const int CULL_OCCLUDER_AND_RECEIVER = 2; // the surface doesn't effect the view at all - -/* -================== -RB_EXP_CullInteractions - -Sets surfaceInteraction_t->cullBits -================== -*/ -void RB_EXP_CullInteractions( viewLight_t *vLight, idPlane frustumPlanes[6] ) { - for ( idInteraction *inter = vLight->lightDef->firstInteraction ; inter ; inter = inter->lightNext ) { - const idRenderEntityLocal *entityDef = inter->entityDef; - if ( !entityDef ) { - continue; - } - if ( inter->numSurfaces < 1 ) { - continue; - } - - int culled = 0; - - if ( r_sb_useCulling.GetBool() ) { - // transform light frustum into object space, positive side points outside the light - idPlane localPlanes[6]; - int plane; - for ( plane = 0 ; plane < 6 ; plane++ ) { - R_GlobalPlaneToLocal( entityDef->modelMatrix, frustumPlanes[plane], localPlanes[plane] ); - } - - // cull the entire entity bounding box - // has referenceBounds been tightened to the actual model bounds? - idVec3 corners[8]; - for ( int i = 0 ; i < 8 ; i++ ) { - corners[i][0] = entityDef->referenceBounds[i&1][0]; - corners[i][1] = entityDef->referenceBounds[(i>>1)&1][1]; - corners[i][2] = entityDef->referenceBounds[(i>>2)&1][2]; - } - - for ( plane = 0 ; plane < 6 ; plane++ ) { - int j; - for ( j = 0 ; j < 8 ; j++ ) { - // if a corner is on the negative side (inside) of the frustum, the surface is not culled - // by this plane - if ( corners[j] * localPlanes[plane].ToVec4().ToVec3() + localPlanes[plane][3] < 0 ) { - break; - } - } - if ( j == 8 ) { - break; // all points outside the light - } - } - if ( plane < 6 ) { - culled = CULL_OCCLUDER_AND_RECEIVER; - } - } - - for ( int i = 0 ; i < inter->numSurfaces ; i++ ) { - surfaceInteraction_t *surfInt = &inter->surfaces[i]; - - if ( !surfInt->ambientTris ) { - continue; - } - surfInt->expCulled = culled; - } - - } -} - -/* -================== -RB_EXP_RenderOccluders -================== -*/ -void RB_EXP_RenderOccluders( viewLight_t *vLight ) { - for ( idInteraction *inter = vLight->lightDef->firstInteraction ; inter ; inter = inter->lightNext ) { - const idRenderEntityLocal *entityDef = inter->entityDef; - if ( !entityDef ) { - continue; - } - if ( inter->numSurfaces < 1 ) { - continue; - } - - // no need to check for current on this, because each interaction is always - // a different space - float matrix[16]; - myGlMultMatrix( inter->entityDef->modelMatrix, lightMatrix, matrix ); - qglLoadMatrixf( matrix ); - - // draw each surface - for ( int i = 0 ; i < inter->numSurfaces ; i++ ) { - surfaceInteraction_t *surfInt = &inter->surfaces[i]; - - if ( !surfInt->ambientTris ) { - continue; - } - if ( surfInt->shader && !surfInt->shader->SurfaceCastsShadow() ) { - continue; - } - - // cull it - if ( surfInt->expCulled == CULL_OCCLUDER_AND_RECEIVER ) { - continue; - } - - // render it - const srfTriangles_t *tri = surfInt->ambientTris; - if ( !tri->ambientCache ) { - R_CreateAmbientCache( const_cast(tri), false ); - } - idDrawVert *ac = (idDrawVert *)vertexCache.Position( tri->ambientCache ); - qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() ); - qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), ac->st.ToFloatPtr() ); - if ( surfInt->shader ) { - surfInt->shader->GetEditorImage()->Bind(); - } - RB_DrawElementsWithCounters( tri ); - } - } -} - -/* -================== -RB_RenderShadowBuffer -================== -*/ -void RB_RenderShadowBuffer( viewLight_t *vLight, int side ) { - float xmin, xmax, ymin, ymax; - float width, height; - float zNear; - - float fov = r_sb_frustomFOV.GetFloat(); - - // - // set up 90 degree projection matrix - // - zNear = 4; - - ymax = zNear * tan( fov * idMath::PI / 360.0f ); - ymin = -ymax; - - xmax = zNear * tan( fov * idMath::PI / 360.0f ); - xmin = -xmax; - - width = xmax - xmin; - height = ymax - ymin; - - lightProjectionMatrix[0] = 2 * zNear / width; - lightProjectionMatrix[4] = 0; - lightProjectionMatrix[8] = 0; - lightProjectionMatrix[12] = 0; - - lightProjectionMatrix[1] = 0; - lightProjectionMatrix[5] = 2 * zNear / height; - lightProjectionMatrix[9] = 0; - lightProjectionMatrix[13] = 0; - - // this is the far-plane-at-infinity formulation, and - // crunches the Z range slightly so w=0 vertexes do not - // rasterize right at the wraparound point - lightProjectionMatrix[2] = 0; - lightProjectionMatrix[6] = 0; - lightProjectionMatrix[10] = -0.999f; - lightProjectionMatrix[14] = -2.0f * zNear; - - lightProjectionMatrix[3] = 0; - lightProjectionMatrix[7] = 0; - lightProjectionMatrix[11] = -1; - lightProjectionMatrix[15] = 0; - - - if ( r_sb_usePbuffer.GetBool() ) { - // set the current openGL drawable to the shadow buffer - R_MakeCurrent( shadowPbufferDC, win32.hGLRC, NULL /* !@# shadowPbuffer */ ); - } - - qglMatrixMode( GL_PROJECTION ); - qglLoadMatrixf( lightProjectionMatrix ); - qglMatrixMode( GL_MODELVIEW ); - - qglViewport( 0, 0, lightBufferSize, lightBufferSize ); - qglScissor( 0, 0, lightBufferSize, lightBufferSize ); - qglStencilFunc( GL_ALWAYS, 0, 255 ); - -qglClearColor( 0, 1, 0, 0 ); -GL_State( GLS_DEPTHFUNC_LESS | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); // make sure depth mask is off before clear -qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - -// draw all the occluders -qglColor3f( 1, 1, 1 ); -GL_SelectTexture( 0 ); -qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); - - backEnd.currentSpace = NULL; - - static float s_flipMatrix[16] = { - // convert from our coordinate system (looking down X) - // to OpenGL's coordinate system (looking down -Z) - 0, 0, -1, 0, - -1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 0, 1 - }; - - float viewMatrix[16]; - - idVec3 vec; - idVec3 origin = vLight->lightDef->globalLightOrigin; - - if ( side == -1 ) { - // projected light - vec = vLight->lightDef->parms.target; - vec.Normalize(); - viewMatrix[0] = vec[0]; - viewMatrix[4] = vec[1]; - viewMatrix[8] = vec[2]; - - vec = vLight->lightDef->parms.right; - vec.Normalize(); - viewMatrix[1] = -vec[0]; - viewMatrix[5] = -vec[1]; - viewMatrix[9] = -vec[2]; - - vec = vLight->lightDef->parms.up; - vec.Normalize(); - viewMatrix[2] = vec[0]; - viewMatrix[6] = vec[1]; - viewMatrix[10] = vec[2]; - } else { - // side of a point light - memset( viewMatrix, 0, sizeof( viewMatrix ) ); - switch ( side ) { - case 0: - viewMatrix[0] = 1; - viewMatrix[9] = 1; - viewMatrix[6] = -1; - break; - case 1: - viewMatrix[0] = -1; - viewMatrix[9] = -1; - viewMatrix[6] = -1; - break; - case 2: - viewMatrix[4] = 1; - viewMatrix[1] = -1; - viewMatrix[10] = 1; - break; - case 3: - viewMatrix[4] = -1; - viewMatrix[1] = -1; - viewMatrix[10] = -1; - break; - case 4: - viewMatrix[8] = 1; - viewMatrix[1] = -1; - viewMatrix[6] = -1; - break; - case 5: - viewMatrix[8] = -1; - viewMatrix[1] = 1; - viewMatrix[6] = -1; - break; - } - } - - viewMatrix[12] = -origin[0] * viewMatrix[0] + -origin[1] * viewMatrix[4] + -origin[2] * viewMatrix[8]; - viewMatrix[13] = -origin[0] * viewMatrix[1] + -origin[1] * viewMatrix[5] + -origin[2] * viewMatrix[9]; - viewMatrix[14] = -origin[0] * viewMatrix[2] + -origin[1] * viewMatrix[6] + -origin[2] * viewMatrix[10]; - - viewMatrix[3] = 0; - viewMatrix[7] = 0; - viewMatrix[11] = 0; - viewMatrix[15] = 1; - - memcpy( unflippedLightMatrix, viewMatrix, sizeof( unflippedLightMatrix ) ); - myGlMultMatrix( viewMatrix, s_flipMatrix,lightMatrix); - - // create frustum planes - idPlane globalFrustum[6]; - - // near clip - globalFrustum[0][0] = -viewMatrix[0]; - globalFrustum[0][1] = -viewMatrix[4]; - globalFrustum[0][2] = -viewMatrix[8]; - globalFrustum[0][3] = -(origin[0] * globalFrustum[0][0] + origin[1] * globalFrustum[0][1] + origin[2] * globalFrustum[0][2]); - - // far clip - globalFrustum[1][0] = viewMatrix[0]; - globalFrustum[1][1] = viewMatrix[4]; - globalFrustum[1][2] = viewMatrix[8]; - globalFrustum[1][3] = -globalFrustum[0][3] - viewLightAxialSize; - - // side clips - globalFrustum[2][0] = -viewMatrix[0] + viewMatrix[1]; - globalFrustum[2][1] = -viewMatrix[4] + viewMatrix[5]; - globalFrustum[2][2] = -viewMatrix[8] + viewMatrix[9]; - - globalFrustum[3][0] = -viewMatrix[0] - viewMatrix[1]; - globalFrustum[3][1] = -viewMatrix[4] - viewMatrix[5]; - globalFrustum[3][2] = -viewMatrix[8] - viewMatrix[9]; - - globalFrustum[4][0] = -viewMatrix[0] + viewMatrix[2]; - globalFrustum[4][1] = -viewMatrix[4] + viewMatrix[6]; - globalFrustum[4][2] = -viewMatrix[8] + viewMatrix[10]; - - globalFrustum[5][0] = -viewMatrix[0] - viewMatrix[2]; - globalFrustum[5][1] = -viewMatrix[4] - viewMatrix[6]; - globalFrustum[5][2] = -viewMatrix[8] - viewMatrix[10]; - - // is this nromalization necessary? - for ( int i = 0 ; i < 6 ; i++ ) { - globalFrustum[i].ToVec4().ToVec3().Normalize(); - } - - for ( int i = 2 ; i < 6 ; i++ ) { - globalFrustum[i][3] = - (origin * globalFrustum[i].ToVec4().ToVec3() ); - } - - RB_EXP_CullInteractions( vLight, globalFrustum ); - - - // FIXME: we want to skip the sampling as well as the generation when not casting shadows - if ( !r_sb_noShadows.GetBool() && vLight->lightShader->LightCastsShadows() ) { - // - // set polygon offset for the rendering - // - switch ( r_sb_occluderFacing.GetInteger() ) { - case 0: // front sides - qglPolygonOffset( r_sb_polyOfsFactor.GetFloat(), r_sb_polyOfsUnits.GetFloat() ); - qglEnable( GL_POLYGON_OFFSET_FILL ); - RB_EXP_RenderOccluders( vLight ); - qglDisable( GL_POLYGON_OFFSET_FILL ); - break; - case 1: // back sides - qglPolygonOffset( -r_sb_polyOfsFactor.GetFloat(), -r_sb_polyOfsUnits.GetFloat() ); - qglEnable( GL_POLYGON_OFFSET_FILL ); - GL_Cull( CT_BACK_SIDED ); - RB_EXP_RenderOccluders( vLight ); - GL_Cull( CT_FRONT_SIDED ); - qglDisable( GL_POLYGON_OFFSET_FILL ); - break; - case 2: // both sides - GL_Cull( CT_BACK_SIDED ); - RB_EXP_RenderOccluders( vLight ); - GL_Cull( CT_FRONT_SIDED ); - shadowImage[2]->Bind(); - qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, lightBufferSize, lightBufferSize ); - - RB_EXP_RenderOccluders( vLight ); - shadowImage[1]->Bind(); - qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, lightBufferSize, lightBufferSize ); - - // fragment program to combine the two depth images - qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, depthMidpointVertexProgram ); - qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, depthMidpointFragmentProgram ); - qglEnable(GL_VERTEX_PROGRAM_ARB); - qglEnable(GL_FRAGMENT_PROGRAM_ARB); - - GL_SelectTextureNoClient( 1 ); - shadowImage[1]->Bind(); - qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - - GL_SelectTextureNoClient( 0 ); - shadowImage[2]->Bind(); - qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - - // draw a full screen quad - qglMatrixMode( GL_PROJECTION ); - qglLoadIdentity(); - qglOrtho( 0, 1, 0, 1, -1, 1 ); - qglMatrixMode( GL_MODELVIEW ); - qglLoadIdentity(); - - GL_State( GLS_DEPTHFUNC_ALWAYS ); - - qglBegin( GL_TRIANGLE_FAN ); - qglTexCoord2f( 0, 0 ); - qglVertex2f( 0, 0 ); - qglTexCoord2f( 0, lightBufferSizeFraction ); - qglVertex2f( 0, 1 ); - qglTexCoord2f( lightBufferSizeFraction, lightBufferSizeFraction ); - qglVertex2f( 1, 1 ); - qglTexCoord2f( lightBufferSizeFraction, 0 ); - qglVertex2f( 1, 0 ); - qglEnd(); - - qglDisable( GL_VERTEX_PROGRAM_ARB ); - qglDisable( GL_FRAGMENT_PROGRAM_ARB ); - - break; - } - } - - // copy to the texture - shadowImage[0]->Bind(); - qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, lightBufferSize, lightBufferSize ); - -qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); - - - // reset the normal view matrix - - qglMatrixMode( GL_PROJECTION ); - qglLoadMatrixf( backEnd.viewDef->projectionMatrix ); - qglMatrixMode( GL_MODELVIEW ); - - // the current modelView matrix is not valid - backEnd.currentSpace = NULL; -} - -/* -================== -RB_EXP_DrawInteraction -================== -*/ -void RB_EXP_DrawInteraction( const drawInteraction_t *din ) { - // load all the vertex program parameters - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_ORIGIN, din->localLightOrigin.ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_VIEW_ORIGIN, din->localViewOrigin.ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_PROJECT_S, din->lightProjection[0].ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_PROJECT_T, din->lightProjection[1].ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_PROJECT_Q, din->lightProjection[2].ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_FALLOFF_S, din->lightProjection[3].ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_BUMP_MATRIX_S, din->bumpMatrix[0].ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_BUMP_MATRIX_T, din->bumpMatrix[1].ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_DIFFUSE_MATRIX_S, din->diffuseMatrix[0].ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_DIFFUSE_MATRIX_T, din->diffuseMatrix[1].ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_SPECULAR_MATRIX_S, din->specularMatrix[0].ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_SPECULAR_MATRIX_T, din->specularMatrix[1].ToFloatPtr() ); - - -// calculate depth projection for shadow buffer -float sRow[4]; -float tRow[4]; -float rRow[4]; -float qRow[4]; -float matrix[16]; -float matrix2[16]; -myGlMultMatrix( din->surf->space->modelMatrix, lightMatrix, matrix ); -myGlMultMatrix( matrix, lightProjectionMatrix, matrix2 ); - -// the final values need to be in 0.0 : 1.0 range instead of -1 : 1 -sRow[0] = 0.5 * lightBufferSizeFraction * ( matrix2[0] + matrix2[3] ); -sRow[1] = 0.5 * lightBufferSizeFraction * ( matrix2[4] + matrix2[7] ); -sRow[2] = 0.5 * lightBufferSizeFraction * ( matrix2[8] + matrix2[11] ); -sRow[3] = 0.5 * lightBufferSizeFraction * ( matrix2[12] + matrix2[15] ); -qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 18, sRow ); -tRow[0] = 0.5 * lightBufferSizeFraction * ( matrix2[1] + matrix2[3] ); -tRow[1] = 0.5 * lightBufferSizeFraction * ( matrix2[5] + matrix2[7] ); -tRow[2] = 0.5 * lightBufferSizeFraction * ( matrix2[9] + matrix2[11] ); -tRow[3] = 0.5 * lightBufferSizeFraction * ( matrix2[13] + matrix2[15] ); -qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 19, tRow ); -rRow[0] = 0.5 * ( matrix2[2] + matrix2[3] ); -rRow[1] = 0.5 * ( matrix2[6] + matrix2[7] ); -rRow[2] = 0.5 * ( matrix2[10] + matrix2[11] ); -rRow[3] = 0.5 * ( matrix2[14] + matrix2[15] ); -qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 20, rRow ); -qRow[0] = matrix2[3]; -qRow[1] = matrix2[7]; -qRow[2] = matrix2[11]; -qRow[3] = matrix2[15]; -qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 21, qRow ); - - - // testing fragment based normal mapping - if ( r_testARBProgram.GetBool() ) { - qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 2, din->localLightOrigin.ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 3, din->localViewOrigin.ToFloatPtr() ); - } - - static const float zero[4] = { 0, 0, 0, 0 }; - static const float one[4] = { 1, 1, 1, 1 }; - static const float negOne[4] = { -1, -1, -1, -1 }; - - switch ( din->vertexColor ) { - case SVC_IGNORE: - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_MODULATE, zero ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_ADD, one ); - break; - case SVC_MODULATE: - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_MODULATE, one ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_ADD, zero ); - break; - case SVC_INVERSE_MODULATE: - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_MODULATE, negOne ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_ADD, one ); - break; - } - - // set the constant colors - qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 0, din->diffuseColor.ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 1, din->specularColor.ToFloatPtr() ); - - //----------------------------------------------------- - // screen power of two correction factor - - float parm[4]; - parm[0] = 1.0 / ( JITTER_SIZE * r_sb_samples.GetInteger() ) ; - parm[1] = 1.0 / JITTER_SIZE; - parm[2] = 0; - parm[3] = 1; - qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 2, parm ); - - // jitter tex scale - parm[0] = - parm[1] = r_sb_jitterScale.GetFloat() * lightBufferSizeFraction; - parm[2] = -r_sb_biasScale.GetFloat(); - parm[3] = 0; - qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 3, parm ); - - // jitter tex offset - if ( r_sb_randomize.GetBool() ) { - parm[0] = (rand()&255) / 255.0; - parm[1] = (rand()&255) / 255.0; - } else { - parm[0] = parm[1] = 0; - } - parm[2] = 0; - parm[3] = 0; - qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 4, parm ); - //----------------------------------------------------- - - // set the textures - - // texture 1 will be the per-surface bump map - GL_SelectTextureNoClient( 1 ); - din->bumpImage->Bind(); - - // texture 2 will be the light falloff texture - GL_SelectTextureNoClient( 2 ); - din->lightFalloffImage->Bind(); - - // texture 3 will be the light projection texture - GL_SelectTextureNoClient( 3 ); - din->lightImage->Bind(); - - // texture 4 is the per-surface diffuse map - GL_SelectTextureNoClient( 4 ); - din->diffuseImage->Bind(); - - // texture 5 is the per-surface specular map - GL_SelectTextureNoClient( 5 ); - din->specularImage->Bind(); - - // draw it - RB_DrawElementsWithCounters( din->surf->geo ); -} - -/* -============= -RB_EXP_CreateDrawInteractions - -============= -*/ -void RB_EXP_CreateDrawInteractions( const drawSurf_t *surf ) { - if ( !surf ) { - return; - } - if ( r_sb_screenSpaceShadow.GetBool() ) { - // perform setup here that will be constant for all interactions - GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | backEnd.depthFunc ); - - if ( r_testARBProgram.GetBool() ) { - qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_TEST ); - qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_TEST ); - } else { - qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_INTERACTION ); - qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_INTERACTION ); - } - } else { - // perform setup here that will be constant for all interactions - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | backEnd.depthFunc ); -GL_State( GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS );//!@# - - // bind the vertex program - qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, shadowVertexProgram ); - if ( r_sb_samples.GetInteger() == 16 ) { - qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, shadowFragmentProgram16 ); - } else if ( r_sb_samples.GetInteger() == 4 ) { - qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, shadowFragmentProgram4 ); - } else if ( r_sb_samples.GetInteger() == 1 ) { - qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, shadowFragmentProgram1 ); - } else { - qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, shadowFragmentProgram0 ); - } - } - - qglEnable(GL_VERTEX_PROGRAM_ARB); - qglEnable(GL_FRAGMENT_PROGRAM_ARB); - - // enable the vertex arrays - qglEnableVertexAttribArrayARB( 8 ); - qglEnableVertexAttribArrayARB( 9 ); - qglEnableVertexAttribArrayARB( 10 ); - qglEnableVertexAttribArrayARB( 11 ); - qglEnableClientState( GL_COLOR_ARRAY ); - - // texture 0 is the normalization cube map for the vector towards the light - GL_SelectTextureNoClient( 0 ); - if ( backEnd.vLight->lightShader->IsAmbientLight() ) { - globalImages->normalCubeMapImage->Bind(); - qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_AMBIENT); - qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_AMBIENT); - } else { - globalImages->normalCubeMapImage->Bind(); - } - - // texture 6 is the specular lookup table - GL_SelectTextureNoClient( 6 ); - if ( r_testARBProgram.GetBool() ) { - globalImages->specular2DTableImage->Bind(); // variable specularity in alpha channel - } else { - globalImages->specularTableImage->Bind(); - } - - - for ( ; surf ; surf=surf->nextOnLight ) { - // perform setup here that will not change over multiple interaction passes - if ( backEnd.vLight->lightShader->IsAmbientLight() ) { - float parm[4]; - - parm[0] = surf->space->modelMatrix[0]; - parm[1] = surf->space->modelMatrix[4]; - parm[2] = surf->space->modelMatrix[8]; - parm[3] = 0; - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 20, parm ); - parm[0] = surf->space->modelMatrix[1]; - parm[1] = surf->space->modelMatrix[5]; - parm[2] = surf->space->modelMatrix[9]; - parm[3] = 0; - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 21, parm ); - parm[0] = surf->space->modelMatrix[2]; - parm[1] = surf->space->modelMatrix[6]; - parm[2] = surf->space->modelMatrix[10]; - parm[3] = 0; - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 22, parm ); - - GL_SelectTextureNoClient( 0 ); - const shaderStage_t *stage = backEnd.vLight->lightShader->GetStage( 0 ); - if ( stage->newStage ) { - stage->newStage->fragmentProgramImages[7]->BindFragment(); - } - } - - // set the vertex pointers - idDrawVert *ac = (idDrawVert *)vertexCache.Position( surf->geo->ambientCache ); - qglColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( idDrawVert ), ac->color ); - qglVertexAttribPointerARB( 11, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->normal.ToFloatPtr() ); - qglVertexAttribPointerARB( 10, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[1].ToFloatPtr() ); - qglVertexAttribPointerARB( 9, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[0].ToFloatPtr() ); - qglVertexAttribPointerARB( 8, 2, GL_FLOAT, false, sizeof( idDrawVert ), ac->st.ToFloatPtr() ); - qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() ); - - // this may cause RB_ARB2_DrawInteraction to be exacuted multiple - // times with different colors and images if the surface or light have multiple layers - if ( r_sb_screenSpaceShadow.GetBool() ) { - RB_CreateSingleDrawInteractions( surf, RB_ARB2_DrawInteraction ); - } else { - RB_CreateSingleDrawInteractions( surf, RB_EXP_DrawInteraction ); - } - } - - qglDisableVertexAttribArrayARB( 8 ); - qglDisableVertexAttribArrayARB( 9 ); - qglDisableVertexAttribArrayARB( 10 ); - qglDisableVertexAttribArrayARB( 11 ); - qglDisableClientState( GL_COLOR_ARRAY ); - - // disable features - GL_SelectTextureNoClient( 6 ); - globalImages->BindNull(); - - GL_SelectTextureNoClient( 5 ); - globalImages->BindNull(); - - GL_SelectTextureNoClient( 4 ); - globalImages->BindNull(); - - GL_SelectTextureNoClient( 3 ); - globalImages->BindNull(); - - GL_SelectTextureNoClient( 2 ); - globalImages->BindNull(); - - GL_SelectTextureNoClient( 1 ); - globalImages->BindNull(); - - backEnd.glState.currenttmu = -1; - GL_SelectTexture( 0 ); - - qglDisable(GL_VERTEX_PROGRAM_ARB); - qglDisable(GL_FRAGMENT_PROGRAM_ARB); -} - -void InvertByTranspose( const float a[16], float r[16] ) { - r[ 0] = a[ 0]; - r[ 1] = a[ 4]; - r[ 2] = a[ 8]; - r[ 3] = 0; - r[ 4] = a[ 1]; - r[ 5] = a[ 5]; - r[ 6] = a[ 9]; - r[ 7] = 0; - r[ 8] = a[ 2]; - r[ 9] = a[ 6]; - r[10] = a[10]; - r[11] = 0; - r[12] = -(r[ 0]*a[12] + r[ 4]*a[13] + r[ 8]*a[14]); - r[13] = -(r[ 1]*a[12] + r[ 5]*a[13] + r[ 9]*a[14]); - r[14] = -(r[ 2]*a[12] + r[ 6]*a[13] + r[10]*a[14]); - r[15] = 1; -} - -void FullInvert( const float a[16], float r[16] ) { - idMat4 am; - - for ( int i = 0 ; i < 4 ; i++ ) { - for ( int j = 0 ; j < 4 ; j++ ) { - am[i][j] = a[j*4+i]; - } - } - -// idVec4 test( 100, 100, 100, 1 ); -// idVec4 transformed, inverted; -// transformed = test * am; - - if ( !am.InverseSelf() ) { - common->Error( "Invert failed" ); - } -// inverted = transformed * am; - - for ( int i = 0 ; i < 4 ; i++ ) { - for ( int j = 0 ; j < 4 ; j++ ) { - r[j*4+i] = am[i][j]; - } - } -} - -/* -================== -RB_Exp_TrianglesForFrustum -================== -*/ -const srfTriangles_t *RB_Exp_TrianglesForFrustum( viewLight_t *vLight, int side ) { - const srfTriangles_t *tri; - - static srfTriangles_t frustumTri; - static idDrawVert verts[5]; - static glIndex_t indexes[18] = { 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 1, 2, 1, 4, 2, 4, 3 }; - - if ( side == -1 ) { - tri = vLight->frustumTris; - } else { - memset( verts, 0, sizeof( verts ) ); - - for ( int i = 0 ; i < 5 ; i++ ) { - verts[i].xyz = vLight->globalLightOrigin; - } - - memset( &frustumTri, 0, sizeof( frustumTri ) ); - frustumTri.indexes = indexes; - frustumTri.verts = verts; - frustumTri.numIndexes = 18; - frustumTri.numVerts = 5; - - tri = &frustumTri; - - float size = viewLightAxialSize; - - switch ( side ) { - case 0: - verts[1].xyz[0] += size; - verts[2].xyz[0] += size; - verts[3].xyz[0] += size; - verts[4].xyz[0] += size; - verts[1].xyz[1] += size; - verts[1].xyz[2] += size; - verts[2].xyz[1] -= size; - verts[2].xyz[2] += size; - verts[3].xyz[1] -= size; - verts[3].xyz[2] -= size; - verts[4].xyz[1] += size; - verts[4].xyz[2] -= size; - break; - case 1: - verts[1].xyz[0] -= size; - verts[2].xyz[0] -= size; - verts[3].xyz[0] -= size; - verts[4].xyz[0] -= size; - verts[1].xyz[1] -= size; - verts[1].xyz[2] += size; - verts[2].xyz[1] += size; - verts[2].xyz[2] += size; - verts[3].xyz[1] += size; - verts[3].xyz[2] -= size; - verts[4].xyz[1] -= size; - verts[4].xyz[2] -= size; - break; - case 2: - verts[1].xyz[1] += size; - verts[2].xyz[1] += size; - verts[3].xyz[1] += size; - verts[4].xyz[1] += size; - verts[1].xyz[0] -= size; - verts[1].xyz[2] += size; - verts[2].xyz[0] += size; - verts[2].xyz[2] += size; - verts[3].xyz[0] += size; - verts[3].xyz[2] -= size; - verts[4].xyz[0] -= size; - verts[4].xyz[2] -= size; - break; - case 3: - verts[1].xyz[1] -= size; - verts[2].xyz[1] -= size; - verts[3].xyz[1] -= size; - verts[4].xyz[1] -= size; - verts[1].xyz[0] += size; - verts[1].xyz[2] += size; - verts[2].xyz[0] -= size; - verts[2].xyz[2] += size; - verts[3].xyz[0] -= size; - verts[3].xyz[2] -= size; - verts[4].xyz[0] += size; - verts[4].xyz[2] -= size; - break; - case 4: - verts[1].xyz[2] += size; - verts[2].xyz[2] += size; - verts[3].xyz[2] += size; - verts[4].xyz[2] += size; - verts[1].xyz[0] += size; - verts[1].xyz[1] += size; - verts[2].xyz[0] -= size; - verts[2].xyz[1] += size; - verts[3].xyz[0] -= size; - verts[3].xyz[1] -= size; - verts[4].xyz[0] += size; - verts[4].xyz[1] -= size; - break; - case 5: - verts[1].xyz[2] -= size; - verts[2].xyz[2] -= size; - verts[3].xyz[2] -= size; - verts[4].xyz[2] -= size; - verts[1].xyz[0] -= size; - verts[1].xyz[1] += size; - verts[2].xyz[0] += size; - verts[2].xyz[1] += size; - verts[3].xyz[0] += size; - verts[3].xyz[1] -= size; - verts[4].xyz[0] -= size; - verts[4].xyz[1] -= size; - break; - } - - frustumTri.ambientCache = vertexCache.AllocFrameTemp( verts, sizeof( verts ) ); - } - - return tri; -} - - -/* -================== -RB_Exp_SelectFrustum -================== -*/ -void RB_Exp_SelectFrustum( viewLight_t *vLight, int side ) { - qglLoadMatrixf( backEnd.viewDef->worldSpace.modelViewMatrix ); - - const srfTriangles_t *tri = RB_Exp_TrianglesForFrustum( vLight, side ); - - idDrawVert *ac = (idDrawVert *)vertexCache.Position( tri->ambientCache ); - qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() ); - - qglDisable( GL_TEXTURE_2D ); - qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); - // clear stencil buffer - qglEnable( GL_SCISSOR_TEST ); - qglEnable( GL_STENCIL_TEST ); - qglClearStencil( 1 ); - qglClear( GL_STENCIL_BUFFER_BIT ); - - // draw front faces of the light frustum, incrementing the stencil buffer on depth fail - // so we can't draw on those pixels - GL_State( GLS_COLORMASK | GLS_ALPHAMASK | GLS_DEPTHMASK | GLS_DEPTHFUNC_LESS ); - qglStencilFunc( GL_ALWAYS, 0, 255 ); - qglStencilOp( GL_KEEP, GL_INCR, GL_KEEP ); - GL_Cull( CT_FRONT_SIDED ); - - RB_DrawElementsWithCounters( tri ); - - // draw back faces of the light frustum with - // depth test greater - // stencil test of equal 1 - // zero stencil stencil when depth test passes, so subsequent surface drawing - // can occur on those pixels - - // this pass does all the shadow filtering - qglStencilFunc( GL_EQUAL, 1, 255 ); - qglStencilOp( GL_KEEP, GL_KEEP, GL_ZERO ); - - GL_Cull( CT_BACK_SIDED ); - qglDepthFunc( GL_GREATER ); - - // write to destination alpha - if ( r_sb_showFrustumPixels.GetBool() ) { - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_DEPTHFUNC_LESS ); - qglDisable( GL_TEXTURE_2D ); - qglColor4f( 0, 0.25, 0, 1 ); - } else { - GL_State( GLS_COLORMASK | GLS_DEPTHMASK | GLS_DEPTHFUNC_LESS ); - qglEnable(GL_VERTEX_PROGRAM_ARB); - qglEnable(GL_FRAGMENT_PROGRAM_ARB); - qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, screenSpaceShadowVertexProgram ); - switch ( r_sb_samples.GetInteger() ) { - case 0: - qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, screenSpaceShadowFragmentProgram0 ); - break; - case 1: - qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, screenSpaceShadowFragmentProgram1 ); - break; - case 4: - qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, screenSpaceShadowFragmentProgram4 ); - break; - case 16: - qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, screenSpaceShadowFragmentProgram16 ); - break; - } - } - -/* -texture[0] = view depth texture -texture[1] = jitter texture -texture[2] = light depth texture -*/ - GL_SelectTextureNoClient( 2 ); - shadowImage[0]->Bind(); - - GL_SelectTextureNoClient( 1 ); - if ( r_sb_samples.GetInteger() == 16 ) { - jitterImage16->Bind(); - } else if ( r_sb_samples.GetInteger() == 4 ) { - jitterImage4->Bind(); - } else { - jitterImage1->Bind(); - } - - GL_SelectTextureNoClient( 0 ); - viewDepthImage->Bind(); - - /* -PARAM positionToDepthTexScale = program.local[0]; # fragment.position to screen depth texture transformation -PARAM zProject = program.local[1]; # projection[10], projection[14], 0, 0 -PARAM positionToViewSpace = program.local[2]; # X add, Y add, X mul, Y mul -PARAM viewToLightS = program.local[3]; -PARAM viewToLightT = program.local[4]; -PARAM viewToLightR = program.local[5]; -PARAM viewToLightQ = program.local[6]; -PARAM positionToJitterTexScale = program.local[7]; # fragment.position to jitter texture -PARAM jitterTexScale = program.local[8]; -PARAM jitterTexOffset = program.local[9]; -*/ - float parm[4]; - int pot; - - // calculate depth projection for shadow buffer - float sRow[4]; - float tRow[4]; - float rRow[4]; - float qRow[4]; - float invertedView[16]; - float invertedProjection[16]; - float matrix[16]; - float matrix2[16]; - - // we need the inverse of the projection matrix to go from NDC to view - FullInvert( backEnd.viewDef->projectionMatrix, invertedProjection ); - - /* - from window to NDC: - ( x - xMid ) * 1.0 / xMid - ( y - yMid ) * 1.0 / yMid - ( z - 0.5 ) * 2 - - from NDC to clip coordinates: - rcp(1/w) - - */ - - // we need the inverse of the viewMatrix to go from view (looking down negative Z) to world - InvertByTranspose( backEnd.viewDef->worldSpace.modelViewMatrix, invertedView ); - - // then we go from world to light view space (looking down negative Z) - myGlMultMatrix( invertedView, lightMatrix, matrix ); - - // then to light projection, giving X/w, Y/w, Z/w in the -1 : 1 range - myGlMultMatrix( matrix, lightProjectionMatrix, matrix2 ); - - // the final values need to be in 0.0 : 1.0 range instead of -1 : 1 - sRow[0] = 0.5 * ( matrix2[0] + matrix2[3] ) * lightBufferSizeFraction; - sRow[1] = 0.5 * ( matrix2[4] + matrix2[7] ) * lightBufferSizeFraction; - sRow[2] = 0.5 * ( matrix2[8] + matrix2[11] ) * lightBufferSizeFraction; - sRow[3] = 0.5 * ( matrix2[12] + matrix2[15] ) * lightBufferSizeFraction; - qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 3, sRow ); - tRow[0] = 0.5 * ( matrix2[1] + matrix2[3] ) * lightBufferSizeFraction; - tRow[1] = 0.5 * ( matrix2[5] + matrix2[7] ) * lightBufferSizeFraction; - tRow[2] = 0.5 * ( matrix2[9] + matrix2[11] ) * lightBufferSizeFraction; - tRow[3] = 0.5 * ( matrix2[13] + matrix2[15] ) * lightBufferSizeFraction; - qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 4, tRow ); - rRow[0] = 0.5 * ( matrix2[2] + matrix2[3] ); - rRow[1] = 0.5 * ( matrix2[6] + matrix2[7] ); - rRow[2] = 0.5 * ( matrix2[10] + matrix2[11] ); - rRow[3] = 0.5 * ( matrix2[14] + matrix2[15] ); - qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 5, rRow ); - qRow[0] = matrix2[3]; - qRow[1] = matrix2[7]; - qRow[2] = matrix2[11]; - qRow[3] = matrix2[15]; - qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 6, qRow ); - - //----------------------------------------------------- - // these should be constant for the entire frame - - // convert 0..viewport-1 sizes to fractions inside the POT screen depth texture - int w = viewBufferSize; - pot = MakePowerOfTwo( w ); - parm[0] = 1.0 / maxViewBufferSize; // * ( (float)viewBufferSize / w ); - int h = viewBufferHeight; - pot = MakePowerOfTwo( h ); - parm[1] = parm[0]; // 1.0 / pot; - parm[2] = 0; - parm[3] = 1; - qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 0, parm ); - - // zProject values - parm[0] = backEnd.viewDef->projectionMatrix[10]; - parm[1] = backEnd.viewDef->projectionMatrix[14]; - parm[2] = 0; - parm[3] = 0; - qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 1, parm ); - - // positionToViewSpace - parm[0] = -1.0 / backEnd.viewDef->projectionMatrix[0]; - parm[1] = -1.0 / backEnd.viewDef->projectionMatrix[5]; - parm[2] = 2.0/viewBufferSize; - parm[3] = 2.0/viewBufferSize; - qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 2, parm ); - - // positionToJitterTexScale - parm[0] = 1.0 / ( JITTER_SIZE * r_sb_samples.GetInteger() ) ; - parm[1] = 1.0 / JITTER_SIZE; - parm[2] = 0; - parm[3] = 1; - qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 7, parm ); - - // jitter tex scale - parm[0] = - parm[1] = r_sb_jitterScale.GetFloat() * lightBufferSizeFraction; - parm[2] = -r_sb_biasScale.GetFloat(); - parm[3] = 0; - qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 8, parm ); - - // jitter tex offset - if ( r_sb_randomize.GetBool() ) { - parm[0] = (rand()&255) / 255.0; - parm[1] = (rand()&255) / 255.0; - } else { - parm[0] = parm[1] = 0; - } - parm[2] = 0; - parm[3] = 0; - qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 9, parm ); - //----------------------------------------------------- - - - - RB_DrawElementsWithCounters( tri ); - - qglDisable(GL_VERTEX_PROGRAM_ARB); - qglDisable(GL_FRAGMENT_PROGRAM_ARB); - - GL_Cull( CT_FRONT_SIDED ); -// qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); - - qglDepthFunc( GL_LEQUAL ); - if ( r_sb_showFrustumPixels.GetBool() ) { - qglEnable( GL_TEXTURE_2D ); - qglColor3f( 1, 1, 1 ); - } - - // after all the frustums have been drawn, the surfaces that have been drawn on will get interactions - // scissor may still be a win even with the stencil test for very fast rejects - qglStencilFunc( GL_EQUAL, 0, 255 ); - qglStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); - - // we can avoid clearing the stencil buffer by changing the hasLight value for each light -} - -/* -================== -R_EXP_CalcLightAxialSize - -all light side projections must currently match, so non-centered -and non-cubic lights must take the largest length -================== -*/ -float R_EXP_CalcLightAxialSize( viewLight_t *vLight ) { - float max = 0; - - if ( !vLight->lightDef->parms.pointLight ) { - idVec3 dir = vLight->lightDef->parms.target - vLight->lightDef->parms.origin; - max = dir.Length(); - return max; - } - - for ( int i = 0 ; i < 3 ; i++ ) { - float dist = fabs(vLight->lightDef->parms.lightCenter[i] ); - dist += vLight->lightDef->parms.lightRadius[i]; - if ( dist > max ) { - max = dist; - } - } - return max; -} - -/* -================== -R_EXP_RenderViewDepthImage - -This could be avoided by drop sampling the native view depth buffer with render to texture -Bilerp might even be aprorpiate, although it would cause issues at edges -================== -*/ -void RB_T_FillDepthBuffer( const drawSurf_t *surf ); - -void R_EXP_RenderViewDepthImage( void ) { - if ( !r_sb_screenSpaceShadow.GetBool() ) { - return; - } - - // if the screen resolution is exactly the window width, we can - // use the depth buffer we already have - if ( 0 ) { // nativeViewBuffer ) { - viewDepthImage->CopyDepthbuffer( backEnd.viewDef->viewport.x1, - backEnd.viewDef->viewport.y1, backEnd.viewDef->viewport.x2 - backEnd.viewDef->viewport.x1 + 1, - backEnd.viewDef->viewport.y2 - backEnd.viewDef->viewport.y1 + 1 ); - } else { - if ( r_sb_usePbuffer.GetBool() ) { - GL_CheckErrors(); - // set the current openGL drawable to the shadow buffer - R_MakeCurrent( viewPbufferDC, win32.hGLRC, NULL /* !@# viewPbuffer */ ); - } - - // render the depth to the new size - qglViewport( 0, 0, viewBufferSize, viewBufferHeight ); - qglScissor( 0, 0, viewBufferSize, viewBufferHeight ); - qglClear( GL_DEPTH_BUFFER_BIT ); - qglStencilFunc( GL_ALWAYS, 0, 255 ); - - // the first texture will be used for alpha tested surfaces - GL_SelectTexture( 0 ); - qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); - - GL_State( GLS_DEPTHFUNC_LESS ); - - RB_RenderDrawSurfListWithFunction( backEnd.viewDef->drawSurfs, backEnd.viewDef->numDrawSurfs, RB_T_FillDepthBuffer ); - - // - // copy it to a texture - // - viewDepthImage->Bind(); - qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, viewBufferSize, viewBufferHeight ); - - if ( r_sb_usePbuffer.GetBool() ) { - // set the normal screen drawable current - R_MakeCurrent( win32.hDC, win32.hGLRC, NULL ); - } - - // reset the window clipping - qglMatrixMode( GL_PROJECTION ); - qglLoadMatrixf( backEnd.viewDef->projectionMatrix ); - qglMatrixMode( GL_MODELVIEW ); - - qglViewport( tr.viewportOffset[0] + backEnd.viewDef->viewport.x1, - tr.viewportOffset[1] + backEnd.viewDef->viewport.y1, - backEnd.viewDef->viewport.x2 + 1 - backEnd.viewDef->viewport.x1, - backEnd.viewDef->viewport.y2 + 1 - backEnd.viewDef->viewport.y1 ); - qglScissor( tr.viewportOffset[0] + backEnd.viewDef->viewport.x1, - tr.viewportOffset[1] + backEnd.viewDef->viewport.y1, - backEnd.viewDef->viewport.x2 + 1 - backEnd.viewDef->viewport.x1, - backEnd.viewDef->viewport.y2 + 1 - backEnd.viewDef->viewport.y1 ); - - // the current modelView matrix is not valid - backEnd.currentSpace = NULL; - } - - qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE ); - qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); -} - -/* -================== -RB_EXP_SetNativeBuffer - -This is always the back buffer, and scissor is set full screen -================== -*/ -void RB_EXP_SetNativeBuffer( void ) { - // set the normal screen drawable current - R_MakeCurrent( win32.hDC, win32.hGLRC, NULL ); - - qglViewport( tr.viewportOffset[0] + backEnd.viewDef->viewport.x1, - tr.viewportOffset[1] + backEnd.viewDef->viewport.y1, - backEnd.viewDef->viewport.x2 + 1 - backEnd.viewDef->viewport.x1, - backEnd.viewDef->viewport.y2 + 1 - backEnd.viewDef->viewport.y1 ); - - backEnd.currentScissor = backEnd.viewDef->viewport; - if ( r_useScissor.GetBool() ) { - qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, - backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1, - backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1, - backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 ); - } -} - -/* -================== -RB_EXP_SetRenderBuffer - -This may be to a float pBuffer, and scissor is set to cover only the light -================== -*/ -void RB_EXP_SetRenderBuffer( viewLight_t *vLight ) { - if ( r_hdr_useFloats.GetBool() ) { - R_MakeCurrent( floatPbufferDC, floatContext, floatPbuffer ); - } else { - if ( !qwglMakeCurrent( win32.hDC, win32.hGLRC ) ) { - GL_CheckErrors(); - common->FatalError( "Couldn't return to normal drawing context" ); - } - } - - qglViewport( tr.viewportOffset[0] + backEnd.viewDef->viewport.x1, - tr.viewportOffset[1] + backEnd.viewDef->viewport.y1, - backEnd.viewDef->viewport.x2 + 1 - backEnd.viewDef->viewport.x1, - backEnd.viewDef->viewport.y2 + 1 - backEnd.viewDef->viewport.y1 ); - - if ( !vLight ) { - backEnd.currentScissor = backEnd.viewDef->viewport; - } else { - backEnd.currentScissor = vLight->scissorRect; - } - if ( r_useScissor.GetBool() ) { - qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, - backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1, - backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1, - backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 ); - } -} - -/* -================== -RB_shadowResampleAlpha - -================== -*/ -void RB_shadowResampleAlpha( void ) { - viewAlphaImage->Bind(); - // we could make this a subimage, but it isn't relevent once we have render-to-texture - qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, viewBufferSize, viewBufferHeight ); - - RB_EXP_SetRenderBuffer( backEnd.vLight ); - -//===================== - - qglLoadMatrixf( backEnd.viewDef->worldSpace.modelViewMatrix ); - - // this uses the full light, not side frustums - const srfTriangles_t *tri = backEnd.vLight->frustumTris; - - idDrawVert *ac = (idDrawVert *)vertexCache.Position( tri->ambientCache ); - qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() ); - - // clear stencil buffer - qglEnable( GL_SCISSOR_TEST ); - qglEnable( GL_STENCIL_TEST ); - qglClearStencil( 1 ); - qglClear( GL_STENCIL_BUFFER_BIT ); - - // draw front faces of the light frustum, incrementing the stencil buffer on depth fail - // so we can't draw on those pixels - GL_State( GLS_COLORMASK | GLS_ALPHAMASK | GLS_DEPTHMASK | GLS_DEPTHFUNC_LESS ); - qglStencilFunc( GL_ALWAYS, 0, 255 ); - qglStencilOp( GL_KEEP, GL_INCR, GL_KEEP ); - GL_Cull( CT_FRONT_SIDED ); - - // set fragment / vertex program? - - RB_DrawElementsWithCounters( tri ); - - // draw back faces of the light frustum with - // depth test greater - // stencil test of equal 1 - // zero stencil stencil when depth test passes, so subsequent interaction drawing - // can occur on those pixels - - // this pass does all the shadow filtering - qglStencilFunc( GL_EQUAL, 1, 255 ); - qglStencilOp( GL_KEEP, GL_KEEP, GL_ZERO ); - - // write to destination alpha - if ( r_sb_showFrustumPixels.GetBool() ) { - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_DEPTHFUNC_LESS ); - qglDisable( GL_TEXTURE_2D ); - qglColor4f( 0, 0.25, 0, 1 ); - } else { - GL_State( GLS_COLORMASK | GLS_DEPTHMASK | GLS_DEPTHFUNC_LESS ); - qglEnable(GL_VERTEX_PROGRAM_ARB); - qglEnable(GL_FRAGMENT_PROGRAM_ARB); - qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, shadowResampleVertexProgram ); - qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, shadowResampleFragmentProgram ); - - // convert 0..viewport-1 sizes to fractions inside the POT screen depth texture - // shrink by one unit for bilerp - float parm[4]; - parm[0] = 1.0 / (maxViewBufferSize+1) * viewBufferSize / maxViewBufferSize; - parm[1] = parm[0]; - parm[2] = 0; - parm[3] = 1; - qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 0, parm ); - } - - GL_Cull( CT_BACK_SIDED ); - qglDepthFunc( GL_GREATER ); - - RB_DrawElementsWithCounters( tri ); - - qglDisable(GL_VERTEX_PROGRAM_ARB); - qglDisable(GL_FRAGMENT_PROGRAM_ARB); - - GL_Cull( CT_FRONT_SIDED ); - - qglDepthFunc( GL_LEQUAL ); - if ( r_sb_showFrustumPixels.GetBool() ) { - qglEnable( GL_TEXTURE_2D ); - qglColor3f( 1, 1, 1 ); - } - - // after all the frustums have been drawn, the surfaces that have been drawn on will get interactions - // scissor may still be a win even with the stencil test for very fast rejects - qglStencilFunc( GL_EQUAL, 0, 255 ); - qglStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); -} - - -/* -================== -RB_EXP_CoverScreen -================== -*/ -void RB_EXP_CoverScreen( void ) { - // draw a full screen quad - qglMatrixMode( GL_PROJECTION ); - qglLoadIdentity(); - qglOrtho( 0, 1, 0, 1, -1, 1 ); - qglMatrixMode( GL_MODELVIEW ); - qglLoadIdentity(); - - qglBegin( GL_TRIANGLE_FAN ); - qglVertex2f( 0, 0 ); - qglVertex2f( 0, 1 ); - qglVertex2f( 1, 1 ); - qglVertex2f( 1, 0 ); - qglEnd(); -} - -/* -================== -RB_EXP_ReadFloatBuffer -================== -*/ -void RB_EXP_ReadFloatBuffer( void ) { - int pixels = glConfig.vidWidth * glConfig.vidHeight; - float *buf = (float *)R_StaticAlloc( pixels * 4 * sizeof( float ) ); - - qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_RGBA, GL_FLOAT, buf ); - - float mins[4] = { 9999, 9999, 9999, 9999 }; - float maxs[4] = { -9999, -9999, -9999, -9999 }; - for ( int i = 0 ; i < pixels ; i++ ) { - for ( int j = 0 ; j < 4 ; j++ ) { - float v = buf[ i*4 + j ]; - if ( v < mins[j] ) { - mins[j] = v; - } - if ( v > maxs[j] ) { - maxs[j] = v; - } - } - } - - RB_EXP_SetNativeBuffer(); - - qglLoadIdentity(); - qglMatrixMode( GL_PROJECTION ); - GL_State( GLS_DEPTHFUNC_ALWAYS ); - qglColor3f( 1, 1, 1 ); - qglPushMatrix(); - qglLoadIdentity(); - qglDisable( GL_TEXTURE_2D ); - qglOrtho( 0, 1, 0, 1, -1, 1 ); - qglRasterPos2f( 0.01f, 0.01f ); - qglDrawPixels( glConfig.vidWidth, glConfig.vidHeight, GL_RGBA, GL_FLOAT, buf ); - qglPopMatrix(); - qglEnable( GL_TEXTURE_2D ); - qglMatrixMode( GL_MODELVIEW ); - - R_StaticFree( buf ); -} - - -void RB_TestGamma( void ); - -/* -================== -RB_EXP_GammaDither -================== -*/ -void RB_EXP_GammaDither( void ) { - if ( !r_hdr_useFloats.GetBool() ) { - return; - } - -#if 0 -r_testGamma.SetBool( true ); -RB_TestGamma(); -r_testGamma.SetBool( false ); -#endif - - RB_EXP_SetNativeBuffer(); - - /* -# texture 0 is the high dynamic range buffer -# texture 1 is the random dither texture -# texture 2 is the light bloom texture - -# writes result.color as the 32 bit dithered and gamma corrected values - -PARAM exposure = program.local[0]; # multiply HDR value by this to get screen pixels -PARAM gammaPower = program.local[1]; -PARAM monitorDither = program.local[2]; -PARAM positionToDitherScale = program.local[3]; -PARAM bloomFraction = program.local[4]; -PARAM positionToBloomScale = program.local[5]; - - */ - - qglBindProgramARB( GL_VERTEX_PROGRAM_ARB,gammaDitherVertexProgram ); - qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, gammaDitherFragmentProgram ); - qglEnable(GL_VERTEX_PROGRAM_ARB); - qglEnable(GL_FRAGMENT_PROGRAM_ARB); - - qglActiveTextureARB( GL_TEXTURE2_ARB ); - qglBindTexture( GL_TEXTURE_RECTANGLE_NV, floatPbufferQuarterImage->texnum ); - R_BindTexImage( floatPbufferQuarter ); - - qglActiveTextureARB( GL_TEXTURE1_ARB ); - random256Image->BindFragment(); - - qglActiveTextureARB( GL_TEXTURE0_ARB ); - qglBindTexture( GL_TEXTURE_RECTANGLE_NV, floatPbufferImage->texnum ); - R_BindTexImage( floatPbuffer ); - - float parm[4]; - - parm[0] = r_hdr_exposure.GetFloat(); - parm[1] = 0; - parm[2] = 0; - parm[3] = 0; - qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 0, parm ); - - parm[0] = r_hdr_gamma.GetFloat(); - parm[1] = 0; - parm[2] = 0; - parm[3] = 0; - qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 1, parm ); - - parm[0] = r_hdr_monitorDither.GetFloat(); - parm[1] = 0; - parm[2] = 0; - parm[3] = 0; - qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 2, parm ); - - parm[0] = 1.0 / 256; - parm[1] = parm[0]; - parm[2] = rand()/65535.0; - parm[3] = rand()/65535.0; - qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 3, parm ); - - parm[0] = 1.0 - r_hdr_bloomFraction.GetFloat(); - parm[1] = r_hdr_bloomFraction.GetFloat(); - parm[2] = 0; - parm[3] = 0; - qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 4, parm ); - - parm[0] = 0.25; - parm[1] = 0.25; - parm[2] = 0; - parm[3] = 0; - qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 5, parm ); - - qglDisable( GL_STENCIL_TEST ); - qglDisable( GL_SCISSOR_TEST ); - qglDisable( GL_DEPTH_TEST ); - - RB_EXP_CoverScreen(); - - qglEnable( GL_DEPTH_TEST ); - - qglDisable(GL_VERTEX_PROGRAM_ARB); - qglDisable(GL_FRAGMENT_PROGRAM_ARB); -} - -/* -================== -RB_EXP_Bloom -================== -*/ -void RB_EXP_Bloom( void ) { - if ( !r_hdr_useFloats.GetBool() ) { - return; - } - - if ( r_hdr_bloomFraction.GetFloat() == 0 ) { - return; - } - - GL_CheckErrors(); - - // - // mip map - // - - // draw to the second floatPbuffer - R_MakeCurrent( floatPbuffer2DC, floatContext, floatPbuffer2 ); - - GL_State( 0 ); - qglDisable( GL_DEPTH_TEST ); - qglDisable( GL_SCISSOR_TEST ); - - qglEnable(GL_VERTEX_PROGRAM_ARB); - qglEnable(GL_FRAGMENT_PROGRAM_ARB); - - qglClearColor( 1.0, 0.5, 0, 0 ); - qglClear( GL_COLOR_BUFFER_BIT ); - qglViewport( 0, 0, glConfig.vidWidth>>1, glConfig.vidHeight>>1 ); - - // read from the original floatPbuffer - qglActiveTextureARB( GL_TEXTURE0_ARB ); - qglBindTexture( GL_TEXTURE_RECTANGLE_NV, floatPbufferImage->texnum ); - R_BindTexImage( floatPbuffer ); - - qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, downSampleVertexProgram ); - qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, downSampleFragmentProgram ); - - RB_EXP_CoverScreen(); - - // - // mip map again - // - qglViewport( 0, 0, glConfig.vidWidth>>2, glConfig.vidHeight>>2 ); - - // draw to the second floatPbuffer - R_MakeCurrent( floatPbufferQuarterDC, floatContext, floatPbufferQuarter ); - - // read from the original floatPbuffer - qglBindTexture( GL_TEXTURE_RECTANGLE_NV, floatPbuffer2Image->texnum ); - R_BindTexImage( floatPbuffer2 ); - - RB_EXP_CoverScreen(); - - // - // blur horizontally - // - /* -# texture 0 is the high dynamic range buffer -# writes result.color as the fp16 result of a smeared bloom - -PARAM step = program.local[0]; # { 1, 0 } or { 0, 1 } for horizontal / vertical separation - */ - - // draw to the second floatPbuffer - R_MakeCurrent( floatPbuffer2DC, floatContext, floatPbuffer2 ); - - qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, bloomVertexProgram ); - qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, bloomFragmentProgram ); - qglEnable(GL_VERTEX_PROGRAM_ARB); - qglEnable(GL_FRAGMENT_PROGRAM_ARB); - - GL_SelectTextureNoClient( 0 ); - - // blur horizontally first to the second floatPbuffer - qglBindTexture( GL_TEXTURE_RECTANGLE_NV, floatPbufferQuarterImage->texnum ); - R_BindTexImage( floatPbufferQuarter ); - - float parm[4]; - - parm[0] = 1; - parm[1] = 0; - parm[2] = 0; - parm[3] = 0; - qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 0, parm ); - - RB_EXP_CoverScreen(); - - // - // now blur vertically back to the quarter pbuffer - // - R_MakeCurrent( floatPbufferQuarterDC, floatContext, floatPbufferQuarter ); - - qglBindTexture( GL_TEXTURE_RECTANGLE_NV, floatPbuffer2Image->texnum ); - R_BindTexImage( floatPbuffer2 ); - - parm[0] = 0; - parm[1] = 1; - parm[2] = 0; - parm[3] = 0; - qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 0, parm ); - - RB_EXP_CoverScreen(); - - //======================== - - qglEnable( GL_DEPTH_TEST ); - qglEnable( GL_SCISSOR_TEST ); - - qglDisable(GL_VERTEX_PROGRAM_ARB); - qglDisable(GL_FRAGMENT_PROGRAM_ARB); - - GL_CheckErrors(); -} - -/* -================== -RB_Exp_DrawInteractions -================== -*/ -void RB_Exp_DrawInteractions( void ) { - if ( !initialized ) { - R_Exp_Allocate(); - } - - if ( !backEnd.viewDef->viewLights ) { - return; - } - - // validate the samples - if ( r_sb_samples.GetInteger() != 16 && r_sb_samples.GetInteger() != 4 && r_sb_samples.GetInteger() != 1 ) { - r_sb_samples.SetInteger( 0 ); - } - - // validate the light resolution - if ( r_sb_lightResolution.GetInteger() < 64 ) { - r_sb_lightResolution.SetInteger( 64 ); - } else if ( r_sb_lightResolution.GetInteger() > maxLightBufferSize ) { - r_sb_lightResolution.SetInteger( maxLightBufferSize ); - } - lightBufferSize = r_sb_lightResolution.GetInteger(); - lightBufferSizeFraction = (float)lightBufferSize / maxLightBufferSize; - - // validate the view resolution - if ( r_sb_viewResolution.GetInteger() < 64 ) { - r_sb_viewResolution.SetInteger( 64 ); - } else if ( r_sb_viewResolution.GetInteger() > maxViewBufferSize ) { - r_sb_viewResolution.SetInteger( maxViewBufferSize ); - } - viewBufferSize = r_sb_viewResolution.GetInteger(); - viewBufferHeight = viewBufferSize * 3 / 4; - viewBufferSizeFraction = (float)viewBufferSize / maxViewBufferSize; - viewBufferHeightFraction = (float)viewBufferHeight / maxViewBufferSize; - if ( viewBufferSize == backEnd.viewDef->viewport.x2 - backEnd.viewDef->viewport.x1 + 1 ) { - nativeViewBuffer = true; - } else { - nativeViewBuffer = false; - } - - // set up for either point sampled or percentage-closer filtering for the shadow sampling - shadowImage[0]->BindFragment(); - if ( r_sb_linearFilter.GetBool() ) { - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - } else { - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - } - qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE ); - - globalImages->BindNull(); - - // copy the current depth buffer to a texture for image-space shadowing, - // or re-render at a lower resolution - R_EXP_RenderViewDepthImage(); - - GL_SelectTexture( 0 ); - qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); - - // disable stencil shadow test - qglStencilFunc( GL_ALWAYS, 128, 255 ); - - // the jitter image will be used to offset sample centers - GL_SelectTextureNoClient( 8 ); - if ( r_sb_samples.GetInteger() == 16 ) { - jitterImage16->BindFragment(); - } else if ( r_sb_samples.GetInteger() == 4 ) { - jitterImage4->BindFragment(); - } else { - jitterImage1->BindFragment(); - } - - // if we are using a float buffer, clear it now - if ( r_hdr_useFloats.GetBool() ) { - RB_EXP_SetRenderBuffer( NULL ); - // we need to set a lot of things, because this is a completely different context - RB_SetDefaultGLState(); - qglClearColor( 0.001f, 1.0f, 0.01f, 0.1f ); - qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - // clear the z buffer, set the projection matrix, etc - RB_BeginDrawingView(); - RB_STD_FillDepthBuffer( (drawSurf_t **)&backEnd.viewDef->drawSurfs[0], backEnd.viewDef->numDrawSurfs ); - } - - - // - // for each light, perform adding and shadowing - // - for ( viewLight_t *vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) { - backEnd.vLight = vLight; - - const idMaterial *lightShader = vLight->lightShader; - - // do fogging later - if ( lightShader->IsFogLight() ) { - continue; - } - if ( lightShader->IsBlendLight() ) { - continue; - } - - if ( !vLight->localInteractions && !vLight->globalInteractions - && !vLight->translucentInteractions ) { - continue; - } - - if ( !vLight->frustumTris->ambientCache ) { - R_CreateAmbientCache( const_cast(vLight->frustumTris), false ); - } - - // all light side projections must currently match, so non-centered - // and non-cubic lights must take the largest length - viewLightAxialSize = R_EXP_CalcLightAxialSize( vLight ); - - int side, sideStop; - - if ( vLight->lightDef->parms.pointLight ) { - if ( r_sb_singleSide.GetInteger() != -1 ) { - side = r_sb_singleSide.GetInteger(); - sideStop = side+1; - } else { - side = 0; - sideStop = 6; - } - } else { - side = -1; - sideStop = 0; - } - - for ( ; side < sideStop ; side++ ) { - // FIXME: check for frustums completely off the screen - - // render a shadow buffer - RB_RenderShadowBuffer( vLight, side ); - - // back to view rendering, possibly in the off-screen buffer - if ( nativeViewBuffer || !r_sb_screenSpaceShadow.GetBool() ) { - // directly to screen - RB_EXP_SetRenderBuffer( vLight ); - } else { - // to off screen buffer - if ( r_sb_usePbuffer.GetBool() ) { - GL_CheckErrors(); - // set the current openGL drawable to the shadow buffer - R_MakeCurrent( viewPbufferDC, win32.hGLRC, viewPbuffer ); - } - qglViewport( 0, 0, viewBufferSize, viewBufferHeight ); - qglScissor( 0, 0, viewBufferSize, viewBufferHeight ); // !@# FIXME: scale light scissor - } - - // render the shadows into destination alpha on the included pixels - RB_Exp_SelectFrustum( vLight, side ); - - if ( !r_sb_screenSpaceShadow.GetBool() ) { - // bind shadow buffer to texture - GL_SelectTextureNoClient( 7 ); - shadowImage[0]->BindFragment(); - - RB_EXP_CreateDrawInteractions( vLight->localInteractions ); - RB_EXP_CreateDrawInteractions( vLight->globalInteractions ); - backEnd.depthFunc = GLS_DEPTHFUNC_LESS; - RB_EXP_CreateDrawInteractions( vLight->translucentInteractions ); - backEnd.depthFunc = GLS_DEPTHFUNC_EQUAL; - } - } - - // render the native window coordinates interactions - if ( r_sb_screenSpaceShadow.GetBool() ) { - if ( !nativeViewBuffer ) { - RB_shadowResampleAlpha(); - qglEnable( GL_STENCIL_TEST ); - } else { - RB_EXP_SetRenderBuffer( vLight ); -if ( r_ignore.GetBool() ) { -qglEnable( GL_STENCIL_TEST ); //!@# -} else { -qglDisable( GL_STENCIL_TEST ); //!@# -} - } - RB_EXP_CreateDrawInteractions( vLight->localInteractions ); - RB_EXP_CreateDrawInteractions( vLight->globalInteractions ); - backEnd.depthFunc = GLS_DEPTHFUNC_LESS; - RB_EXP_CreateDrawInteractions( vLight->translucentInteractions ); - backEnd.depthFunc = GLS_DEPTHFUNC_EQUAL; - } - } - - GL_SelectTexture( 0 ); - qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); - - // experimental transfer function - for ( int i = 7 ; i >= 0 ; i-- ) { - GL_SelectTextureNoClient( i ); - globalImages->BindNull(); - } - GL_State( 0 ); - - RB_EXP_Bloom(); - RB_EXP_GammaDither(); - - // these haven't been state saved - for ( int i = 0 ; i < 8 ; i++ ) { - backEnd.glState.tmu[i].current2DMap = -1; - } - - // take it out of texture compare mode so I can testImage it for debugging - shadowImage[0]->BindFragment(); - qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE ); - - -} - - - -/* -================== -R_Exp_Init -================== -*/ -void R_Exp_Init( void ) { - glConfig.allowExpPath = false; - - common->Printf( "---------- R_Exp_Init ----------\n" ); - - if ( !glConfig.ARBVertexProgramAvailable || !glConfig.ARBFragmentProgramAvailable ) { - common->Printf( "Not available.\n" ); - return; - } -RB_CreateBloomTable(); -#if 0 - if ( !R_CheckExtension( "GL_NV_float_buffer" ) ) { - common->Printf( "Not available.\n" ); - return; - } - if ( !R_CheckExtension( "GL_NV_texture_rectangle" ) ) { - common->Printf( "Not available.\n" ); - return; - } -#endif - -#if 0 - qglCombinerParameterfvNV = (void (APIENTRY *)( GLenum pname, const GLfloat *params )) - GLimp_ExtensionPointer( "glCombinerParameterfvNV" ); -#endif - - common->Printf( "Available.\n" ); - - if ( !idStr::Icmp( r_renderer.GetString(), "exp" ) ) { - R_Exp_Allocate(); - } - - common->Printf( "--------------------------------------------\n" ); - - glConfig.allowExpPath = true; -} diff --git a/neo/renderer/tr_local.h b/neo/renderer/tr_local.h index 0be149e3..2b3f87df 100644 --- a/neo/renderer/tr_local.h +++ b/neo/renderer/tr_local.h @@ -813,8 +813,6 @@ extern glconfig_t glConfig; // outside of TR since it shouldn't be cleared du // // cvars // -extern idCVar r_ext_vertex_array_range; - extern idCVar r_mode; // video mode number extern idCVar r_displayRefresh; // optional display refresh rate option for vid mode extern idCVar r_fullscreen; // 0 = windowed, 1 = full screen