2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 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.
24 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.
26 ===========================================================================
29 #include "../idlib/precompiled.h"
33 #include "../sys/win32/win_local.h"
37 strictly experimental / research codepaths
39 !!!if we use front facing occluders, we can portal flow from light centers
41 try depth_component_16 rendering
43 do we care about portals from light perspective? back / front face issues.
45 how do we do weapon depth hacks with shadow buffers?
46 distort their world space vertexes instead of offsetting their depth?
48 jittering off the side of a projection will give wrong shadows
50 really huge lights, like sunlight, are going to be problematic with fixed projections
51 we could tile the projections and let the auto-resize cut them down as necessary
53 It sucks that depth buffers are non-linear, because the bias and compares change with distance
55 polygon offset factor causes occasional texture holes from highly angled textures
59 static bool initialized;
61 static int lightBufferSize = 1024;
62 static int maxLightBufferSize = 1024;
63 static float lightBufferSizeFraction = 0.5;
65 static int viewBufferSize = 1024;
66 static int viewBufferHeight = 768;
67 static int maxViewBufferSize = 1024;
68 static float viewBufferSizeFraction = 0.5;
69 static float viewBufferHeightFraction = 0.5;
70 static bool nativeViewBuffer = false; // true if viewBufferSize is the viewport width
72 static HPBUFFERARB floatPbuffer;
73 static HDC floatPbufferDC;
74 static idImage *floatPbufferImage;
76 static HPBUFFERARB floatPbuffer2;
77 static HDC floatPbuffer2DC;
78 static idImage *floatPbuffer2Image;
80 static HPBUFFERARB floatPbufferQuarter;
81 static HDC floatPbufferQuarterDC;
82 static idImage *floatPbufferQuarterImage;
84 static HGLRC floatContext;
86 static HPBUFFERARB shadowPbuffer;
87 static HDC shadowPbufferDC;
89 static HPBUFFERARB viewPbuffer;
90 static HDC viewPbufferDC;
92 static idImage *shadowImage[3];
94 static idImage *viewDepthImage;
95 static idImage *viewAlphaImage;
97 static idImage *viewShadowImage;
99 static idImage *jitterImage16;
100 static idImage *jitterImage4;
101 static idImage *jitterImage1;
103 static idImage *random256Image;
105 static int shadowVertexProgram;
106 static int shadowFragmentProgram16;
107 static int shadowFragmentProgram4;
108 static int shadowFragmentProgram1;
109 static int shadowFragmentProgram0;
111 static int screenSpaceShadowVertexProgram;
112 static int screenSpaceShadowFragmentProgram16;
113 static int screenSpaceShadowFragmentProgram4;
114 static int screenSpaceShadowFragmentProgram1;
115 static int screenSpaceShadowFragmentProgram0;
117 static int depthMidpointVertexProgram;
118 static int depthMidpointFragmentProgram;
120 static int shadowResampleVertexProgram;
121 static int shadowResampleFragmentProgram;
123 static int gammaDitherVertexProgram;
124 static int gammaDitherFragmentProgram;
126 static int downSampleVertexProgram;
127 static int downSampleFragmentProgram;
129 static int bloomVertexProgram;
130 static int bloomFragmentProgram;
132 static float viewLightAxialSize;
134 idCVar r_sb_lightResolution( "r_sb_lightResolution", "1024", CVAR_RENDERER | CVAR_INTEGER, "Pixel dimensions for each shadow buffer, 64 - 2048" );
135 idCVar r_sb_viewResolution( "r_sb_viewResolution", "1024", CVAR_RENDERER | CVAR_INTEGER, "Width of screen space shadow sampling" );
136 idCVar r_sb_noShadows( "r_sb_noShadows", "0", CVAR_RENDERER | CVAR_BOOL, "don't draw any occluders" );
137 idCVar r_sb_usePbuffer( "r_sb_usePbuffer", "1", CVAR_RENDERER | CVAR_BOOL, "draw offscreen" );
138 idCVar r_sb_jitterScale( "r_sb_jitterScale", "0.006", CVAR_RENDERER | CVAR_FLOAT, "scale factor for jitter offset" );
139 idCVar r_sb_biasScale( "r_sb_biasScale", "0.0001", CVAR_RENDERER | CVAR_FLOAT, "scale factor for jitter bias" );
140 idCVar r_sb_samples( "r_sb_samples", "4", CVAR_RENDERER | CVAR_INTEGER, "0, 1, 4, or 16" );
141 idCVar r_sb_randomize( "r_sb_randomize", "1", CVAR_RENDERER | CVAR_BOOL, "randomly offset jitter texture each draw" );
142 // polyOfsFactor causes holes in low res images
143 idCVar r_sb_polyOfsFactor( "r_sb_polyOfsFactor", "2", CVAR_RENDERER | CVAR_FLOAT, "polygonOffset factor for drawing shadow buffer" );
144 idCVar r_sb_polyOfsUnits( "r_sb_polyOfsUnits", "3000", CVAR_RENDERER | CVAR_FLOAT, "polygonOffset units for drawing shadow buffer" );
145 idCVar r_sb_occluderFacing( "r_sb_occluderFacing", "0", CVAR_RENDERER | CVAR_INTEGER, "0 = front faces, 1 = back faces, 2 = midway between" );
146 // r_sb_randomizeBufferOrientation?
148 idCVar r_sb_frustomFOV( "r_sb_frustomFOV", "92", CVAR_RENDERER | CVAR_FLOAT, "oversize FOV for point light side matching" );
149 idCVar r_sb_showFrustumPixels( "r_sb_showFrustumPixels", "0", CVAR_RENDERER | CVAR_BOOL, "color the pixels contained in the frustum" );
150 idCVar r_sb_singleSide( "r_sb_singleSide", "-1", CVAR_RENDERER | CVAR_INTEGER, "only draw a single side (0-5) of point lights" );
151 idCVar r_sb_useCulling( "r_sb_useCulling", "1", CVAR_RENDERER | CVAR_BOOL, "cull geometry to individual side frustums" );
152 idCVar r_sb_linearFilter( "r_sb_linearFilter", "1", CVAR_RENDERER | CVAR_BOOL, "use GL_LINEAR instead of GL_NEAREST on shadow maps" );
154 idCVar r_sb_screenSpaceShadow( "r_sb_screenSpaceShadow", "1", CVAR_RENDERER | CVAR_BOOL, "build shadows in screen space instead of on surfaces" );
156 idCVar r_hdr_useFloats( "r_hdr_useFloats", "0", CVAR_RENDERER | CVAR_BOOL, "use a floating point rendering buffer" );
157 idCVar r_hdr_exposure( "r_hdr_exposure", "1.0", CVAR_RENDERER | CVAR_FLOAT, "maximum light scale" );
158 idCVar r_hdr_bloomFraction( "r_hdr_bloomFraction", "0.1", CVAR_RENDERER | CVAR_FLOAT, "fraction to smear across neighbors" );
159 idCVar r_hdr_gamma( "r_hdr_gamma", "1", CVAR_RENDERER | CVAR_FLOAT, "monitor gamma power" );
160 idCVar r_hdr_monitorDither( "r_hdr_monitorDither", "0.01", CVAR_RENDERER | CVAR_FLOAT, "random dither in monitor space" );
162 // from world space to light origin, looking down the X axis
163 static float unflippedLightMatrix[16];
165 // from world space to OpenGL view space, looking down the negative Z axis
166 static float lightMatrix[16];
168 // from OpenGL view space to OpenGL NDC ( -1 : 1 in XYZ )
169 static float lightProjectionMatrix[16];
172 void RB_ARB2_DrawInteraction( const drawInteraction_t *din );
179 wglString_t wglString[] = {
180 { "WGL_NUMBER_PIXEL_FORMATS_ARB", 0x2000 },
181 { "WGL_DRAW_TO_WINDOW_ARB", 0x2001 },
182 { "WGL_DRAW_TO_BITMAP_ARB", 0x2002 },
183 { "WGL_ACCELERATION_ARB", 0x2003 },
184 { "WGL_NEED_PALETTE_ARB", 0x2004 },
185 { "WGL_NEED_SYSTEM_PALETTE_ARB", 0x2005 },
186 { "WGL_SWAP_LAYER_BUFFERS_ARB", 0x2006 },
187 { "WGL_SWAP_METHOD_ARB", 0x2007 },
188 { "WGL_NUMBER_OVERLAYS_ARB", 0x2008 },
189 { "WGL_NUMBER_UNDERLAYS_ARB", 0x2009 },
190 { "WGL_TRANSPARENT_ARB", 0x200A },
191 { "WGL_TRANSPARENT_RED_VALUE_ARB", 0x2037 },
192 { "WGL_TRANSPARENT_GREEN_VALUE_ARB", 0x2038 },
193 { "WGL_TRANSPARENT_BLUE_VALUE_ARB", 0x2039 },
194 { "WGL_TRANSPARENT_ALPHA_VALUE_ARB", 0x203A },
195 { "WGL_TRANSPARENT_INDEX_VALUE_ARB", 0x203B },
196 { "WGL_SHARE_DEPTH_ARB", 0x200C },
197 { "WGL_SHARE_STENCIL_ARB", 0x200D },
198 { "WGL_SHARE_ACCUM_ARB", 0x200E },
199 { "WGL_SUPPORT_GDI_ARB", 0x200F },
200 { "WGL_SUPPORT_OPENGL_ARB", 0x2010 },
201 { "WGL_DOUBLE_BUFFER_ARB", 0x2011 },
202 { "WGL_STEREO_ARB", 0x2012 },
203 { "WGL_PIXEL_TYPE_ARB", 0x2013 },
204 { "WGL_COLOR_BITS_ARB", 0x2014 },
205 { "WGL_RED_BITS_ARB", 0x2015 },
206 { "WGL_RED_SHIFT_ARB", 0x2016 },
207 { "WGL_GREEN_BITS_ARB", 0x2017 },
208 { "WGL_GREEN_SHIFT_ARB", 0x2018 },
209 { "WGL_BLUE_BITS_ARB", 0x2019 },
210 { "WGL_BLUE_SHIFT_ARB", 0x201A },
211 { "WGL_ALPHA_BITS_ARB", 0x201B },
212 { "WGL_ALPHA_SHIFT_ARB", 0x201C },
213 { "WGL_ACCUM_BITS_ARB", 0x201D },
214 { "WGL_ACCUM_RED_BITS_ARB", 0x201E },
215 { "WGL_ACCUM_GREEN_BITS_ARB", 0x201F },
216 { "WGL_ACCUM_BLUE_BITS_ARB", 0x2020 },
217 { "WGL_ACCUM_ALPHA_BITS_ARB", 0x2021 },
218 { "WGL_DEPTH_BITS_ARB", 0x2022 },
219 { "WGL_STENCIL_BITS_ARB", 0x2023 },
220 { "WGL_AUX_BUFFERS_ARB", 0x2024 },
222 { "WGL_NO_ACCELERATION_ARB", 0x2025 },
223 { "WGL_GENERIC_ACCELERATION_ARB", 0x2026 },
224 { "WGL_FULL_ACCELERATION_ARB", 0x2027 },
226 { "WGL_SWAP_EXCHANGE_ARB", 0x2028 },
227 { "WGL_SWAP_COPY_ARB", 0x2029 },
228 { "WGL_SWAP_UNDEFINED_ARB", 0x202A },
230 { "WGL_TYPE_RGBA_ARB", 0x202B },
231 { "WGL_TYPE_COLORINDEX_ARB", 0x202C },
234 static const int NUM_WGL_STRINGS = sizeof( wglString ) / sizeof( wglString[0] );
236 static void R_CheckWglErrors( void ) {
237 int err = GetLastError();
242 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
245 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
253 case 13: name = "ERROR_INVALID_DATA"; break;
254 case 6: name = "ERROR_INVALID_HANDLE"; break;
255 case 4317: name = "ERROR_INVALID_OPERATION"; break;
256 default: name = va( "code %i", err ); break;
259 common->Printf( "GetLastError: %s\n", name );
262 static void R_MakeCurrent( HDC dc, HGLRC context, HPBUFFERARB pbuffer ) {
264 if ( !wglReleaseTexImageARB( pbuffer, WGL_FRONT_LEFT_ARB ) ) {
266 common->Error( "wglReleaseTexImageARB failed" );
269 if ( !qwglMakeCurrent( dc, context ) ) {
271 common->FatalError( "qwglMakeCurrent failed" );
275 static void R_BindTexImage( HPBUFFERARB pbuffer ) {
276 if ( !wglReleaseTexImageARB( pbuffer, WGL_FRONT_LEFT_ARB ) ) {
278 common->Error( "wglReleaseTexImageARB failed" );
280 if ( !wglBindTexImageARB( pbuffer, WGL_FRONT_LEFT_ARB ) ) {
282 common->Error( "failed wglBindTexImageARB" );
286 static void R_ReportTextureParms( void ) {
289 // q glGetTexParameteriv( GL_TEXTURE_RECTANGLE_NV,
290 qglGetIntegerv( GL_TEXTURE_BINDING_RECTANGLE_NV, parms );
299 static const int BLOOM_RADIUS = 8;
300 static void RB_CreateBloomTable( void ) {
301 float bloom[BLOOM_RADIUS];
306 for ( int i = 0 ; i < BLOOM_RADIUS ; i++ ) {
307 float f = (float)i / stdDev;
308 bloom[i] = exp( -0.5 * f * f );
312 total = ( total - bloom[0] ) * 2 + bloom[0];
314 // normalize to 1.0 contribution, so a full row or column will equal 1.0
315 for ( int i = 0 ; i < BLOOM_RADIUS ; i++ ) {
316 bloom[i] *= 1.0 / total;
317 common->Printf( "PARAM bloom%i = { %f };\n", i, bloom[i] );
324 GL_SelectTextureNoClient
327 static void GL_SelectTextureNoClient( int unit ) {
328 backEnd.glState.currenttmu = unit;
329 qglActiveTextureARB( GL_TEXTURE0_ARB + unit );
330 RB_LogComment( "glActiveTextureARB( %i )\n", unit );
336 R_CreateShadowBufferImage
340 static void R_CreateShadowBufferImage( idImage *image ) {
341 byte *data = (byte *)Mem_Alloc( lightBufferSize*lightBufferSize );
343 memset( data, 0, lightBufferSize*lightBufferSize );
345 image->GenerateImage( (byte *)data, 4, 4,
346 TF_LINEAR, false, TR_CLAMP_TO_BORDER, TD_HIGH_QUALITY );
348 // now reset it to a shadow depth image
350 image->uploadWidth = image->uploadHeight = lightBufferSize;
351 qglTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24_ARB, lightBufferSize, lightBufferSize,
352 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, data );
354 qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE );
355 // qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE );
356 qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL );
358 // explicit zero depth border
360 color[0] = color[1] = color[2] = color[3] = 0;
361 qglTexParameterfv( GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color );
368 static void R_CreateViewAlphaImage( idImage *image ) {
369 int c = viewBufferSize*viewBufferSize*4;
370 byte *data = (byte *)Mem_Alloc( c );
372 // don't let it pick an intensity format
373 for ( int i = 0 ; i < c ; i++ ) {
376 memset( data, 0, viewBufferSize*viewBufferSize );
378 image->GenerateImage( (byte *)data, viewBufferSize, viewBufferSize,
379 TF_LINEAR, false, TR_CLAMP, TD_HIGH_QUALITY );
382 static void R_CreateStubImage( idImage *image ) {
385 // generate the texture number
386 qglGenTextures( 1, &image->texnum );
387 qglBindTexture( GL_TEXTURE_RECTANGLE_NV, image->texnum );
388 memset( data, 0, sizeof( data ) );
389 glTexImage2D( GL_TEXTURE_RECTANGLE_NV, 0, GL_FLOAT_RGBA16_NV, 4, 3, 0, GL_RGBA, GL_FLOAT, &data );
398 const static int JITTER_SIZE = 128;
399 static void R_CreateJitterImage16( idImage *image ) {
400 byte data[JITTER_SIZE][JITTER_SIZE*16][4];
402 for ( int i = 0 ; i < JITTER_SIZE ; i++ ) {
403 for ( int s = 0 ; s < 16 ; s++ ) {
404 int sOfs = 64 * ( s & 3 );
405 int tOfs = 64 * ( ( s >> 2 ) & 3 );
407 for ( int j = 0 ; j < JITTER_SIZE ; j++ ) {
408 data[i][s*JITTER_SIZE+j][0] = (rand() & 63 ) | sOfs;
409 data[i][s*JITTER_SIZE+j][1] = (rand() & 63 ) | tOfs;
410 data[i][s*JITTER_SIZE+j][2] = rand();
411 data[i][s*JITTER_SIZE+j][3] = 0;
416 image->GenerateImage( (byte *)data, JITTER_SIZE*16, JITTER_SIZE,
417 TF_NEAREST, false, TR_REPEAT, TD_HIGH_QUALITY );
420 static void R_CreateJitterImage4( idImage *image ) {
421 byte data[JITTER_SIZE][JITTER_SIZE*4][4];
423 for ( int i = 0 ; i < JITTER_SIZE ; i++ ) {
424 for ( int s = 0 ; s < 4 ; s++ ) {
425 int sOfs = 128 * ( s & 1 );
426 int tOfs = 128 * ( ( s >> 1 ) & 1 );
428 for ( int j = 0 ; j < JITTER_SIZE ; j++ ) {
429 data[i][s*JITTER_SIZE+j][0] = (rand() & 127 ) | sOfs;
430 data[i][s*JITTER_SIZE+j][1] = (rand() & 127 ) | tOfs;
431 data[i][s*JITTER_SIZE+j][2] = rand();
432 data[i][s*JITTER_SIZE+j][3] = 0;
437 image->GenerateImage( (byte *)data, JITTER_SIZE*4, JITTER_SIZE,
438 TF_NEAREST, false, TR_REPEAT, TD_HIGH_QUALITY );
441 static void R_CreateJitterImage1( idImage *image ) {
442 byte data[JITTER_SIZE][JITTER_SIZE][4];
444 for ( int i = 0 ; i < JITTER_SIZE ; i++ ) {
445 for ( int j = 0 ; j < JITTER_SIZE ; j++ ) {
446 data[i][j][0] = rand();
447 data[i][j][1] = rand();
448 data[i][j][2] = rand();
453 image->GenerateImage( (byte *)data, JITTER_SIZE, JITTER_SIZE,
454 TF_NEAREST, false, TR_REPEAT, TD_HIGH_QUALITY );
457 static void R_CreateRandom256Image( idImage *image ) {
458 byte data[256][256][4];
460 for ( int i = 0 ; i < 256 ; i++ ) {
461 for ( int j = 0 ; j < 256 ; j++ ) {
462 data[i][j][0] = rand();
463 data[i][j][1] = rand();
464 data[i][j][2] = rand();
465 data[i][j][3] = rand();
469 image->GenerateImage( (byte *)data, 256, 256,
470 TF_NEAREST, false, TR_REPEAT, TD_HIGH_QUALITY );
479 void R_PrintPixelFormat( int pixelFormat ) {
484 common->Printf( "----- pixelFormat %i -----\n", pixelFormat );
486 for ( int i = 1 ; i < NUM_WGL_STRINGS ; i++ ) {
487 iAttribute = wglString[i].num;
488 res = wglGetPixelFormatAttribivARB( win32.hDC, pixelFormat, 0, 1, &iAttribute, &iValue );
489 if ( res && iValue ) {
490 common->Printf( "%s : %i\n", wglString[i].name, iValue );
501 void R_Exp_Allocate( void ) {
502 // find a pixel format for our floating point pbuffer
503 int iAttributes[NUM_WGL_STRINGS*2], *atr_p;
504 FLOAT fAttributes[] = {0, 0};
506 int pixelformats[1024];
508 int pbiAttributes[] = {0, 0};
514 // allocate the floating point rendering buffer
518 *atr_p++ = WGL_DRAW_TO_PBUFFER_ARB;
520 *atr_p++ = WGL_FLOAT_COMPONENTS_NV;
522 *atr_p++ = WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV;
524 // *atr_p++ = WGL_BIND_TO_TEXTURE_RGBA_ARB;
526 *atr_p++ = WGL_DEPTH_BITS_ARB;
528 *atr_p++ = WGL_STENCIL_BITS_ARB;
533 ret = wglChoosePixelFormatARB( win32.hDC, iAttributes, fAttributes,
534 sizeof( pixelformats ) / sizeof( pixelformats[0] ), pixelformats, &numFormats );
537 for ( int i = 0 ; i < (int)numFormats ; i++ ) {
538 R_PrintPixelFormat( pixelformats[i] );
541 common->Printf( "\nfloatPbuffer:\n" );
542 R_PrintPixelFormat( pixelformats[0] );
544 // allocate a pbuffer with this pixel format
545 int pbiAttributesTexture[] = {
546 WGL_TEXTURE_FORMAT_ARB, WGL_TEXTURE_FLOAT_RGBA_NV,
547 WGL_TEXTURE_TARGET_ARB, WGL_TEXTURE_RECTANGLE_NV, // WGL_TEXTURE_2D_ARB,
550 floatPbuffer = wglCreatePbufferARB( win32.hDC, pixelformats[0], glConfig.vidWidth,
551 glConfig.vidHeight, pbiAttributesTexture );
552 if ( !floatPbuffer ) {
553 common->Printf( "failed to create floatPbuffer.\n" );
556 floatPbufferDC = wglGetPbufferDCARB( floatPbuffer );
557 floatPbufferImage = globalImages->ImageFromFunction( "_floatPbuffer", R_CreateStubImage );
559 // create a second buffer for ping-pong operations
560 floatPbuffer2 = wglCreatePbufferARB( win32.hDC, pixelformats[0], glConfig.vidWidth,
561 glConfig.vidHeight, pbiAttributesTexture );
562 if ( !floatPbuffer2 ) {
563 common->Printf( "failed to create floatPbuffer.\n" );
566 floatPbuffer2DC = wglGetPbufferDCARB( floatPbuffer2 );
567 floatPbuffer2Image = globalImages->ImageFromFunction( "_floatPbuffer2", R_CreateStubImage );
569 // create a third buffer for down sampling operations
570 floatPbufferQuarter = wglCreatePbufferARB( win32.hDC, pixelformats[0], glConfig.vidWidth / 4,
571 glConfig.vidHeight / 4, pbiAttributesTexture );
572 if ( !floatPbufferQuarter ) {
573 common->Printf( "failed to create floatPbuffer.\n" );
576 floatPbufferQuarterDC = wglGetPbufferDCARB( floatPbufferQuarter );
577 floatPbufferQuarterImage = globalImages->ImageFromFunction( "floatPbufferQuarter", R_CreateStubImage );
579 // create a new GL context for this pixel format and share textures
580 floatContext = wglCreateContext( floatPbufferDC );
581 if ( !floatContext ) {
582 common->Printf( "failed to create context for floatPbufferDC.\n" );
586 if ( !wglShareLists( floatContext, win32.hGLRC ) ) {
587 common->Printf( "failed to share lists.\n" );
590 // create a rendering context for this pixel format and share textures
592 // allocate a texture for the rendering
596 //=================================================================================
599 // allocate the shadow pbuffer
603 *atr_p++ = WGL_DRAW_TO_PBUFFER_ARB;
605 *atr_p++ = WGL_RED_BITS_ARB;
607 *atr_p++ = WGL_GREEN_BITS_ARB;
609 *atr_p++ = WGL_BLUE_BITS_ARB;
611 *atr_p++ = WGL_ALPHA_BITS_ARB;
613 *atr_p++ = WGL_DEPTH_BITS_ARB;
615 *atr_p++ = WGL_STENCIL_BITS_ARB;
620 ret = wglChoosePixelFormatARB( win32.hDC, iAttributes, fAttributes,
621 sizeof( pixelformats ) / sizeof( pixelformats[0] ), pixelformats, &numFormats );
623 for ( int i = 0 ; i < (int)numFormats ; i++ ) {
624 R_PrintPixelFormat( pixelformats[i] );
627 common->Printf( "\nshadowPbuffer:\n" );
628 R_PrintPixelFormat( pixelformats[0] );
630 pixelformats[0] = win32.pixelformat; // forced to do this by wgl...
632 //-----------------------------------
634 lightBufferSize = maxLightBufferSize;
636 // allocate a pbuffer with this pixel format
637 shadowPbuffer = wglCreatePbufferARB( win32.hDC, pixelformats[0], lightBufferSize,
638 lightBufferSize, pbiAttributes );
640 // allocate a rendering context for the pbuffer
641 shadowPbufferDC = wglGetPbufferDCARB( shadowPbuffer );
643 // generate the texture number
644 shadowImage[0] = globalImages->ImageFromFunction( va("_shadowBuffer%i_0",lightBufferSize), R_CreateShadowBufferImage );
645 shadowImage[1] = globalImages->ImageFromFunction( va("_shadowBuffer%i_1",lightBufferSize), R_CreateShadowBufferImage );
646 shadowImage[2] = globalImages->ImageFromFunction( va("_shadowBuffer%i_2",lightBufferSize), R_CreateShadowBufferImage );
648 //-----------------------------------
650 lightBufferSize = maxViewBufferSize;
652 // allocate a pbuffer with this pixel format
653 viewPbuffer = wglCreatePbufferARB( win32.hDC, pixelformats[0], maxViewBufferSize,
654 maxViewBufferSize, pbiAttributes );
656 // allocate a rendering context for the pbuffer
657 viewPbufferDC = wglGetPbufferDCARB( viewPbuffer );
659 // create the image space depth buffer for image-space shadow trnasforms
660 viewDepthImage = globalImages->ImageFromFunction("_viewDepth", R_CreateShadowBufferImage );
662 // create the image space shadow alpha buffer for subsampling the shadow calculation
663 viewAlphaImage = globalImages->ImageFromFunction("_viewAlpha", R_CreateViewAlphaImage );
665 //-----------------------------------
667 // generate the jitter image
668 jitterImage16 = globalImages->ImageFromFunction( "_jitter16", R_CreateJitterImage16 );
669 jitterImage4 = globalImages->ImageFromFunction( "_jitter4", R_CreateJitterImage4 );
670 jitterImage1 = globalImages->ImageFromFunction( "_jitter1", R_CreateJitterImage1 );
672 depthMidpointVertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "depthMidpoint.vfp" );
673 depthMidpointFragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "depthMidpoint.vfp" );
675 shadowResampleVertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "shadowResample.vfp" );
676 shadowResampleFragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "shadowResample.vfp" );
678 screenSpaceShadowVertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "screenSpaceShadow1.vfp" );
680 screenSpaceShadowFragmentProgram0 = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "screenSpaceShadow0.vfp" );
681 screenSpaceShadowFragmentProgram1 = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "screenSpaceShadow1.vfp" );
682 screenSpaceShadowFragmentProgram4 = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "screenSpaceShadow4.vfp" );
683 screenSpaceShadowFragmentProgram16 = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "screenSpaceShadow16.vfp" );
685 shadowVertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "shadowBufferInteraction1.vfp" );
687 shadowFragmentProgram0 = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "shadowBufferInteraction0.vfp" );
688 shadowFragmentProgram1 = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "shadowBufferInteraction1.vfp" );
689 shadowFragmentProgram4 = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "shadowBufferInteraction4.vfp" );
690 shadowFragmentProgram16 = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "shadowBufferInteraction16.vfp" );
692 gammaDitherVertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "gammaDither.vfp" );
693 gammaDitherFragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "gammaDither.vfp" );
695 downSampleVertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "downSample.vfp" );
696 downSampleFragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "downSample.vfp" );
698 bloomVertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "bloom.vfp" );
699 bloomFragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "bloom.vfp" );
701 random256Image = globalImages->ImageFromFunction( "_random256", R_CreateRandom256Image );
704 //===========================================================================================
706 static const int CULL_RECEIVER = 1; // still draw occluder, but it is out of the view
707 static const int CULL_OCCLUDER_AND_RECEIVER = 2; // the surface doesn't effect the view at all
711 RB_EXP_CullInteractions
713 Sets surfaceInteraction_t->cullBits
716 void RB_EXP_CullInteractions( viewLight_t *vLight, idPlane frustumPlanes[6] ) {
717 for ( idInteraction *inter = vLight->lightDef->firstInteraction ; inter ; inter = inter->lightNext ) {
718 const idRenderEntityLocal *entityDef = inter->entityDef;
722 if ( inter->numSurfaces < 1 ) {
728 if ( r_sb_useCulling.GetBool() ) {
729 // transform light frustum into object space, positive side points outside the light
730 idPlane localPlanes[6];
732 for ( plane = 0 ; plane < 6 ; plane++ ) {
733 R_GlobalPlaneToLocal( entityDef->modelMatrix, frustumPlanes[plane], localPlanes[plane] );
736 // cull the entire entity bounding box
737 // has referenceBounds been tightened to the actual model bounds?
739 for ( int i = 0 ; i < 8 ; i++ ) {
740 corners[i][0] = entityDef->referenceBounds[i&1][0];
741 corners[i][1] = entityDef->referenceBounds[(i>>1)&1][1];
742 corners[i][2] = entityDef->referenceBounds[(i>>2)&1][2];
745 for ( plane = 0 ; plane < 6 ; plane++ ) {
747 for ( j = 0 ; j < 8 ; j++ ) {
748 // if a corner is on the negative side (inside) of the frustum, the surface is not culled
750 if ( corners[j] * localPlanes[plane].ToVec4().ToVec3() + localPlanes[plane][3] < 0 ) {
755 break; // all points outside the light
759 culled = CULL_OCCLUDER_AND_RECEIVER;
763 for ( int i = 0 ; i < inter->numSurfaces ; i++ ) {
764 surfaceInteraction_t *surfInt = &inter->surfaces[i];
766 if ( !surfInt->ambientTris ) {
769 surfInt->expCulled = culled;
777 RB_EXP_RenderOccluders
780 void RB_EXP_RenderOccluders( viewLight_t *vLight ) {
781 for ( idInteraction *inter = vLight->lightDef->firstInteraction ; inter ; inter = inter->lightNext ) {
782 const idRenderEntityLocal *entityDef = inter->entityDef;
786 if ( inter->numSurfaces < 1 ) {
790 // no need to check for current on this, because each interaction is always
793 myGlMultMatrix( inter->entityDef->modelMatrix, lightMatrix, matrix );
794 qglLoadMatrixf( matrix );
797 for ( int i = 0 ; i < inter->numSurfaces ; i++ ) {
798 surfaceInteraction_t *surfInt = &inter->surfaces[i];
800 if ( !surfInt->ambientTris ) {
803 if ( surfInt->shader && !surfInt->shader->SurfaceCastsShadow() ) {
808 if ( surfInt->expCulled == CULL_OCCLUDER_AND_RECEIVER ) {
813 const srfTriangles_t *tri = surfInt->ambientTris;
814 if ( !tri->ambientCache ) {
815 R_CreateAmbientCache( const_cast<srfTriangles_t *>(tri), false );
817 idDrawVert *ac = (idDrawVert *)vertexCache.Position( tri->ambientCache );
818 qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() );
819 qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), ac->st.ToFloatPtr() );
820 if ( surfInt->shader ) {
821 surfInt->shader->GetEditorImage()->Bind();
823 RB_DrawElementsWithCounters( tri );
830 RB_RenderShadowBuffer
833 void RB_RenderShadowBuffer( viewLight_t *vLight, int side ) {
834 float xmin, xmax, ymin, ymax;
838 float fov = r_sb_frustomFOV.GetFloat();
841 // set up 90 degree projection matrix
845 ymax = zNear * tan( fov * idMath::PI / 360.0f );
848 xmax = zNear * tan( fov * idMath::PI / 360.0f );
852 height = ymax - ymin;
854 lightProjectionMatrix[0] = 2 * zNear / width;
855 lightProjectionMatrix[4] = 0;
856 lightProjectionMatrix[8] = 0;
857 lightProjectionMatrix[12] = 0;
859 lightProjectionMatrix[1] = 0;
860 lightProjectionMatrix[5] = 2 * zNear / height;
861 lightProjectionMatrix[9] = 0;
862 lightProjectionMatrix[13] = 0;
864 // this is the far-plane-at-infinity formulation, and
865 // crunches the Z range slightly so w=0 vertexes do not
866 // rasterize right at the wraparound point
867 lightProjectionMatrix[2] = 0;
868 lightProjectionMatrix[6] = 0;
869 lightProjectionMatrix[10] = -0.999f;
870 lightProjectionMatrix[14] = -2.0f * zNear;
872 lightProjectionMatrix[3] = 0;
873 lightProjectionMatrix[7] = 0;
874 lightProjectionMatrix[11] = -1;
875 lightProjectionMatrix[15] = 0;
878 if ( r_sb_usePbuffer.GetBool() ) {
879 // set the current openGL drawable to the shadow buffer
880 R_MakeCurrent( shadowPbufferDC, win32.hGLRC, NULL /* !@# shadowPbuffer */ );
883 qglMatrixMode( GL_PROJECTION );
884 qglLoadMatrixf( lightProjectionMatrix );
885 qglMatrixMode( GL_MODELVIEW );
887 qglViewport( 0, 0, lightBufferSize, lightBufferSize );
888 qglScissor( 0, 0, lightBufferSize, lightBufferSize );
889 qglStencilFunc( GL_ALWAYS, 0, 255 );
891 qglClearColor( 0, 1, 0, 0 );
892 GL_State( GLS_DEPTHFUNC_LESS | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); // make sure depth mask is off before clear
893 qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
895 // draw all the occluders
896 qglColor3f( 1, 1, 1 );
897 GL_SelectTexture( 0 );
898 qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
900 backEnd.currentSpace = NULL;
902 static float s_flipMatrix[16] = {
903 // convert from our coordinate system (looking down X)
904 // to OpenGL's coordinate system (looking down -Z)
911 float viewMatrix[16];
914 idVec3 origin = vLight->lightDef->globalLightOrigin;
918 vec = vLight->lightDef->parms.target;
920 viewMatrix[0] = vec[0];
921 viewMatrix[4] = vec[1];
922 viewMatrix[8] = vec[2];
924 vec = vLight->lightDef->parms.right;
926 viewMatrix[1] = -vec[0];
927 viewMatrix[5] = -vec[1];
928 viewMatrix[9] = -vec[2];
930 vec = vLight->lightDef->parms.up;
932 viewMatrix[2] = vec[0];
933 viewMatrix[6] = vec[1];
934 viewMatrix[10] = vec[2];
936 // side of a point light
937 memset( viewMatrix, 0, sizeof( viewMatrix ) );
972 viewMatrix[12] = -origin[0] * viewMatrix[0] + -origin[1] * viewMatrix[4] + -origin[2] * viewMatrix[8];
973 viewMatrix[13] = -origin[0] * viewMatrix[1] + -origin[1] * viewMatrix[5] + -origin[2] * viewMatrix[9];
974 viewMatrix[14] = -origin[0] * viewMatrix[2] + -origin[1] * viewMatrix[6] + -origin[2] * viewMatrix[10];
981 memcpy( unflippedLightMatrix, viewMatrix, sizeof( unflippedLightMatrix ) );
982 myGlMultMatrix( viewMatrix, s_flipMatrix,lightMatrix);
984 // create frustum planes
985 idPlane globalFrustum[6];
988 globalFrustum[0][0] = -viewMatrix[0];
989 globalFrustum[0][1] = -viewMatrix[4];
990 globalFrustum[0][2] = -viewMatrix[8];
991 globalFrustum[0][3] = -(origin[0] * globalFrustum[0][0] + origin[1] * globalFrustum[0][1] + origin[2] * globalFrustum[0][2]);
994 globalFrustum[1][0] = viewMatrix[0];
995 globalFrustum[1][1] = viewMatrix[4];
996 globalFrustum[1][2] = viewMatrix[8];
997 globalFrustum[1][3] = -globalFrustum[0][3] - viewLightAxialSize;
1000 globalFrustum[2][0] = -viewMatrix[0] + viewMatrix[1];
1001 globalFrustum[2][1] = -viewMatrix[4] + viewMatrix[5];
1002 globalFrustum[2][2] = -viewMatrix[8] + viewMatrix[9];
1004 globalFrustum[3][0] = -viewMatrix[0] - viewMatrix[1];
1005 globalFrustum[3][1] = -viewMatrix[4] - viewMatrix[5];
1006 globalFrustum[3][2] = -viewMatrix[8] - viewMatrix[9];
1008 globalFrustum[4][0] = -viewMatrix[0] + viewMatrix[2];
1009 globalFrustum[4][1] = -viewMatrix[4] + viewMatrix[6];
1010 globalFrustum[4][2] = -viewMatrix[8] + viewMatrix[10];
1012 globalFrustum[5][0] = -viewMatrix[0] - viewMatrix[2];
1013 globalFrustum[5][1] = -viewMatrix[4] - viewMatrix[6];
1014 globalFrustum[5][2] = -viewMatrix[8] - viewMatrix[10];
1016 // is this nromalization necessary?
1017 for ( int i = 0 ; i < 6 ; i++ ) {
1018 globalFrustum[i].ToVec4().ToVec3().Normalize();
1021 for ( int i = 2 ; i < 6 ; i++ ) {
1022 globalFrustum[i][3] = - (origin * globalFrustum[i].ToVec4().ToVec3() );
1025 RB_EXP_CullInteractions( vLight, globalFrustum );
1028 // FIXME: we want to skip the sampling as well as the generation when not casting shadows
1029 if ( !r_sb_noShadows.GetBool() && vLight->lightShader->LightCastsShadows() ) {
1031 // set polygon offset for the rendering
1033 switch ( r_sb_occluderFacing.GetInteger() ) {
1034 case 0: // front sides
1035 qglPolygonOffset( r_sb_polyOfsFactor.GetFloat(), r_sb_polyOfsUnits.GetFloat() );
1036 qglEnable( GL_POLYGON_OFFSET_FILL );
1037 RB_EXP_RenderOccluders( vLight );
1038 qglDisable( GL_POLYGON_OFFSET_FILL );
1040 case 1: // back sides
1041 qglPolygonOffset( -r_sb_polyOfsFactor.GetFloat(), -r_sb_polyOfsUnits.GetFloat() );
1042 qglEnable( GL_POLYGON_OFFSET_FILL );
1043 GL_Cull( CT_BACK_SIDED );
1044 RB_EXP_RenderOccluders( vLight );
1045 GL_Cull( CT_FRONT_SIDED );
1046 qglDisable( GL_POLYGON_OFFSET_FILL );
1048 case 2: // both sides
1049 GL_Cull( CT_BACK_SIDED );
1050 RB_EXP_RenderOccluders( vLight );
1051 GL_Cull( CT_FRONT_SIDED );
1052 shadowImage[2]->Bind();
1053 qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, lightBufferSize, lightBufferSize );
1055 RB_EXP_RenderOccluders( vLight );
1056 shadowImage[1]->Bind();
1057 qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, lightBufferSize, lightBufferSize );
1059 // fragment program to combine the two depth images
1060 qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, depthMidpointVertexProgram );
1061 qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, depthMidpointFragmentProgram );
1062 qglEnable(GL_VERTEX_PROGRAM_ARB);
1063 qglEnable(GL_FRAGMENT_PROGRAM_ARB);
1065 GL_SelectTextureNoClient( 1 );
1066 shadowImage[1]->Bind();
1067 qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE );
1068 qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
1069 qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
1071 GL_SelectTextureNoClient( 0 );
1072 shadowImage[2]->Bind();
1073 qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE );
1074 qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
1075 qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
1077 // draw a full screen quad
1078 qglMatrixMode( GL_PROJECTION );
1080 qglOrtho( 0, 1, 0, 1, -1, 1 );
1081 qglMatrixMode( GL_MODELVIEW );
1084 GL_State( GLS_DEPTHFUNC_ALWAYS );
1086 qglBegin( GL_TRIANGLE_FAN );
1087 qglTexCoord2f( 0, 0 );
1088 qglVertex2f( 0, 0 );
1089 qglTexCoord2f( 0, lightBufferSizeFraction );
1090 qglVertex2f( 0, 1 );
1091 qglTexCoord2f( lightBufferSizeFraction, lightBufferSizeFraction );
1092 qglVertex2f( 1, 1 );
1093 qglTexCoord2f( lightBufferSizeFraction, 0 );
1094 qglVertex2f( 1, 0 );
1097 qglDisable( GL_VERTEX_PROGRAM_ARB );
1098 qglDisable( GL_FRAGMENT_PROGRAM_ARB );
1104 // copy to the texture
1105 shadowImage[0]->Bind();
1106 qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, lightBufferSize, lightBufferSize );
1108 qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
1111 // reset the normal view matrix
1113 qglMatrixMode( GL_PROJECTION );
1114 qglLoadMatrixf( backEnd.viewDef->projectionMatrix );
1115 qglMatrixMode( GL_MODELVIEW );
1117 // the current modelView matrix is not valid
1118 backEnd.currentSpace = NULL;
1123 RB_EXP_DrawInteraction
1126 void RB_EXP_DrawInteraction( const drawInteraction_t *din ) {
1127 // load all the vertex program parameters
1128 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_ORIGIN, din->localLightOrigin.ToFloatPtr() );
1129 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_VIEW_ORIGIN, din->localViewOrigin.ToFloatPtr() );
1130 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_PROJECT_S, din->lightProjection[0].ToFloatPtr() );
1131 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_PROJECT_T, din->lightProjection[1].ToFloatPtr() );
1132 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_PROJECT_Q, din->lightProjection[2].ToFloatPtr() );
1133 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_FALLOFF_S, din->lightProjection[3].ToFloatPtr() );
1134 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_BUMP_MATRIX_S, din->bumpMatrix[0].ToFloatPtr() );
1135 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_BUMP_MATRIX_T, din->bumpMatrix[1].ToFloatPtr() );
1136 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_DIFFUSE_MATRIX_S, din->diffuseMatrix[0].ToFloatPtr() );
1137 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_DIFFUSE_MATRIX_T, din->diffuseMatrix[1].ToFloatPtr() );
1138 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_SPECULAR_MATRIX_S, din->specularMatrix[0].ToFloatPtr() );
1139 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_SPECULAR_MATRIX_T, din->specularMatrix[1].ToFloatPtr() );
1142 // calculate depth projection for shadow buffer
1149 myGlMultMatrix( din->surf->space->modelMatrix, lightMatrix, matrix );
1150 myGlMultMatrix( matrix, lightProjectionMatrix, matrix2 );
1152 // the final values need to be in 0.0 : 1.0 range instead of -1 : 1
1153 sRow[0] = 0.5 * lightBufferSizeFraction * ( matrix2[0] + matrix2[3] );
1154 sRow[1] = 0.5 * lightBufferSizeFraction * ( matrix2[4] + matrix2[7] );
1155 sRow[2] = 0.5 * lightBufferSizeFraction * ( matrix2[8] + matrix2[11] );
1156 sRow[3] = 0.5 * lightBufferSizeFraction * ( matrix2[12] + matrix2[15] );
1157 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 18, sRow );
1158 tRow[0] = 0.5 * lightBufferSizeFraction * ( matrix2[1] + matrix2[3] );
1159 tRow[1] = 0.5 * lightBufferSizeFraction * ( matrix2[5] + matrix2[7] );
1160 tRow[2] = 0.5 * lightBufferSizeFraction * ( matrix2[9] + matrix2[11] );
1161 tRow[3] = 0.5 * lightBufferSizeFraction * ( matrix2[13] + matrix2[15] );
1162 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 19, tRow );
1163 rRow[0] = 0.5 * ( matrix2[2] + matrix2[3] );
1164 rRow[1] = 0.5 * ( matrix2[6] + matrix2[7] );
1165 rRow[2] = 0.5 * ( matrix2[10] + matrix2[11] );
1166 rRow[3] = 0.5 * ( matrix2[14] + matrix2[15] );
1167 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 20, rRow );
1168 qRow[0] = matrix2[3];
1169 qRow[1] = matrix2[7];
1170 qRow[2] = matrix2[11];
1171 qRow[3] = matrix2[15];
1172 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 21, qRow );
1175 // testing fragment based normal mapping
1176 if ( r_testARBProgram.GetBool() ) {
1177 qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 2, din->localLightOrigin.ToFloatPtr() );
1178 qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 3, din->localViewOrigin.ToFloatPtr() );
1181 static const float zero[4] = { 0, 0, 0, 0 };
1182 static const float one[4] = { 1, 1, 1, 1 };
1183 static const float negOne[4] = { -1, -1, -1, -1 };
1185 switch ( din->vertexColor ) {
1187 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_MODULATE, zero );
1188 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_ADD, one );
1191 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_MODULATE, one );
1192 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_ADD, zero );
1194 case SVC_INVERSE_MODULATE:
1195 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_MODULATE, negOne );
1196 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_ADD, one );
1200 // set the constant colors
1201 qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 0, din->diffuseColor.ToFloatPtr() );
1202 qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 1, din->specularColor.ToFloatPtr() );
1204 //-----------------------------------------------------
1205 // screen power of two correction factor
1208 parm[0] = 1.0 / ( JITTER_SIZE * r_sb_samples.GetInteger() ) ;
1209 parm[1] = 1.0 / JITTER_SIZE;
1212 qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 2, parm );
1216 parm[1] = r_sb_jitterScale.GetFloat() * lightBufferSizeFraction;
1217 parm[2] = -r_sb_biasScale.GetFloat();
1219 qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 3, parm );
1221 // jitter tex offset
1222 if ( r_sb_randomize.GetBool() ) {
1223 parm[0] = (rand()&255) / 255.0;
1224 parm[1] = (rand()&255) / 255.0;
1226 parm[0] = parm[1] = 0;
1230 qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 4, parm );
1231 //-----------------------------------------------------
1235 // texture 1 will be the per-surface bump map
1236 GL_SelectTextureNoClient( 1 );
1237 din->bumpImage->Bind();
1239 // texture 2 will be the light falloff texture
1240 GL_SelectTextureNoClient( 2 );
1241 din->lightFalloffImage->Bind();
1243 // texture 3 will be the light projection texture
1244 GL_SelectTextureNoClient( 3 );
1245 din->lightImage->Bind();
1247 // texture 4 is the per-surface diffuse map
1248 GL_SelectTextureNoClient( 4 );
1249 din->diffuseImage->Bind();
1251 // texture 5 is the per-surface specular map
1252 GL_SelectTextureNoClient( 5 );
1253 din->specularImage->Bind();
1256 RB_DrawElementsWithCounters( din->surf->geo );
1261 RB_EXP_CreateDrawInteractions
1265 void RB_EXP_CreateDrawInteractions( const drawSurf_t *surf ) {
1269 if ( r_sb_screenSpaceShadow.GetBool() ) {
1270 // perform setup here that will be constant for all interactions
1271 GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | backEnd.depthFunc );
1273 if ( r_testARBProgram.GetBool() ) {
1274 qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_TEST );
1275 qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_TEST );
1277 qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_INTERACTION );
1278 qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_INTERACTION );
1281 // perform setup here that will be constant for all interactions
1282 GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | backEnd.depthFunc );
1283 GL_State( GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS );//!@#
1285 // bind the vertex program
1286 qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, shadowVertexProgram );
1287 if ( r_sb_samples.GetInteger() == 16 ) {
1288 qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, shadowFragmentProgram16 );
1289 } else if ( r_sb_samples.GetInteger() == 4 ) {
1290 qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, shadowFragmentProgram4 );
1291 } else if ( r_sb_samples.GetInteger() == 1 ) {
1292 qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, shadowFragmentProgram1 );
1294 qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, shadowFragmentProgram0 );
1298 qglEnable(GL_VERTEX_PROGRAM_ARB);
1299 qglEnable(GL_FRAGMENT_PROGRAM_ARB);
1301 // enable the vertex arrays
1302 qglEnableVertexAttribArrayARB( 8 );
1303 qglEnableVertexAttribArrayARB( 9 );
1304 qglEnableVertexAttribArrayARB( 10 );
1305 qglEnableVertexAttribArrayARB( 11 );
1306 qglEnableClientState( GL_COLOR_ARRAY );
1308 // texture 0 is the normalization cube map for the vector towards the light
1309 GL_SelectTextureNoClient( 0 );
1310 if ( backEnd.vLight->lightShader->IsAmbientLight() ) {
1311 globalImages->normalCubeMapImage->Bind();
1312 qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_AMBIENT);
1313 qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_AMBIENT);
1315 globalImages->normalCubeMapImage->Bind();
1318 // texture 6 is the specular lookup table
1319 GL_SelectTextureNoClient( 6 );
1320 if ( r_testARBProgram.GetBool() ) {
1321 globalImages->specular2DTableImage->Bind(); // variable specularity in alpha channel
1323 globalImages->specularTableImage->Bind();
1327 for ( ; surf ; surf=surf->nextOnLight ) {
1328 // perform setup here that will not change over multiple interaction passes
1329 if ( backEnd.vLight->lightShader->IsAmbientLight() ) {
1332 parm[0] = surf->space->modelMatrix[0];
1333 parm[1] = surf->space->modelMatrix[4];
1334 parm[2] = surf->space->modelMatrix[8];
1336 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 20, parm );
1337 parm[0] = surf->space->modelMatrix[1];
1338 parm[1] = surf->space->modelMatrix[5];
1339 parm[2] = surf->space->modelMatrix[9];
1341 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 21, parm );
1342 parm[0] = surf->space->modelMatrix[2];
1343 parm[1] = surf->space->modelMatrix[6];
1344 parm[2] = surf->space->modelMatrix[10];
1346 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 22, parm );
1348 GL_SelectTextureNoClient( 0 );
1349 const shaderStage_t *stage = backEnd.vLight->lightShader->GetStage( 0 );
1350 if ( stage->newStage ) {
1351 stage->newStage->fragmentProgramImages[7]->BindFragment();
1355 // set the vertex pointers
1356 idDrawVert *ac = (idDrawVert *)vertexCache.Position( surf->geo->ambientCache );
1357 qglColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( idDrawVert ), ac->color );
1358 qglVertexAttribPointerARB( 11, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->normal.ToFloatPtr() );
1359 qglVertexAttribPointerARB( 10, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[1].ToFloatPtr() );
1360 qglVertexAttribPointerARB( 9, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[0].ToFloatPtr() );
1361 qglVertexAttribPointerARB( 8, 2, GL_FLOAT, false, sizeof( idDrawVert ), ac->st.ToFloatPtr() );
1362 qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() );
1364 // this may cause RB_ARB2_DrawInteraction to be exacuted multiple
1365 // times with different colors and images if the surface or light have multiple layers
1366 if ( r_sb_screenSpaceShadow.GetBool() ) {
1367 RB_CreateSingleDrawInteractions( surf, RB_ARB2_DrawInteraction );
1369 RB_CreateSingleDrawInteractions( surf, RB_EXP_DrawInteraction );
1373 qglDisableVertexAttribArrayARB( 8 );
1374 qglDisableVertexAttribArrayARB( 9 );
1375 qglDisableVertexAttribArrayARB( 10 );
1376 qglDisableVertexAttribArrayARB( 11 );
1377 qglDisableClientState( GL_COLOR_ARRAY );
1380 GL_SelectTextureNoClient( 6 );
1381 globalImages->BindNull();
1383 GL_SelectTextureNoClient( 5 );
1384 globalImages->BindNull();
1386 GL_SelectTextureNoClient( 4 );
1387 globalImages->BindNull();
1389 GL_SelectTextureNoClient( 3 );
1390 globalImages->BindNull();
1392 GL_SelectTextureNoClient( 2 );
1393 globalImages->BindNull();
1395 GL_SelectTextureNoClient( 1 );
1396 globalImages->BindNull();
1398 backEnd.glState.currenttmu = -1;
1399 GL_SelectTexture( 0 );
1401 qglDisable(GL_VERTEX_PROGRAM_ARB);
1402 qglDisable(GL_FRAGMENT_PROGRAM_ARB);
1405 void InvertByTranspose( const float a[16], float r[16] ) {
1418 r[12] = -(r[ 0]*a[12] + r[ 4]*a[13] + r[ 8]*a[14]);
1419 r[13] = -(r[ 1]*a[12] + r[ 5]*a[13] + r[ 9]*a[14]);
1420 r[14] = -(r[ 2]*a[12] + r[ 6]*a[13] + r[10]*a[14]);
1424 void FullInvert( const float a[16], float r[16] ) {
1427 for ( int i = 0 ; i < 4 ; i++ ) {
1428 for ( int j = 0 ; j < 4 ; j++ ) {
1429 am[i][j] = a[j*4+i];
1433 // idVec4 test( 100, 100, 100, 1 );
1434 // idVec4 transformed, inverted;
1435 // transformed = test * am;
1437 if ( !am.InverseSelf() ) {
1438 common->Error( "Invert failed" );
1440 // inverted = transformed * am;
1442 for ( int i = 0 ; i < 4 ; i++ ) {
1443 for ( int j = 0 ; j < 4 ; j++ ) {
1444 r[j*4+i] = am[i][j];
1451 RB_Exp_TrianglesForFrustum
1454 const srfTriangles_t *RB_Exp_TrianglesForFrustum( viewLight_t *vLight, int side ) {
1455 const srfTriangles_t *tri;
1457 static srfTriangles_t frustumTri;
1458 static idDrawVert verts[5];
1459 static glIndex_t indexes[18] = { 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 1, 2, 1, 4, 2, 4, 3 };
1462 tri = vLight->frustumTris;
1464 memset( verts, 0, sizeof( verts ) );
1466 for ( int i = 0 ; i < 5 ; i++ ) {
1467 verts[i].xyz = vLight->globalLightOrigin;
1470 memset( &frustumTri, 0, sizeof( frustumTri ) );
1471 frustumTri.indexes = indexes;
1472 frustumTri.verts = verts;
1473 frustumTri.numIndexes = 18;
1474 frustumTri.numVerts = 5;
1478 float size = viewLightAxialSize;
1482 verts[1].xyz[0] += size;
1483 verts[2].xyz[0] += size;
1484 verts[3].xyz[0] += size;
1485 verts[4].xyz[0] += size;
1486 verts[1].xyz[1] += size;
1487 verts[1].xyz[2] += size;
1488 verts[2].xyz[1] -= size;
1489 verts[2].xyz[2] += size;
1490 verts[3].xyz[1] -= size;
1491 verts[3].xyz[2] -= size;
1492 verts[4].xyz[1] += size;
1493 verts[4].xyz[2] -= size;
1496 verts[1].xyz[0] -= size;
1497 verts[2].xyz[0] -= size;
1498 verts[3].xyz[0] -= size;
1499 verts[4].xyz[0] -= size;
1500 verts[1].xyz[1] -= size;
1501 verts[1].xyz[2] += size;
1502 verts[2].xyz[1] += size;
1503 verts[2].xyz[2] += size;
1504 verts[3].xyz[1] += size;
1505 verts[3].xyz[2] -= size;
1506 verts[4].xyz[1] -= size;
1507 verts[4].xyz[2] -= size;
1510 verts[1].xyz[1] += size;
1511 verts[2].xyz[1] += size;
1512 verts[3].xyz[1] += size;
1513 verts[4].xyz[1] += size;
1514 verts[1].xyz[0] -= size;
1515 verts[1].xyz[2] += size;
1516 verts[2].xyz[0] += size;
1517 verts[2].xyz[2] += size;
1518 verts[3].xyz[0] += size;
1519 verts[3].xyz[2] -= size;
1520 verts[4].xyz[0] -= size;
1521 verts[4].xyz[2] -= size;
1524 verts[1].xyz[1] -= size;
1525 verts[2].xyz[1] -= size;
1526 verts[3].xyz[1] -= size;
1527 verts[4].xyz[1] -= size;
1528 verts[1].xyz[0] += size;
1529 verts[1].xyz[2] += size;
1530 verts[2].xyz[0] -= size;
1531 verts[2].xyz[2] += size;
1532 verts[3].xyz[0] -= size;
1533 verts[3].xyz[2] -= size;
1534 verts[4].xyz[0] += size;
1535 verts[4].xyz[2] -= size;
1538 verts[1].xyz[2] += size;
1539 verts[2].xyz[2] += size;
1540 verts[3].xyz[2] += size;
1541 verts[4].xyz[2] += size;
1542 verts[1].xyz[0] += size;
1543 verts[1].xyz[1] += size;
1544 verts[2].xyz[0] -= size;
1545 verts[2].xyz[1] += size;
1546 verts[3].xyz[0] -= size;
1547 verts[3].xyz[1] -= size;
1548 verts[4].xyz[0] += size;
1549 verts[4].xyz[1] -= size;
1552 verts[1].xyz[2] -= size;
1553 verts[2].xyz[2] -= size;
1554 verts[3].xyz[2] -= size;
1555 verts[4].xyz[2] -= size;
1556 verts[1].xyz[0] -= size;
1557 verts[1].xyz[1] += size;
1558 verts[2].xyz[0] += size;
1559 verts[2].xyz[1] += size;
1560 verts[3].xyz[0] += size;
1561 verts[3].xyz[1] -= size;
1562 verts[4].xyz[0] -= size;
1563 verts[4].xyz[1] -= size;
1567 frustumTri.ambientCache = vertexCache.AllocFrameTemp( verts, sizeof( verts ) );
1576 RB_Exp_SelectFrustum
1579 void RB_Exp_SelectFrustum( viewLight_t *vLight, int side ) {
1580 qglLoadMatrixf( backEnd.viewDef->worldSpace.modelViewMatrix );
1582 const srfTriangles_t *tri = RB_Exp_TrianglesForFrustum( vLight, side );
1584 idDrawVert *ac = (idDrawVert *)vertexCache.Position( tri->ambientCache );
1585 qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() );
1587 qglDisable( GL_TEXTURE_2D );
1588 qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
1589 // clear stencil buffer
1590 qglEnable( GL_SCISSOR_TEST );
1591 qglEnable( GL_STENCIL_TEST );
1592 qglClearStencil( 1 );
1593 qglClear( GL_STENCIL_BUFFER_BIT );
1595 // draw front faces of the light frustum, incrementing the stencil buffer on depth fail
1596 // so we can't draw on those pixels
1597 GL_State( GLS_COLORMASK | GLS_ALPHAMASK | GLS_DEPTHMASK | GLS_DEPTHFUNC_LESS );
1598 qglStencilFunc( GL_ALWAYS, 0, 255 );
1599 qglStencilOp( GL_KEEP, GL_INCR, GL_KEEP );
1600 GL_Cull( CT_FRONT_SIDED );
1602 RB_DrawElementsWithCounters( tri );
1604 // draw back faces of the light frustum with
1605 // depth test greater
1606 // stencil test of equal 1
1607 // zero stencil stencil when depth test passes, so subsequent surface drawing
1608 // can occur on those pixels
1610 // this pass does all the shadow filtering
1611 qglStencilFunc( GL_EQUAL, 1, 255 );
1612 qglStencilOp( GL_KEEP, GL_KEEP, GL_ZERO );
1614 GL_Cull( CT_BACK_SIDED );
1615 qglDepthFunc( GL_GREATER );
1617 // write to destination alpha
1618 if ( r_sb_showFrustumPixels.GetBool() ) {
1619 GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_DEPTHFUNC_LESS );
1620 qglDisable( GL_TEXTURE_2D );
1621 qglColor4f( 0, 0.25, 0, 1 );
1623 GL_State( GLS_COLORMASK | GLS_DEPTHMASK | GLS_DEPTHFUNC_LESS );
1624 qglEnable(GL_VERTEX_PROGRAM_ARB);
1625 qglEnable(GL_FRAGMENT_PROGRAM_ARB);
1626 qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, screenSpaceShadowVertexProgram );
1627 switch ( r_sb_samples.GetInteger() ) {
1629 qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, screenSpaceShadowFragmentProgram0 );
1632 qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, screenSpaceShadowFragmentProgram1 );
1635 qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, screenSpaceShadowFragmentProgram4 );
1638 qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, screenSpaceShadowFragmentProgram16 );
1644 texture[0] = view depth texture
1645 texture[1] = jitter texture
1646 texture[2] = light depth texture
1648 GL_SelectTextureNoClient( 2 );
1649 shadowImage[0]->Bind();
1651 GL_SelectTextureNoClient( 1 );
1652 if ( r_sb_samples.GetInteger() == 16 ) {
1653 jitterImage16->Bind();
1654 } else if ( r_sb_samples.GetInteger() == 4 ) {
1655 jitterImage4->Bind();
1657 jitterImage1->Bind();
1660 GL_SelectTextureNoClient( 0 );
1661 viewDepthImage->Bind();
1664 PARAM positionToDepthTexScale = program.local[0]; # fragment.position to screen depth texture transformation
1665 PARAM zProject = program.local[1]; # projection[10], projection[14], 0, 0
1666 PARAM positionToViewSpace = program.local[2]; # X add, Y add, X mul, Y mul
1667 PARAM viewToLightS = program.local[3];
1668 PARAM viewToLightT = program.local[4];
1669 PARAM viewToLightR = program.local[5];
1670 PARAM viewToLightQ = program.local[6];
1671 PARAM positionToJitterTexScale = program.local[7]; # fragment.position to jitter texture
1672 PARAM jitterTexScale = program.local[8];
1673 PARAM jitterTexOffset = program.local[9];
1678 // calculate depth projection for shadow buffer
1683 float invertedView[16];
1684 float invertedProjection[16];
1688 // we need the inverse of the projection matrix to go from NDC to view
1689 FullInvert( backEnd.viewDef->projectionMatrix, invertedProjection );
1693 ( x - xMid ) * 1.0 / xMid
1694 ( y - yMid ) * 1.0 / yMid
1697 from NDC to clip coordinates:
1702 // we need the inverse of the viewMatrix to go from view (looking down negative Z) to world
1703 InvertByTranspose( backEnd.viewDef->worldSpace.modelViewMatrix, invertedView );
1705 // then we go from world to light view space (looking down negative Z)
1706 myGlMultMatrix( invertedView, lightMatrix, matrix );
1708 // then to light projection, giving X/w, Y/w, Z/w in the -1 : 1 range
1709 myGlMultMatrix( matrix, lightProjectionMatrix, matrix2 );
1711 // the final values need to be in 0.0 : 1.0 range instead of -1 : 1
1712 sRow[0] = 0.5 * ( matrix2[0] + matrix2[3] ) * lightBufferSizeFraction;
1713 sRow[1] = 0.5 * ( matrix2[4] + matrix2[7] ) * lightBufferSizeFraction;
1714 sRow[2] = 0.5 * ( matrix2[8] + matrix2[11] ) * lightBufferSizeFraction;
1715 sRow[3] = 0.5 * ( matrix2[12] + matrix2[15] ) * lightBufferSizeFraction;
1716 qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 3, sRow );
1717 tRow[0] = 0.5 * ( matrix2[1] + matrix2[3] ) * lightBufferSizeFraction;
1718 tRow[1] = 0.5 * ( matrix2[5] + matrix2[7] ) * lightBufferSizeFraction;
1719 tRow[2] = 0.5 * ( matrix2[9] + matrix2[11] ) * lightBufferSizeFraction;
1720 tRow[3] = 0.5 * ( matrix2[13] + matrix2[15] ) * lightBufferSizeFraction;
1721 qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 4, tRow );
1722 rRow[0] = 0.5 * ( matrix2[2] + matrix2[3] );
1723 rRow[1] = 0.5 * ( matrix2[6] + matrix2[7] );
1724 rRow[2] = 0.5 * ( matrix2[10] + matrix2[11] );
1725 rRow[3] = 0.5 * ( matrix2[14] + matrix2[15] );
1726 qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 5, rRow );
1727 qRow[0] = matrix2[3];
1728 qRow[1] = matrix2[7];
1729 qRow[2] = matrix2[11];
1730 qRow[3] = matrix2[15];
1731 qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 6, qRow );
1733 //-----------------------------------------------------
1734 // these should be constant for the entire frame
1736 // convert 0..viewport-1 sizes to fractions inside the POT screen depth texture
1737 int w = viewBufferSize;
1738 pot = MakePowerOfTwo( w );
1739 parm[0] = 1.0 / maxViewBufferSize; // * ( (float)viewBufferSize / w );
1740 int h = viewBufferHeight;
1741 pot = MakePowerOfTwo( h );
1742 parm[1] = parm[0]; // 1.0 / pot;
1745 qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 0, parm );
1748 parm[0] = backEnd.viewDef->projectionMatrix[10];
1749 parm[1] = backEnd.viewDef->projectionMatrix[14];
1752 qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 1, parm );
1754 // positionToViewSpace
1755 parm[0] = -1.0 / backEnd.viewDef->projectionMatrix[0];
1756 parm[1] = -1.0 / backEnd.viewDef->projectionMatrix[5];
1757 parm[2] = 2.0/viewBufferSize;
1758 parm[3] = 2.0/viewBufferSize;
1759 qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 2, parm );
1761 // positionToJitterTexScale
1762 parm[0] = 1.0 / ( JITTER_SIZE * r_sb_samples.GetInteger() ) ;
1763 parm[1] = 1.0 / JITTER_SIZE;
1766 qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 7, parm );
1770 parm[1] = r_sb_jitterScale.GetFloat() * lightBufferSizeFraction;
1771 parm[2] = -r_sb_biasScale.GetFloat();
1773 qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 8, parm );
1775 // jitter tex offset
1776 if ( r_sb_randomize.GetBool() ) {
1777 parm[0] = (rand()&255) / 255.0;
1778 parm[1] = (rand()&255) / 255.0;
1780 parm[0] = parm[1] = 0;
1784 qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 9, parm );
1785 //-----------------------------------------------------
1789 RB_DrawElementsWithCounters( tri );
1791 qglDisable(GL_VERTEX_PROGRAM_ARB);
1792 qglDisable(GL_FRAGMENT_PROGRAM_ARB);
1794 GL_Cull( CT_FRONT_SIDED );
1795 // qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
1797 qglDepthFunc( GL_LEQUAL );
1798 if ( r_sb_showFrustumPixels.GetBool() ) {
1799 qglEnable( GL_TEXTURE_2D );
1800 qglColor3f( 1, 1, 1 );
1803 // after all the frustums have been drawn, the surfaces that have been drawn on will get interactions
1804 // scissor may still be a win even with the stencil test for very fast rejects
1805 qglStencilFunc( GL_EQUAL, 0, 255 );
1806 qglStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
1808 // we can avoid clearing the stencil buffer by changing the hasLight value for each light
1813 R_EXP_CalcLightAxialSize
1815 all light side projections must currently match, so non-centered
1816 and non-cubic lights must take the largest length
1819 float R_EXP_CalcLightAxialSize( viewLight_t *vLight ) {
1822 if ( !vLight->lightDef->parms.pointLight ) {
1823 idVec3 dir = vLight->lightDef->parms.target - vLight->lightDef->parms.origin;
1828 for ( int i = 0 ; i < 3 ; i++ ) {
1829 float dist = fabs(vLight->lightDef->parms.lightCenter[i] );
1830 dist += vLight->lightDef->parms.lightRadius[i];
1840 R_EXP_RenderViewDepthImage
1842 This could be avoided by drop sampling the native view depth buffer with render to texture
1843 Bilerp might even be aprorpiate, although it would cause issues at edges
1846 void RB_T_FillDepthBuffer( const drawSurf_t *surf );
1848 void R_EXP_RenderViewDepthImage( void ) {
1849 if ( !r_sb_screenSpaceShadow.GetBool() ) {
1853 // if the screen resolution is exactly the window width, we can
1854 // use the depth buffer we already have
1855 if ( 0 ) { // nativeViewBuffer ) {
1856 viewDepthImage->CopyDepthbuffer( backEnd.viewDef->viewport.x1,
1857 backEnd.viewDef->viewport.y1, backEnd.viewDef->viewport.x2 - backEnd.viewDef->viewport.x1 + 1,
1858 backEnd.viewDef->viewport.y2 - backEnd.viewDef->viewport.y1 + 1 );
1860 RB_LogComment( "---------- R_EXP_RenderViewDepthImage ----------\n" );
1862 if ( r_sb_usePbuffer.GetBool() ) {
1864 // set the current openGL drawable to the shadow buffer
1865 R_MakeCurrent( viewPbufferDC, win32.hGLRC, NULL /* !@# viewPbuffer */ );
1868 // render the depth to the new size
1869 qglViewport( 0, 0, viewBufferSize, viewBufferHeight );
1870 qglScissor( 0, 0, viewBufferSize, viewBufferHeight );
1871 qglClear( GL_DEPTH_BUFFER_BIT );
1872 qglStencilFunc( GL_ALWAYS, 0, 255 );
1874 // the first texture will be used for alpha tested surfaces
1875 GL_SelectTexture( 0 );
1876 qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
1878 GL_State( GLS_DEPTHFUNC_LESS );
1880 RB_RenderDrawSurfListWithFunction( backEnd.viewDef->drawSurfs, backEnd.viewDef->numDrawSurfs, RB_T_FillDepthBuffer );
1883 // copy it to a texture
1885 viewDepthImage->Bind();
1886 qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, viewBufferSize, viewBufferHeight );
1888 if ( r_sb_usePbuffer.GetBool() ) {
1889 // set the normal screen drawable current
1890 R_MakeCurrent( win32.hDC, win32.hGLRC, NULL );
1893 // reset the window clipping
1894 qglMatrixMode( GL_PROJECTION );
1895 qglLoadMatrixf( backEnd.viewDef->projectionMatrix );
1896 qglMatrixMode( GL_MODELVIEW );
1898 qglViewport( tr.viewportOffset[0] + backEnd.viewDef->viewport.x1,
1899 tr.viewportOffset[1] + backEnd.viewDef->viewport.y1,
1900 backEnd.viewDef->viewport.x2 + 1 - backEnd.viewDef->viewport.x1,
1901 backEnd.viewDef->viewport.y2 + 1 - backEnd.viewDef->viewport.y1 );
1902 qglScissor( tr.viewportOffset[0] + backEnd.viewDef->viewport.x1,
1903 tr.viewportOffset[1] + backEnd.viewDef->viewport.y1,
1904 backEnd.viewDef->viewport.x2 + 1 - backEnd.viewDef->viewport.x1,
1905 backEnd.viewDef->viewport.y2 + 1 - backEnd.viewDef->viewport.y1 );
1907 // the current modelView matrix is not valid
1908 backEnd.currentSpace = NULL;
1911 qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE );
1912 qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE );
1913 qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
1914 qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
1919 RB_EXP_SetNativeBuffer
1921 This is always the back buffer, and scissor is set full screen
1924 void RB_EXP_SetNativeBuffer( void ) {
1925 // set the normal screen drawable current
1926 R_MakeCurrent( win32.hDC, win32.hGLRC, NULL );
1928 qglViewport( tr.viewportOffset[0] + backEnd.viewDef->viewport.x1,
1929 tr.viewportOffset[1] + backEnd.viewDef->viewport.y1,
1930 backEnd.viewDef->viewport.x2 + 1 - backEnd.viewDef->viewport.x1,
1931 backEnd.viewDef->viewport.y2 + 1 - backEnd.viewDef->viewport.y1 );
1933 backEnd.currentScissor = backEnd.viewDef->viewport;
1934 if ( r_useScissor.GetBool() ) {
1935 qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1,
1936 backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1,
1937 backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1,
1938 backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 );
1944 RB_EXP_SetRenderBuffer
1946 This may be to a float pBuffer, and scissor is set to cover only the light
1949 void RB_EXP_SetRenderBuffer( viewLight_t *vLight ) {
1950 if ( r_hdr_useFloats.GetBool() ) {
1951 R_MakeCurrent( floatPbufferDC, floatContext, floatPbuffer );
1953 if ( !qwglMakeCurrent( win32.hDC, win32.hGLRC ) ) {
1955 common->FatalError( "Couldn't return to normal drawing context" );
1959 qglViewport( tr.viewportOffset[0] + backEnd.viewDef->viewport.x1,
1960 tr.viewportOffset[1] + backEnd.viewDef->viewport.y1,
1961 backEnd.viewDef->viewport.x2 + 1 - backEnd.viewDef->viewport.x1,
1962 backEnd.viewDef->viewport.y2 + 1 - backEnd.viewDef->viewport.y1 );
1965 backEnd.currentScissor = backEnd.viewDef->viewport;
1967 backEnd.currentScissor = vLight->scissorRect;
1969 if ( r_useScissor.GetBool() ) {
1970 qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1,
1971 backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1,
1972 backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1,
1973 backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 );
1979 RB_shadowResampleAlpha
1983 void RB_shadowResampleAlpha( void ) {
1984 viewAlphaImage->Bind();
1985 // we could make this a subimage, but it isn't relevent once we have render-to-texture
1986 qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, viewBufferSize, viewBufferHeight );
1988 RB_EXP_SetRenderBuffer( backEnd.vLight );
1990 //=====================
1992 qglLoadMatrixf( backEnd.viewDef->worldSpace.modelViewMatrix );
1994 // this uses the full light, not side frustums
1995 const srfTriangles_t *tri = backEnd.vLight->frustumTris;
1997 idDrawVert *ac = (idDrawVert *)vertexCache.Position( tri->ambientCache );
1998 qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() );
2000 // clear stencil buffer
2001 qglEnable( GL_SCISSOR_TEST );
2002 qglEnable( GL_STENCIL_TEST );
2003 qglClearStencil( 1 );
2004 qglClear( GL_STENCIL_BUFFER_BIT );
2006 // draw front faces of the light frustum, incrementing the stencil buffer on depth fail
2007 // so we can't draw on those pixels
2008 GL_State( GLS_COLORMASK | GLS_ALPHAMASK | GLS_DEPTHMASK | GLS_DEPTHFUNC_LESS );
2009 qglStencilFunc( GL_ALWAYS, 0, 255 );
2010 qglStencilOp( GL_KEEP, GL_INCR, GL_KEEP );
2011 GL_Cull( CT_FRONT_SIDED );
2013 // set fragment / vertex program?
2015 RB_DrawElementsWithCounters( tri );
2017 // draw back faces of the light frustum with
2018 // depth test greater
2019 // stencil test of equal 1
2020 // zero stencil stencil when depth test passes, so subsequent interaction drawing
2021 // can occur on those pixels
2023 // this pass does all the shadow filtering
2024 qglStencilFunc( GL_EQUAL, 1, 255 );
2025 qglStencilOp( GL_KEEP, GL_KEEP, GL_ZERO );
2027 // write to destination alpha
2028 if ( r_sb_showFrustumPixels.GetBool() ) {
2029 GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_DEPTHFUNC_LESS );
2030 qglDisable( GL_TEXTURE_2D );
2031 qglColor4f( 0, 0.25, 0, 1 );
2033 GL_State( GLS_COLORMASK | GLS_DEPTHMASK | GLS_DEPTHFUNC_LESS );
2034 qglEnable(GL_VERTEX_PROGRAM_ARB);
2035 qglEnable(GL_FRAGMENT_PROGRAM_ARB);
2036 qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, shadowResampleVertexProgram );
2037 qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, shadowResampleFragmentProgram );
2039 // convert 0..viewport-1 sizes to fractions inside the POT screen depth texture
2040 // shrink by one unit for bilerp
2042 parm[0] = 1.0 / (maxViewBufferSize+1) * viewBufferSize / maxViewBufferSize;
2046 qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 0, parm );
2049 GL_Cull( CT_BACK_SIDED );
2050 qglDepthFunc( GL_GREATER );
2052 RB_DrawElementsWithCounters( tri );
2054 qglDisable(GL_VERTEX_PROGRAM_ARB);
2055 qglDisable(GL_FRAGMENT_PROGRAM_ARB);
2057 GL_Cull( CT_FRONT_SIDED );
2059 qglDepthFunc( GL_LEQUAL );
2060 if ( r_sb_showFrustumPixels.GetBool() ) {
2061 qglEnable( GL_TEXTURE_2D );
2062 qglColor3f( 1, 1, 1 );
2065 // after all the frustums have been drawn, the surfaces that have been drawn on will get interactions
2066 // scissor may still be a win even with the stencil test for very fast rejects
2067 qglStencilFunc( GL_EQUAL, 0, 255 );
2068 qglStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
2077 void RB_EXP_CoverScreen( void ) {
2078 // draw a full screen quad
2079 qglMatrixMode( GL_PROJECTION );
2081 qglOrtho( 0, 1, 0, 1, -1, 1 );
2082 qglMatrixMode( GL_MODELVIEW );
2085 qglBegin( GL_TRIANGLE_FAN );
2086 qglVertex2f( 0, 0 );
2087 qglVertex2f( 0, 1 );
2088 qglVertex2f( 1, 1 );
2089 qglVertex2f( 1, 0 );
2095 RB_EXP_ReadFloatBuffer
2098 void RB_EXP_ReadFloatBuffer( void ) {
2099 int pixels = glConfig.vidWidth * glConfig.vidHeight;
2100 float *buf = (float *)R_StaticAlloc( pixels * 4 * sizeof( float ) );
2102 qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_RGBA, GL_FLOAT, buf );
2104 float mins[4] = { 9999, 9999, 9999, 9999 };
2105 float maxs[4] = { -9999, -9999, -9999, -9999 };
2106 for ( int i = 0 ; i < pixels ; i++ ) {
2107 for ( int j = 0 ; j < 4 ; j++ ) {
2108 float v = buf[ i*4 + j ];
2109 if ( v < mins[j] ) {
2112 if ( v > maxs[j] ) {
2118 RB_EXP_SetNativeBuffer();
2121 qglMatrixMode( GL_PROJECTION );
2122 GL_State( GLS_DEPTHFUNC_ALWAYS );
2123 qglColor3f( 1, 1, 1 );
2126 qglDisable( GL_TEXTURE_2D );
2127 qglOrtho( 0, 1, 0, 1, -1, 1 );
2128 qglRasterPos2f( 0.01f, 0.01f );
2129 qglDrawPixels( glConfig.vidWidth, glConfig.vidHeight, GL_RGBA, GL_FLOAT, buf );
2131 qglEnable( GL_TEXTURE_2D );
2132 qglMatrixMode( GL_MODELVIEW );
2134 R_StaticFree( buf );
2138 void RB_TestGamma( void );
2145 void RB_EXP_GammaDither( void ) {
2146 if ( !r_hdr_useFloats.GetBool() ) {
2151 r_testGamma.SetBool( true );
2153 r_testGamma.SetBool( false );
2156 RB_EXP_SetNativeBuffer();
2159 # texture 0 is the high dynamic range buffer
2160 # texture 1 is the random dither texture
2161 # texture 2 is the light bloom texture
2163 # writes result.color as the 32 bit dithered and gamma corrected values
2165 PARAM exposure = program.local[0]; # multiply HDR value by this to get screen pixels
2166 PARAM gammaPower = program.local[1];
2167 PARAM monitorDither = program.local[2];
2168 PARAM positionToDitherScale = program.local[3];
2169 PARAM bloomFraction = program.local[4];
2170 PARAM positionToBloomScale = program.local[5];
2174 qglBindProgramARB( GL_VERTEX_PROGRAM_ARB,gammaDitherVertexProgram );
2175 qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, gammaDitherFragmentProgram );
2176 qglEnable(GL_VERTEX_PROGRAM_ARB);
2177 qglEnable(GL_FRAGMENT_PROGRAM_ARB);
2179 qglActiveTextureARB( GL_TEXTURE2_ARB );
2180 qglBindTexture( GL_TEXTURE_RECTANGLE_NV, floatPbufferQuarterImage->texnum );
2181 R_BindTexImage( floatPbufferQuarter );
2183 qglActiveTextureARB( GL_TEXTURE1_ARB );
2184 random256Image->BindFragment();
2186 qglActiveTextureARB( GL_TEXTURE0_ARB );
2187 qglBindTexture( GL_TEXTURE_RECTANGLE_NV, floatPbufferImage->texnum );
2188 R_BindTexImage( floatPbuffer );
2192 parm[0] = r_hdr_exposure.GetFloat();
2196 qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 0, parm );
2198 parm[0] = r_hdr_gamma.GetFloat();
2202 qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 1, parm );
2204 parm[0] = r_hdr_monitorDither.GetFloat();
2208 qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 2, parm );
2210 parm[0] = 1.0 / 256;
2212 parm[2] = rand()/65535.0;
2213 parm[3] = rand()/65535.0;
2214 qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 3, parm );
2216 parm[0] = 1.0 - r_hdr_bloomFraction.GetFloat();
2217 parm[1] = r_hdr_bloomFraction.GetFloat();
2220 qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 4, parm );
2226 qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 5, parm );
2228 qglDisable( GL_STENCIL_TEST );
2229 qglDisable( GL_SCISSOR_TEST );
2230 qglDisable( GL_DEPTH_TEST );
2232 RB_EXP_CoverScreen();
2234 qglEnable( GL_DEPTH_TEST );
2236 qglDisable(GL_VERTEX_PROGRAM_ARB);
2237 qglDisable(GL_FRAGMENT_PROGRAM_ARB);
2245 void RB_EXP_Bloom( void ) {
2246 if ( !r_hdr_useFloats.GetBool() ) {
2250 if ( r_hdr_bloomFraction.GetFloat() == 0 ) {
2260 // draw to the second floatPbuffer
2261 R_MakeCurrent( floatPbuffer2DC, floatContext, floatPbuffer2 );
2264 qglDisable( GL_DEPTH_TEST );
2265 qglDisable( GL_SCISSOR_TEST );
2267 qglEnable(GL_VERTEX_PROGRAM_ARB);
2268 qglEnable(GL_FRAGMENT_PROGRAM_ARB);
2270 qglClearColor( 1.0, 0.5, 0, 0 );
2271 qglClear( GL_COLOR_BUFFER_BIT );
2272 qglViewport( 0, 0, glConfig.vidWidth>>1, glConfig.vidHeight>>1 );
2274 // read from the original floatPbuffer
2275 qglActiveTextureARB( GL_TEXTURE0_ARB );
2276 qglBindTexture( GL_TEXTURE_RECTANGLE_NV, floatPbufferImage->texnum );
2277 R_BindTexImage( floatPbuffer );
2279 qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, downSampleVertexProgram );
2280 qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, downSampleFragmentProgram );
2282 RB_EXP_CoverScreen();
2287 qglViewport( 0, 0, glConfig.vidWidth>>2, glConfig.vidHeight>>2 );
2289 // draw to the second floatPbuffer
2290 R_MakeCurrent( floatPbufferQuarterDC, floatContext, floatPbufferQuarter );
2292 // read from the original floatPbuffer
2293 qglBindTexture( GL_TEXTURE_RECTANGLE_NV, floatPbuffer2Image->texnum );
2294 R_BindTexImage( floatPbuffer2 );
2296 RB_EXP_CoverScreen();
2299 // blur horizontally
2302 # texture 0 is the high dynamic range buffer
2303 # writes result.color as the fp16 result of a smeared bloom
2305 PARAM step = program.local[0]; # { 1, 0 } or { 0, 1 } for horizontal / vertical separation
2308 // draw to the second floatPbuffer
2309 R_MakeCurrent( floatPbuffer2DC, floatContext, floatPbuffer2 );
2311 qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, bloomVertexProgram );
2312 qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, bloomFragmentProgram );
2313 qglEnable(GL_VERTEX_PROGRAM_ARB);
2314 qglEnable(GL_FRAGMENT_PROGRAM_ARB);
2316 GL_SelectTextureNoClient( 0 );
2318 // blur horizontally first to the second floatPbuffer
2319 qglBindTexture( GL_TEXTURE_RECTANGLE_NV, floatPbufferQuarterImage->texnum );
2320 R_BindTexImage( floatPbufferQuarter );
2328 qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 0, parm );
2330 RB_EXP_CoverScreen();
2333 // now blur vertically back to the quarter pbuffer
2335 R_MakeCurrent( floatPbufferQuarterDC, floatContext, floatPbufferQuarter );
2337 qglBindTexture( GL_TEXTURE_RECTANGLE_NV, floatPbuffer2Image->texnum );
2338 R_BindTexImage( floatPbuffer2 );
2344 qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 0, parm );
2346 RB_EXP_CoverScreen();
2348 //========================
2350 qglEnable( GL_DEPTH_TEST );
2351 qglEnable( GL_SCISSOR_TEST );
2353 qglDisable(GL_VERTEX_PROGRAM_ARB);
2354 qglDisable(GL_FRAGMENT_PROGRAM_ARB);
2361 RB_Exp_DrawInteractions
2364 void RB_Exp_DrawInteractions( void ) {
2365 if ( !initialized ) {
2369 if ( !backEnd.viewDef->viewLights ) {
2373 // validate the samples
2374 if ( r_sb_samples.GetInteger() != 16 && r_sb_samples.GetInteger() != 4 && r_sb_samples.GetInteger() != 1 ) {
2375 r_sb_samples.SetInteger( 0 );
2378 // validate the light resolution
2379 if ( r_sb_lightResolution.GetInteger() < 64 ) {
2380 r_sb_lightResolution.SetInteger( 64 );
2381 } else if ( r_sb_lightResolution.GetInteger() > maxLightBufferSize ) {
2382 r_sb_lightResolution.SetInteger( maxLightBufferSize );
2384 lightBufferSize = r_sb_lightResolution.GetInteger();
2385 lightBufferSizeFraction = (float)lightBufferSize / maxLightBufferSize;
2387 // validate the view resolution
2388 if ( r_sb_viewResolution.GetInteger() < 64 ) {
2389 r_sb_viewResolution.SetInteger( 64 );
2390 } else if ( r_sb_viewResolution.GetInteger() > maxViewBufferSize ) {
2391 r_sb_viewResolution.SetInteger( maxViewBufferSize );
2393 viewBufferSize = r_sb_viewResolution.GetInteger();
2394 viewBufferHeight = viewBufferSize * 3 / 4;
2395 viewBufferSizeFraction = (float)viewBufferSize / maxViewBufferSize;
2396 viewBufferHeightFraction = (float)viewBufferHeight / maxViewBufferSize;
2397 if ( viewBufferSize == backEnd.viewDef->viewport.x2 - backEnd.viewDef->viewport.x1 + 1 ) {
2398 nativeViewBuffer = true;
2400 nativeViewBuffer = false;
2403 // set up for either point sampled or percentage-closer filtering for the shadow sampling
2404 shadowImage[0]->BindFragment();
2405 if ( r_sb_linearFilter.GetBool() ) {
2406 qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
2407 qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
2409 qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
2410 qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
2412 qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE );
2414 globalImages->BindNull();
2416 // copy the current depth buffer to a texture for image-space shadowing,
2417 // or re-render at a lower resolution
2418 R_EXP_RenderViewDepthImage();
2420 GL_SelectTexture( 0 );
2421 qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
2423 // disable stencil shadow test
2424 qglStencilFunc( GL_ALWAYS, 128, 255 );
2426 // the jitter image will be used to offset sample centers
2427 GL_SelectTextureNoClient( 8 );
2428 if ( r_sb_samples.GetInteger() == 16 ) {
2429 jitterImage16->BindFragment();
2430 } else if ( r_sb_samples.GetInteger() == 4 ) {
2431 jitterImage4->BindFragment();
2433 jitterImage1->BindFragment();
2436 // if we are using a float buffer, clear it now
2437 if ( r_hdr_useFloats.GetBool() ) {
2438 RB_EXP_SetRenderBuffer( NULL );
2439 // we need to set a lot of things, because this is a completely different context
2440 RB_SetDefaultGLState();
2441 qglClearColor( 0.001f, 1.0f, 0.01f, 0.1f );
2442 qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
2443 // clear the z buffer, set the projection matrix, etc
2444 RB_BeginDrawingView();
2445 RB_STD_FillDepthBuffer( (drawSurf_t **)&backEnd.viewDef->drawSurfs[0], backEnd.viewDef->numDrawSurfs );
2450 // for each light, perform adding and shadowing
2452 for ( viewLight_t *vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) {
2453 backEnd.vLight = vLight;
2455 const idMaterial *lightShader = vLight->lightShader;
2458 if ( lightShader->IsFogLight() ) {
2461 if ( lightShader->IsBlendLight() ) {
2465 if ( !vLight->localInteractions && !vLight->globalInteractions
2466 && !vLight->translucentInteractions ) {
2470 if ( !vLight->frustumTris->ambientCache ) {
2471 R_CreateAmbientCache( const_cast<srfTriangles_t *>(vLight->frustumTris), false );
2474 // all light side projections must currently match, so non-centered
2475 // and non-cubic lights must take the largest length
2476 viewLightAxialSize = R_EXP_CalcLightAxialSize( vLight );
2480 if ( vLight->lightDef->parms.pointLight ) {
2481 if ( r_sb_singleSide.GetInteger() != -1 ) {
2482 side = r_sb_singleSide.GetInteger();
2493 for ( ; side < sideStop ; side++ ) {
2494 // FIXME: check for frustums completely off the screen
2496 // render a shadow buffer
2497 RB_RenderShadowBuffer( vLight, side );
2499 // back to view rendering, possibly in the off-screen buffer
2500 if ( nativeViewBuffer || !r_sb_screenSpaceShadow.GetBool() ) {
2501 // directly to screen
2502 RB_EXP_SetRenderBuffer( vLight );
2504 // to off screen buffer
2505 if ( r_sb_usePbuffer.GetBool() ) {
2507 // set the current openGL drawable to the shadow buffer
2508 R_MakeCurrent( viewPbufferDC, win32.hGLRC, viewPbuffer );
2510 qglViewport( 0, 0, viewBufferSize, viewBufferHeight );
2511 qglScissor( 0, 0, viewBufferSize, viewBufferHeight ); // !@# FIXME: scale light scissor
2514 // render the shadows into destination alpha on the included pixels
2515 RB_Exp_SelectFrustum( vLight, side );
2517 if ( !r_sb_screenSpaceShadow.GetBool() ) {
2518 // bind shadow buffer to texture
2519 GL_SelectTextureNoClient( 7 );
2520 shadowImage[0]->BindFragment();
2522 RB_EXP_CreateDrawInteractions( vLight->localInteractions );
2523 RB_EXP_CreateDrawInteractions( vLight->globalInteractions );
2524 backEnd.depthFunc = GLS_DEPTHFUNC_LESS;
2525 RB_EXP_CreateDrawInteractions( vLight->translucentInteractions );
2526 backEnd.depthFunc = GLS_DEPTHFUNC_EQUAL;
2530 // render the native window coordinates interactions
2531 if ( r_sb_screenSpaceShadow.GetBool() ) {
2532 if ( !nativeViewBuffer ) {
2533 RB_shadowResampleAlpha();
2534 qglEnable( GL_STENCIL_TEST );
2536 RB_EXP_SetRenderBuffer( vLight );
2537 if ( r_ignore.GetBool() ) {
2538 qglEnable( GL_STENCIL_TEST ); //!@#
2540 qglDisable( GL_STENCIL_TEST ); //!@#
2543 RB_EXP_CreateDrawInteractions( vLight->localInteractions );
2544 RB_EXP_CreateDrawInteractions( vLight->globalInteractions );
2545 backEnd.depthFunc = GLS_DEPTHFUNC_LESS;
2546 RB_EXP_CreateDrawInteractions( vLight->translucentInteractions );
2547 backEnd.depthFunc = GLS_DEPTHFUNC_EQUAL;
2551 GL_SelectTexture( 0 );
2552 qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
2554 // experimental transfer function
2555 for ( int i = 7 ; i >= 0 ; i-- ) {
2556 GL_SelectTextureNoClient( i );
2557 globalImages->BindNull();
2562 RB_EXP_GammaDither();
2564 // these haven't been state saved
2565 for ( int i = 0 ; i < 8 ; i++ ) {
2566 backEnd.glState.tmu[i].current2DMap = -1;
2569 // take it out of texture compare mode so I can testImage it for debugging
2570 shadowImage[0]->BindFragment();
2571 qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE );
2583 void R_Exp_Init( void ) {
2584 glConfig.allowExpPath = false;
2586 common->Printf( "---------- R_Exp_Init ----------\n" );
2588 if ( !glConfig.ARBVertexProgramAvailable || !glConfig.ARBFragmentProgramAvailable ) {
2589 common->Printf( "Not available.\n" );
2592 RB_CreateBloomTable();
2594 if ( !R_CheckExtension( "GL_NV_float_buffer" ) ) {
2595 common->Printf( "Not available.\n" );
2598 if ( !R_CheckExtension( "GL_NV_texture_rectangle" ) ) {
2599 common->Printf( "Not available.\n" );
2605 qglCombinerParameterfvNV = (void (APIENTRY *)( GLenum pname, const GLfloat *params ))
2606 GLimp_ExtensionPointer( "glCombinerParameterfvNV" );
2609 common->Printf( "Available.\n" );
2611 if ( !idStr::Icmp( r_renderer.GetString(), "exp" ) ) {
2615 common->Printf( "--------------------------------------------\n" );
2617 glConfig.allowExpPath = true;