]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/renderer/draw_exp.cpp
Use the same OpenAL headers on all platforms.
[icculus/iodoom3.git] / neo / renderer / draw_exp.cpp
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
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.
13
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.
18
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/>.
21
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.
23
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.
25
26 ===========================================================================
27 */
28
29 #include "../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include "tr_local.h"
33 #include "../sys/win32/win_local.h"
34
35 /*
36
37 strictly experimental / research codepaths
38
39 !!!if we use front facing occluders, we can portal flow from light centers
40
41 try depth_component_16 rendering
42
43 do we care about portals from light perspective? back / front face issues.
44
45 how do we do weapon depth hacks with shadow buffers?
46         distort their world space vertexes instead of offsetting their depth?
47
48 jittering off the side of a projection will give wrong shadows
49
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
52
53 It sucks that depth buffers are non-linear, because the bias and compares change with distance
54
55 polygon offset factor causes occasional texture holes from highly angled textures
56
57 */
58
59 static  bool            initialized;
60
61 static  int lightBufferSize = 1024;
62 static  int     maxLightBufferSize = 1024;
63 static float lightBufferSizeFraction = 0.5;
64
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
71
72 static  HPBUFFERARB     floatPbuffer;
73 static  HDC                     floatPbufferDC;
74 static  idImage         *floatPbufferImage;
75
76 static  HPBUFFERARB     floatPbuffer2;
77 static  HDC                     floatPbuffer2DC;
78 static  idImage         *floatPbuffer2Image;
79
80 static  HPBUFFERARB     floatPbufferQuarter;
81 static  HDC                     floatPbufferQuarterDC;
82 static  idImage         *floatPbufferQuarterImage;
83
84 static  HGLRC           floatContext;
85
86 static  HPBUFFERARB     shadowPbuffer;
87 static  HDC                     shadowPbufferDC;
88
89 static  HPBUFFERARB     viewPbuffer;
90 static  HDC                     viewPbufferDC;
91
92 static  idImage         *shadowImage[3];
93
94 static  idImage         *viewDepthImage;
95 static  idImage         *viewAlphaImage;
96
97 static  idImage         *viewShadowImage;
98
99 static  idImage         *jitterImage16;
100 static  idImage         *jitterImage4;
101 static  idImage         *jitterImage1;
102
103 static  idImage         *random256Image;
104
105 static  int                     shadowVertexProgram;
106 static  int                     shadowFragmentProgram16;
107 static  int                     shadowFragmentProgram4;
108 static  int                     shadowFragmentProgram1;
109 static  int                     shadowFragmentProgram0;
110
111 static  int                     screenSpaceShadowVertexProgram;
112 static  int                     screenSpaceShadowFragmentProgram16;
113 static  int                     screenSpaceShadowFragmentProgram4;
114 static  int                     screenSpaceShadowFragmentProgram1;
115 static  int                     screenSpaceShadowFragmentProgram0;
116
117 static  int                     depthMidpointVertexProgram;
118 static  int                     depthMidpointFragmentProgram;
119
120 static  int                     shadowResampleVertexProgram;
121 static  int                     shadowResampleFragmentProgram;
122
123 static  int                     gammaDitherVertexProgram;
124 static  int                     gammaDitherFragmentProgram;
125
126 static  int                     downSampleVertexProgram;
127 static  int                     downSampleFragmentProgram;
128
129 static  int                     bloomVertexProgram;
130 static  int                     bloomFragmentProgram;
131
132 static  float           viewLightAxialSize;
133
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?
147
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" );
153
154 idCVar r_sb_screenSpaceShadow( "r_sb_screenSpaceShadow", "1", CVAR_RENDERER | CVAR_BOOL, "build shadows in screen space instead of on surfaces" );
155
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" );
161
162 // from world space to light origin, looking down the X axis
163 static float    unflippedLightMatrix[16];
164
165 // from world space to OpenGL view space, looking down the negative Z axis
166 static float    lightMatrix[16];
167
168 // from OpenGL view space to OpenGL NDC ( -1 : 1 in XYZ )
169 static float    lightProjectionMatrix[16];
170
171
172 void    RB_ARB2_DrawInteraction( const drawInteraction_t *din );
173
174 typedef struct {
175         const char      *name;
176         int                     num;
177 } wglString_t;
178
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 },
221
222 { "WGL_NO_ACCELERATION_ARB",                    0x2025 },
223 { "WGL_GENERIC_ACCELERATION_ARB",               0x2026 },
224 { "WGL_FULL_ACCELERATION_ARB",          0x2027 },
225
226 { "WGL_SWAP_EXCHANGE_ARB",                      0x2028 },
227 { "WGL_SWAP_COPY_ARB",                  0x2029 },
228 { "WGL_SWAP_UNDEFINED_ARB",                     0x202A },
229
230 { "WGL_TYPE_RGBA_ARB",                  0x202B },
231 { "WGL_TYPE_COLORINDEX_ARB",                    0x202C },
232 };
233
234 static const int NUM_WGL_STRINGS = sizeof( wglString ) / sizeof( wglString[0] );
235
236 static void R_CheckWglErrors( void ) {
237         int     err = GetLastError();
238         char    *name;
239
240 #if 0
241         LPVOID lpMsgBuf;
242         FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
243                                         NULL,
244                                         err,
245                                         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
246                                         (LPTSTR) &lpMsgBuf,
247                                         0,
248                                         NULL 
249                                         );
250 #endif
251         err &= 0xffff;
252         switch ( err ) {
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;
257         }
258
259         common->Printf( "GetLastError: %s\n", name );
260 }
261
262 static void R_MakeCurrent( HDC dc, HGLRC context, HPBUFFERARB pbuffer ) {
263         if ( pbuffer ) {
264                 if ( !wglReleaseTexImageARB( pbuffer, WGL_FRONT_LEFT_ARB ) ) {
265                         R_CheckWglErrors();
266                         common->Error( "wglReleaseTexImageARB failed" );
267                 }
268         }
269         if ( !qwglMakeCurrent( dc, context ) ) {
270                 R_CheckWglErrors();
271                 common->FatalError( "qwglMakeCurrent failed" );
272         }
273 }
274
275 static void R_BindTexImage( HPBUFFERARB pbuffer ) {
276         if ( !wglReleaseTexImageARB( pbuffer, WGL_FRONT_LEFT_ARB ) ) {
277                 R_CheckWglErrors();
278                 common->Error( "wglReleaseTexImageARB failed" );
279         }
280         if ( !wglBindTexImageARB( pbuffer, WGL_FRONT_LEFT_ARB ) ) {
281                 R_CheckWglErrors();
282                 common->Error( "failed wglBindTexImageARB" );
283         }
284 }
285
286 static void R_ReportTextureParms( void ) {
287         int     parms[8];
288
289 //      q glGetTexParameteriv( GL_TEXTURE_RECTANGLE_NV, 
290         qglGetIntegerv( GL_TEXTURE_BINDING_RECTANGLE_NV, parms );
291
292 }
293
294 /*
295 ====================
296 RB_CreateBloomTable
297 ====================
298 */
299 static const int        BLOOM_RADIUS = 8;
300 static void RB_CreateBloomTable( void ) {
301         float   bloom[BLOOM_RADIUS];
302         float   total = 0;
303
304         // gaussian
305         float   stdDev = 2.0;
306         for ( int i = 0 ; i < BLOOM_RADIUS ; i++ ) {
307                 float   f = (float)i / stdDev;
308                 bloom[i] = exp( -0.5 * f * f );
309                 total += bloom[i];
310         }
311
312         total = ( total - bloom[0] ) * 2 + bloom[0];
313
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] );
318         }
319
320 }
321
322 /*
323 ====================
324 GL_SelectTextureNoClient
325 ====================
326 */
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 );
331 }
332
333
334 /*
335 ================
336 R_CreateShadowBufferImage
337
338 ================
339 */
340 static void R_CreateShadowBufferImage( idImage *image ) {
341         byte    *data = (byte *)Mem_Alloc( lightBufferSize*lightBufferSize );
342
343         memset( data, 0, lightBufferSize*lightBufferSize );
344
345         image->GenerateImage( (byte *)data, 4, 4, 
346                 TF_LINEAR, false, TR_CLAMP_TO_BORDER, TD_HIGH_QUALITY );
347
348         // now reset it to a shadow depth image
349         GL_CheckErrors();
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 );
353
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 );
357
358         // explicit zero depth border
359         float   color[4];
360         color[0] = color[1] = color[2] = color[3] = 0;
361         qglTexParameterfv( GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color );
362
363         GL_CheckErrors();
364
365         Mem_Free( data );
366 }
367
368 static void R_CreateViewAlphaImage( idImage *image ) {
369         int             c = viewBufferSize*viewBufferSize*4;
370         byte    *data = (byte *)Mem_Alloc( c );
371
372         // don't let it pick an intensity format
373         for ( int i = 0 ; i < c ; i++ ) {
374                 data[i] = i;
375         }
376         memset( data, 0, viewBufferSize*viewBufferSize );
377
378         image->GenerateImage( (byte *)data, viewBufferSize, viewBufferSize, 
379                 TF_LINEAR, false, TR_CLAMP, TD_HIGH_QUALITY );
380 }
381
382 static void R_CreateStubImage( idImage *image ) {
383         float   data[3][4][4];
384
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 );
390 }
391
392 /*
393 ================
394 R_CreateJitterImage
395
396 ================
397 */
398 const static    int JITTER_SIZE = 128;
399 static void R_CreateJitterImage16( idImage *image ) {
400         byte    data[JITTER_SIZE][JITTER_SIZE*16][4];
401
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 );
406
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;
412                         }
413                 }
414         }
415
416         image->GenerateImage( (byte *)data, JITTER_SIZE*16, JITTER_SIZE, 
417                 TF_NEAREST, false, TR_REPEAT, TD_HIGH_QUALITY );
418 }
419
420 static void R_CreateJitterImage4( idImage *image ) {
421         byte    data[JITTER_SIZE][JITTER_SIZE*4][4];
422
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 );
427
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;
433                         }
434                 }
435         }
436
437         image->GenerateImage( (byte *)data, JITTER_SIZE*4, JITTER_SIZE, 
438                 TF_NEAREST, false, TR_REPEAT, TD_HIGH_QUALITY );
439 }
440
441 static void R_CreateJitterImage1( idImage *image ) {
442         byte    data[JITTER_SIZE][JITTER_SIZE][4];
443
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();
449                         data[i][j][3] = 0;
450                 }
451         }
452
453         image->GenerateImage( (byte *)data, JITTER_SIZE, JITTER_SIZE, 
454                 TF_NEAREST, false, TR_REPEAT, TD_HIGH_QUALITY );
455 }
456
457 static void R_CreateRandom256Image( idImage *image ) {
458         byte    data[256][256][4];
459
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();
466                 }
467         }
468
469         image->GenerateImage( (byte *)data, 256, 256, 
470                 TF_NEAREST, false, TR_REPEAT, TD_HIGH_QUALITY );
471 }
472
473
474 /*
475 ==================
476 R_PrintPixelFormat
477 ==================
478 */
479 void R_PrintPixelFormat( int pixelFormat ) {
480         int             res;
481         int             iAttribute;
482         int     iValue;
483
484         common->Printf( "----- pixelFormat %i -----\n", pixelFormat );
485
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 );
491                 }
492         }
493 }
494
495
496 /*
497 ==================
498 R_Exp_Allocate
499 ==================
500 */
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};
505         UINT    numFormats;
506         int             pixelformats[1024];
507         int             ret;
508         int     pbiAttributes[] = {0, 0};
509
510         initialized = true;
511
512 #if 1
513         //
514         // allocate the floating point rendering buffer
515         //
516         atr_p = iAttributes;
517
518         *atr_p++ = WGL_DRAW_TO_PBUFFER_ARB;
519         *atr_p++ = TRUE;
520         *atr_p++ = WGL_FLOAT_COMPONENTS_NV;
521         *atr_p++ = TRUE;
522         *atr_p++ = WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV;
523         *atr_p++ = TRUE;
524 //      *atr_p++ = WGL_BIND_TO_TEXTURE_RGBA_ARB;
525 //      *atr_p++ = TRUE;
526         *atr_p++ = WGL_DEPTH_BITS_ARB;
527         *atr_p++ = 24;
528         *atr_p++ = WGL_STENCIL_BITS_ARB;
529         *atr_p++ = 8;
530         *atr_p++ = 0;
531         *atr_p++ = 0;
532
533         ret = wglChoosePixelFormatARB( win32.hDC, iAttributes, fAttributes, 
534                 sizeof( pixelformats ) / sizeof( pixelformats[0] ), pixelformats, &numFormats );
535
536 #if 0
537         for ( int i = 0 ; i < (int)numFormats ; i++ ) {
538                 R_PrintPixelFormat( pixelformats[i] );
539         }
540 #endif
541         common->Printf( "\nfloatPbuffer:\n" );
542         R_PrintPixelFormat( pixelformats[0] );
543
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,
548                         0, 0};
549
550         floatPbuffer = wglCreatePbufferARB( win32.hDC, pixelformats[0], glConfig.vidWidth,
551                 glConfig.vidHeight, pbiAttributesTexture );
552         if ( !floatPbuffer ) {
553                 common->Printf( "failed to create floatPbuffer.\n" );
554                 GL_CheckErrors();
555         }
556         floatPbufferDC = wglGetPbufferDCARB( floatPbuffer );
557         floatPbufferImage = globalImages->ImageFromFunction( "_floatPbuffer", R_CreateStubImage );
558
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" );
564                 GL_CheckErrors();
565         }
566         floatPbuffer2DC = wglGetPbufferDCARB( floatPbuffer2 );
567         floatPbuffer2Image = globalImages->ImageFromFunction( "_floatPbuffer2", R_CreateStubImage );
568
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" );
574                 GL_CheckErrors();
575         }
576         floatPbufferQuarterDC = wglGetPbufferDCARB( floatPbufferQuarter );
577         floatPbufferQuarterImage = globalImages->ImageFromFunction( "floatPbufferQuarter", R_CreateStubImage );
578
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" );
583                 GL_CheckErrors();
584         }
585
586         if ( !wglShareLists( floatContext, win32.hGLRC ) ) {
587                 common->Printf( "failed to share lists.\n" );
588         }
589
590         // create a rendering context for this pixel format and share textures
591
592         // allocate a texture for the rendering 
593
594 #endif
595
596         //=================================================================================
597
598         //
599         // allocate the shadow pbuffer
600         //
601         atr_p = iAttributes;
602
603         *atr_p++ = WGL_DRAW_TO_PBUFFER_ARB;
604         *atr_p++ = TRUE;
605         *atr_p++ = WGL_RED_BITS_ARB;
606         *atr_p++ = 8;
607         *atr_p++ = WGL_GREEN_BITS_ARB;
608         *atr_p++ = 8;
609         *atr_p++ = WGL_BLUE_BITS_ARB;
610         *atr_p++ = 8;
611         *atr_p++ = WGL_ALPHA_BITS_ARB;
612         *atr_p++ = 8;
613         *atr_p++ = WGL_DEPTH_BITS_ARB;
614         *atr_p++ = 24;
615         *atr_p++ = WGL_STENCIL_BITS_ARB;
616         *atr_p++ = 8;
617         *atr_p++ = 0;
618         *atr_p++ = 0;
619
620         ret = wglChoosePixelFormatARB( win32.hDC, iAttributes, fAttributes, 
621                 sizeof( pixelformats ) / sizeof( pixelformats[0] ), pixelformats, &numFormats );
622 #if 0
623         for ( int i = 0 ; i < (int)numFormats ; i++ ) {
624                 R_PrintPixelFormat( pixelformats[i] );  
625         }
626 #endif
627         common->Printf( "\nshadowPbuffer:\n" );
628         R_PrintPixelFormat( pixelformats[0] );
629
630 pixelformats[0] = win32.pixelformat;    // forced to do this by wgl...
631
632         //-----------------------------------
633
634         lightBufferSize = maxLightBufferSize;
635
636         // allocate a pbuffer with this pixel format
637         shadowPbuffer = wglCreatePbufferARB( win32.hDC, pixelformats[0], lightBufferSize,
638                 lightBufferSize, pbiAttributes );
639
640         // allocate a rendering context for the pbuffer
641         shadowPbufferDC = wglGetPbufferDCARB( shadowPbuffer );
642
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 );
647
648         //-----------------------------------
649
650         lightBufferSize = maxViewBufferSize;
651
652         // allocate a pbuffer with this pixel format
653         viewPbuffer = wglCreatePbufferARB( win32.hDC, pixelformats[0], maxViewBufferSize,
654                 maxViewBufferSize, pbiAttributes );
655
656         // allocate a rendering context for the pbuffer
657         viewPbufferDC = wglGetPbufferDCARB( viewPbuffer );
658
659         // create the image space depth buffer for image-space shadow trnasforms
660         viewDepthImage = globalImages->ImageFromFunction("_viewDepth", R_CreateShadowBufferImage );
661
662         // create the image space shadow alpha buffer for subsampling the shadow calculation
663         viewAlphaImage = globalImages->ImageFromFunction("_viewAlpha", R_CreateViewAlphaImage );
664
665         //-----------------------------------
666
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 );
671
672         depthMidpointVertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "depthMidpoint.vfp" );
673         depthMidpointFragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "depthMidpoint.vfp" );
674
675         shadowResampleVertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "shadowResample.vfp" );
676         shadowResampleFragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "shadowResample.vfp" );
677
678         screenSpaceShadowVertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "screenSpaceShadow1.vfp" );
679
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" );
684
685         shadowVertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "shadowBufferInteraction1.vfp" );
686
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" );
691
692         gammaDitherVertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "gammaDither.vfp" );
693         gammaDitherFragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "gammaDither.vfp" );
694
695         downSampleVertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "downSample.vfp" );
696         downSampleFragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "downSample.vfp" );
697
698         bloomVertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "bloom.vfp" );
699         bloomFragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "bloom.vfp" );
700
701         random256Image = globalImages->ImageFromFunction( "_random256", R_CreateRandom256Image );
702 }
703
704 //===========================================================================================
705
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
708
709 /*
710 ==================
711 RB_EXP_CullInteractions
712
713 Sets surfaceInteraction_t->cullBits
714 ==================
715 */
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;
719                 if ( !entityDef ) {
720                         continue;
721                 }
722                 if ( inter->numSurfaces < 1 ) {
723                         continue;
724                 }
725
726                 int     culled = 0;
727
728                 if ( r_sb_useCulling.GetBool() ) {
729                         // transform light frustum into object space, positive side points outside the light
730                         idPlane localPlanes[6];
731                         int             plane;
732                         for ( plane = 0 ; plane < 6 ; plane++ ) {
733                                 R_GlobalPlaneToLocal( entityDef->modelMatrix, frustumPlanes[plane], localPlanes[plane] );
734                         }
735
736                         // cull the entire entity bounding box
737                         // has referenceBounds been tightened to the actual model bounds?
738                         idVec3  corners[8];
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];
743                         }
744
745                         for ( plane = 0 ; plane < 6 ; plane++ ) {
746                                 int             j;
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
749                                         // by this plane
750                                         if ( corners[j] * localPlanes[plane].ToVec4().ToVec3() + localPlanes[plane][3] < 0 ) {
751                                                 break;
752                                         }
753                                 }
754                                 if ( j == 8 ) {
755                                         break;                  // all points outside the light
756                                 }
757                         }
758                         if ( plane < 6 ) {
759                                 culled = CULL_OCCLUDER_AND_RECEIVER;
760                         }
761                 }
762
763                 for ( int i = 0 ; i < inter->numSurfaces ; i++ ) {
764                         surfaceInteraction_t    *surfInt = &inter->surfaces[i];
765
766                         if ( !surfInt->ambientTris ) {
767                                 continue;
768                         }
769                         surfInt->expCulled = culled;
770                 }
771
772         }
773 }
774
775 /*
776 ==================
777 RB_EXP_RenderOccluders
778 ==================
779 */
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;
783                 if ( !entityDef ) {
784                         continue;
785                 }
786                 if ( inter->numSurfaces < 1 ) {
787                         continue;
788                 }
789
790                 // no need to check for current on this, because each interaction is always
791                 // a different space
792                 float   matrix[16];
793                 myGlMultMatrix( inter->entityDef->modelMatrix, lightMatrix, matrix );
794                 qglLoadMatrixf( matrix );
795
796                 // draw each surface
797                 for ( int i = 0 ; i < inter->numSurfaces ; i++ ) {
798                         surfaceInteraction_t    *surfInt = &inter->surfaces[i];
799
800                         if ( !surfInt->ambientTris ) {
801                                 continue;
802                         }
803                         if ( surfInt->shader && !surfInt->shader->SurfaceCastsShadow() ) {
804                                 continue;
805                         }
806
807                         // cull it
808                         if ( surfInt->expCulled == CULL_OCCLUDER_AND_RECEIVER ) {
809                                 continue;
810                         }
811
812                         // render it
813                         const srfTriangles_t *tri = surfInt->ambientTris;
814                         if ( !tri->ambientCache ) {
815                                 R_CreateAmbientCache( const_cast<srfTriangles_t *>(tri), false ); 
816                         }
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();
822         }
823                         RB_DrawElementsWithCounters( tri );
824                 }
825         }
826 }
827
828 /*
829 ==================
830 RB_RenderShadowBuffer
831 ==================
832 */
833 void    RB_RenderShadowBuffer( viewLight_t      *vLight, int side ) {
834         float   xmin, xmax, ymin, ymax;
835         float   width, height;
836         float   zNear;
837
838         float   fov = r_sb_frustomFOV.GetFloat();
839
840         //
841         // set up 90 degree projection matrix
842         //
843         zNear   = 4;
844
845         ymax = zNear * tan( fov * idMath::PI / 360.0f );
846         ymin = -ymax;
847
848         xmax = zNear * tan( fov * idMath::PI / 360.0f );
849         xmin = -xmax;
850
851         width = xmax - xmin;
852         height = ymax - ymin;
853
854         lightProjectionMatrix[0] = 2 * zNear / width;
855         lightProjectionMatrix[4] = 0;
856         lightProjectionMatrix[8] = 0;
857         lightProjectionMatrix[12] = 0;
858
859         lightProjectionMatrix[1] = 0;
860         lightProjectionMatrix[5] = 2 * zNear / height;
861         lightProjectionMatrix[9] = 0;
862         lightProjectionMatrix[13] = 0;
863
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;
871
872         lightProjectionMatrix[3] = 0;
873         lightProjectionMatrix[7] = 0;
874         lightProjectionMatrix[11] = -1;
875         lightProjectionMatrix[15] = 0;
876
877
878         if ( r_sb_usePbuffer.GetBool() ) {
879                 // set the current openGL drawable to the shadow buffer
880                 R_MakeCurrent( shadowPbufferDC, win32.hGLRC, NULL /* !@# shadowPbuffer */ );
881         }
882
883         qglMatrixMode( GL_PROJECTION );
884         qglLoadMatrixf( lightProjectionMatrix );
885         qglMatrixMode( GL_MODELVIEW );
886
887         qglViewport( 0, 0, lightBufferSize, lightBufferSize );
888         qglScissor( 0, 0, lightBufferSize, lightBufferSize );
889         qglStencilFunc( GL_ALWAYS, 0, 255 );
890
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 );
894
895 // draw all the occluders
896 qglColor3f( 1, 1, 1 );
897 GL_SelectTexture( 0 );
898 qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
899
900         backEnd.currentSpace = NULL;
901
902         static float    s_flipMatrix[16] = {
903                 // convert from our coordinate system (looking down X)
904                 // to OpenGL's coordinate system (looking down -Z)
905                 0, 0, -1, 0,
906                 -1, 0, 0, 0,
907                 0, 1, 0, 0,
908                 0, 0, 0, 1
909         };
910
911         float   viewMatrix[16];
912
913         idVec3  vec;
914         idVec3  origin = vLight->lightDef->globalLightOrigin;
915
916         if ( side == -1 ) {
917                 // projected light
918                 vec = vLight->lightDef->parms.target;
919                 vec.Normalize();
920                 viewMatrix[0] = vec[0];
921                 viewMatrix[4] = vec[1];
922                 viewMatrix[8] = vec[2];
923
924                 vec = vLight->lightDef->parms.right;
925                 vec.Normalize();
926                 viewMatrix[1] = -vec[0];
927                 viewMatrix[5] = -vec[1];
928                 viewMatrix[9] = -vec[2];
929
930                 vec = vLight->lightDef->parms.up;
931                 vec.Normalize();
932                 viewMatrix[2] = vec[0];
933                 viewMatrix[6] = vec[1];
934                 viewMatrix[10] = vec[2];
935         } else {
936                 // side of a point light
937                 memset( viewMatrix, 0, sizeof( viewMatrix ) );
938                 switch ( side ) {
939                 case 0:
940                         viewMatrix[0] = 1;
941                         viewMatrix[9] = 1;
942                         viewMatrix[6] = -1;
943                         break;
944                 case 1:
945                         viewMatrix[0] = -1;
946                         viewMatrix[9] = -1;
947                         viewMatrix[6] = -1;
948                         break;
949                 case 2:
950                         viewMatrix[4] = 1;
951                         viewMatrix[1] = -1;
952                         viewMatrix[10] = 1;
953                         break;
954                 case 3:
955                         viewMatrix[4] = -1;
956                         viewMatrix[1] = -1;
957                         viewMatrix[10] = -1;
958                         break;
959                 case 4:
960                         viewMatrix[8] = 1;
961                         viewMatrix[1] = -1;
962                         viewMatrix[6] = -1;
963                         break;
964                 case 5:
965                         viewMatrix[8] = -1;
966                         viewMatrix[1] = 1;
967                         viewMatrix[6] = -1;
968                         break;
969                 }
970         }
971
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];
975
976         viewMatrix[3] = 0;
977         viewMatrix[7] = 0;
978         viewMatrix[11] = 0;
979         viewMatrix[15] = 1;
980
981         memcpy( unflippedLightMatrix, viewMatrix, sizeof( unflippedLightMatrix ) );
982         myGlMultMatrix( viewMatrix, s_flipMatrix,lightMatrix);
983
984         // create frustum planes
985         idPlane globalFrustum[6];
986
987         // near clip
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]);
992
993         // far clip
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;
998
999         // side clips
1000         globalFrustum[2][0] = -viewMatrix[0] + viewMatrix[1];
1001         globalFrustum[2][1] = -viewMatrix[4] + viewMatrix[5];
1002         globalFrustum[2][2] = -viewMatrix[8] + viewMatrix[9];
1003
1004         globalFrustum[3][0] = -viewMatrix[0] - viewMatrix[1];
1005         globalFrustum[3][1] = -viewMatrix[4] - viewMatrix[5];
1006         globalFrustum[3][2] = -viewMatrix[8] - viewMatrix[9];
1007
1008         globalFrustum[4][0] = -viewMatrix[0] + viewMatrix[2];
1009         globalFrustum[4][1] = -viewMatrix[4] + viewMatrix[6];
1010         globalFrustum[4][2] = -viewMatrix[8] + viewMatrix[10];
1011
1012         globalFrustum[5][0] = -viewMatrix[0] - viewMatrix[2];
1013         globalFrustum[5][1] = -viewMatrix[4] - viewMatrix[6];
1014         globalFrustum[5][2] = -viewMatrix[8] - viewMatrix[10];
1015
1016         // is this nromalization necessary?
1017         for ( int i = 0 ; i < 6 ; i++ ) {
1018                 globalFrustum[i].ToVec4().ToVec3().Normalize();
1019         }
1020
1021         for ( int i = 2 ; i < 6 ; i++ ) {
1022                 globalFrustum[i][3] = - (origin * globalFrustum[i].ToVec4().ToVec3() );
1023         }
1024
1025         RB_EXP_CullInteractions( vLight, globalFrustum );
1026
1027
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() ) {
1030                 //
1031                 // set polygon offset for the rendering
1032                 //
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 );
1039                         break;
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 );
1047                         break;
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 );
1054
1055                         RB_EXP_RenderOccluders( vLight );
1056                         shadowImage[1]->Bind();
1057                         qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, lightBufferSize, lightBufferSize );
1058
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);
1064
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 );
1070
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 );
1076
1077                         // draw a full screen quad
1078                         qglMatrixMode( GL_PROJECTION );
1079                         qglLoadIdentity(); 
1080                         qglOrtho( 0, 1, 0, 1, -1, 1 );
1081                         qglMatrixMode( GL_MODELVIEW );
1082                         qglLoadIdentity();
1083
1084                         GL_State( GLS_DEPTHFUNC_ALWAYS );
1085
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 );
1095                         qglEnd();
1096
1097                         qglDisable( GL_VERTEX_PROGRAM_ARB );
1098                         qglDisable( GL_FRAGMENT_PROGRAM_ARB );
1099
1100                         break;
1101                 }
1102         }
1103
1104         // copy to the texture
1105         shadowImage[0]->Bind();
1106         qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, lightBufferSize, lightBufferSize );
1107
1108 qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
1109
1110
1111         // reset the normal view matrix
1112
1113         qglMatrixMode( GL_PROJECTION );
1114         qglLoadMatrixf( backEnd.viewDef->projectionMatrix );
1115         qglMatrixMode( GL_MODELVIEW );
1116
1117         // the current modelView matrix is not valid
1118         backEnd.currentSpace = NULL;
1119 }
1120
1121 /*
1122 ==================
1123 RB_EXP_DrawInteraction
1124 ==================
1125 */
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() );
1140
1141
1142 // calculate depth projection for shadow buffer
1143 float   sRow[4];
1144 float   tRow[4];
1145 float   rRow[4];
1146 float   qRow[4];
1147 float   matrix[16];
1148 float   matrix2[16];
1149 myGlMultMatrix( din->surf->space->modelMatrix, lightMatrix, matrix );
1150 myGlMultMatrix( matrix, lightProjectionMatrix, matrix2 );
1151
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 );
1173
1174
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() );
1179         }
1180
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 };
1184
1185         switch ( din->vertexColor ) {
1186         case SVC_IGNORE:
1187                 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_MODULATE, zero );
1188                 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_ADD, one );
1189                 break;
1190         case SVC_MODULATE:
1191                 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_MODULATE, one );
1192                 qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_ADD, zero );
1193                 break;
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 );
1197                 break;
1198         }
1199
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() );
1203
1204         //-----------------------------------------------------
1205         // screen power of two correction factor
1206
1207         float   parm[4];
1208         parm[0] = 1.0 / ( JITTER_SIZE * r_sb_samples.GetInteger() ) ;
1209         parm[1] = 1.0 / JITTER_SIZE;
1210         parm[2] = 0;
1211         parm[3] = 1;
1212         qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 2, parm );
1213
1214         // jitter tex scale
1215         parm[0] = 
1216         parm[1] = r_sb_jitterScale.GetFloat() * lightBufferSizeFraction;
1217         parm[2] = -r_sb_biasScale.GetFloat();
1218         parm[3] = 0;
1219         qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 3, parm );
1220
1221         // jitter tex offset
1222         if ( r_sb_randomize.GetBool() ) {
1223                 parm[0] = (rand()&255) / 255.0;
1224                 parm[1] = (rand()&255) / 255.0;
1225         } else {
1226                 parm[0] = parm[1] = 0;
1227         }
1228         parm[2] = 0;
1229         parm[3] = 0;
1230         qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 4, parm );
1231         //-----------------------------------------------------
1232
1233         // set the textures
1234
1235         // texture 1 will be the per-surface bump map
1236         GL_SelectTextureNoClient( 1 );
1237         din->bumpImage->Bind();
1238
1239         // texture 2 will be the light falloff texture
1240         GL_SelectTextureNoClient( 2 );
1241         din->lightFalloffImage->Bind();
1242
1243         // texture 3 will be the light projection texture
1244         GL_SelectTextureNoClient( 3 );
1245         din->lightImage->Bind();
1246
1247         // texture 4 is the per-surface diffuse map
1248         GL_SelectTextureNoClient( 4 );
1249         din->diffuseImage->Bind();
1250
1251         // texture 5 is the per-surface specular map
1252         GL_SelectTextureNoClient( 5 );
1253         din->specularImage->Bind();
1254
1255         // draw it
1256         RB_DrawElementsWithCounters( din->surf->geo );
1257 }
1258
1259 /*
1260 =============
1261 RB_EXP_CreateDrawInteractions
1262
1263 =============
1264 */
1265 void RB_EXP_CreateDrawInteractions( const drawSurf_t *surf ) {
1266         if ( !surf ) {
1267                 return;
1268         }
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 );
1272
1273                 if ( r_testARBProgram.GetBool() ) {
1274                         qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_TEST );
1275                         qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_TEST );
1276                 } else {
1277                         qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_INTERACTION );
1278                         qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_INTERACTION );
1279                 }
1280         } else {
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 );//!@#
1284
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 );
1293                 } else {
1294                         qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, shadowFragmentProgram0 );
1295                 }
1296         }
1297
1298         qglEnable(GL_VERTEX_PROGRAM_ARB);
1299         qglEnable(GL_FRAGMENT_PROGRAM_ARB);
1300
1301         // enable the vertex arrays
1302         qglEnableVertexAttribArrayARB( 8 );
1303         qglEnableVertexAttribArrayARB( 9 );
1304         qglEnableVertexAttribArrayARB( 10 );
1305         qglEnableVertexAttribArrayARB( 11 );
1306         qglEnableClientState( GL_COLOR_ARRAY );
1307
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);
1314         } else {
1315                 globalImages->normalCubeMapImage->Bind();
1316         }
1317
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
1322         } else {
1323                 globalImages->specularTableImage->Bind();
1324         }
1325
1326
1327         for ( ; surf ; surf=surf->nextOnLight ) {
1328                 // perform setup here that will not change over multiple interaction passes
1329                 if ( backEnd.vLight->lightShader->IsAmbientLight() ) {
1330                         float   parm[4];
1331
1332                         parm[0] = surf->space->modelMatrix[0];
1333                         parm[1] = surf->space->modelMatrix[4];
1334                         parm[2] = surf->space->modelMatrix[8];
1335                         parm[3] = 0;
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];
1340                         parm[3] = 0;
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];
1345                         parm[3] = 0;
1346                         qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 22, parm );
1347
1348                         GL_SelectTextureNoClient( 0 );
1349                         const shaderStage_t *stage = backEnd.vLight->lightShader->GetStage( 0 );
1350                         if ( stage->newStage ) {
1351                                 stage->newStage->fragmentProgramImages[7]->BindFragment();
1352                         }
1353                 }
1354
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() );
1363
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 );
1368                 } else {
1369                         RB_CreateSingleDrawInteractions( surf, RB_EXP_DrawInteraction );
1370                 }
1371         }
1372
1373         qglDisableVertexAttribArrayARB( 8 );
1374         qglDisableVertexAttribArrayARB( 9 );
1375         qglDisableVertexAttribArrayARB( 10 );
1376         qglDisableVertexAttribArrayARB( 11 );
1377         qglDisableClientState( GL_COLOR_ARRAY );
1378
1379         // disable features
1380         GL_SelectTextureNoClient( 6 );
1381         globalImages->BindNull();
1382
1383         GL_SelectTextureNoClient( 5 );
1384         globalImages->BindNull();
1385
1386         GL_SelectTextureNoClient( 4 );
1387         globalImages->BindNull();
1388
1389         GL_SelectTextureNoClient( 3 );
1390         globalImages->BindNull();
1391
1392         GL_SelectTextureNoClient( 2 );
1393         globalImages->BindNull();
1394
1395         GL_SelectTextureNoClient( 1 );
1396         globalImages->BindNull();
1397
1398         backEnd.glState.currenttmu = -1;
1399         GL_SelectTexture( 0 );
1400
1401         qglDisable(GL_VERTEX_PROGRAM_ARB);
1402         qglDisable(GL_FRAGMENT_PROGRAM_ARB);
1403 }
1404
1405 void InvertByTranspose( const float a[16], float r[16] ) {
1406     r[ 0] = a[ 0];
1407     r[ 1] = a[ 4];
1408     r[ 2] = a[ 8];
1409         r[ 3] = 0;
1410     r[ 4] = a[ 1];
1411     r[ 5] = a[ 5];
1412     r[ 6] = a[ 9];
1413         r[ 7] = 0;
1414     r[ 8] = a[ 2];
1415     r[ 9] = a[ 6];
1416     r[10] = a[10];
1417         r[11] = 0;
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]);
1421         r[15] = 1;
1422 }
1423
1424 void FullInvert( const float a[16], float r[16] ) {
1425         idMat4  am;
1426
1427         for ( int i = 0 ; i < 4 ; i++ ) {
1428                 for ( int j = 0 ; j < 4 ; j++ ) {
1429                         am[i][j] = a[j*4+i];
1430                 }
1431         }
1432
1433 //      idVec4 test( 100, 100, 100, 1 );
1434 //      idVec4  transformed, inverted;
1435 //      transformed = test * am;
1436
1437         if ( !am.InverseSelf() ) {
1438                 common->Error( "Invert failed" );
1439         }
1440 //      inverted = transformed * am;
1441
1442         for ( int i = 0 ; i < 4 ; i++ ) {
1443                 for ( int j = 0 ; j < 4 ; j++ ) {
1444                         r[j*4+i] = am[i][j];
1445                 }
1446         }
1447 }
1448
1449 /*
1450 ==================
1451 RB_Exp_TrianglesForFrustum
1452 ==================
1453 */
1454 const srfTriangles_t    *RB_Exp_TrianglesForFrustum( viewLight_t *vLight, int side ) {
1455         const srfTriangles_t *tri;
1456
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 };
1460
1461         if ( side == -1 ) {
1462                 tri = vLight->frustumTris;
1463         } else {
1464                 memset( verts, 0, sizeof( verts ) );
1465
1466                 for ( int i = 0 ; i < 5 ; i++ ) {
1467                         verts[i].xyz = vLight->globalLightOrigin;
1468                 }
1469
1470                 memset( &frustumTri, 0, sizeof( frustumTri ) );
1471                 frustumTri.indexes = indexes;
1472                 frustumTri.verts = verts;
1473                 frustumTri.numIndexes = 18;
1474                 frustumTri.numVerts = 5;
1475
1476                 tri = &frustumTri;
1477
1478                 float   size = viewLightAxialSize;
1479
1480                 switch ( side ) {
1481                 case 0:
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;
1494                         break;
1495                 case 1:
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;
1508                         break;
1509                 case 2:
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;
1522                         break;
1523                 case 3:
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;
1536                         break;
1537                 case 4:
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;
1550                         break;
1551                 case 5:
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;
1564                         break;
1565                 }
1566
1567                 frustumTri.ambientCache = vertexCache.AllocFrameTemp( verts, sizeof( verts ) );
1568         }
1569
1570         return tri;
1571 }
1572
1573
1574 /*
1575 ==================
1576 RB_Exp_SelectFrustum
1577 ==================
1578 */
1579 void    RB_Exp_SelectFrustum( viewLight_t *vLight, int side ) {
1580         qglLoadMatrixf( backEnd.viewDef->worldSpace.modelViewMatrix );
1581
1582         const srfTriangles_t *tri = RB_Exp_TrianglesForFrustum( vLight, side );
1583
1584         idDrawVert *ac = (idDrawVert *)vertexCache.Position( tri->ambientCache );
1585         qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() );
1586
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 );
1594
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 );
1601
1602         RB_DrawElementsWithCounters( tri );
1603         
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
1609
1610         // this pass does all the shadow filtering
1611         qglStencilFunc( GL_EQUAL, 1, 255 );
1612         qglStencilOp( GL_KEEP, GL_KEEP, GL_ZERO );
1613
1614         GL_Cull( CT_BACK_SIDED );
1615         qglDepthFunc( GL_GREATER );
1616
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 );
1622         } else {
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() ) {
1628                 case 0:
1629                         qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, screenSpaceShadowFragmentProgram0 );
1630                         break;
1631                 case 1:
1632                         qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, screenSpaceShadowFragmentProgram1 );
1633                         break;
1634                 case 4:
1635                         qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, screenSpaceShadowFragmentProgram4 );
1636                         break;
1637                 case 16:
1638                         qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, screenSpaceShadowFragmentProgram16 );
1639                         break;
1640                 }
1641         }
1642
1643 /*
1644 texture[0] = view depth texture
1645 texture[1] = jitter texture
1646 texture[2] = light depth texture
1647 */
1648         GL_SelectTextureNoClient( 2 );
1649         shadowImage[0]->Bind();
1650
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();
1656         } else {
1657                 jitterImage1->Bind();
1658         }
1659
1660         GL_SelectTextureNoClient( 0 );
1661         viewDepthImage->Bind();
1662
1663         /*
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];
1674 */
1675         float   parm[4];
1676         int             pot;
1677
1678         // calculate depth projection for shadow buffer
1679         float   sRow[4];
1680         float   tRow[4];
1681         float   rRow[4];
1682         float   qRow[4];
1683         float   invertedView[16];
1684         float   invertedProjection[16];
1685         float   matrix[16];
1686         float   matrix2[16];
1687
1688         // we need the inverse of the projection matrix to go from NDC to view
1689         FullInvert( backEnd.viewDef->projectionMatrix, invertedProjection );
1690
1691         /*
1692         from window to NDC:
1693                 ( x - xMid ) * 1.0 / xMid
1694                 ( y - yMid ) * 1.0 / yMid
1695                 ( z - 0.5 ) * 2
1696
1697         from NDC to clip coordinates:
1698                 rcp(1/w)
1699
1700         */
1701
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 );
1704
1705         // then we go from world to light view space (looking down negative Z)
1706         myGlMultMatrix( invertedView, lightMatrix, matrix );
1707
1708         // then to light projection, giving X/w, Y/w, Z/w in the -1 : 1 range
1709         myGlMultMatrix( matrix, lightProjectionMatrix, matrix2 );
1710
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 );
1732
1733         //-----------------------------------------------------
1734         // these should be constant for the entire frame
1735
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;
1743         parm[2] = 0;
1744         parm[3] = 1;
1745         qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 0, parm );
1746
1747         // zProject values
1748         parm[0] = backEnd.viewDef->projectionMatrix[10];
1749         parm[1] = backEnd.viewDef->projectionMatrix[14];
1750         parm[2] = 0;
1751         parm[3] = 0;
1752         qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 1, parm );
1753
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 );
1760
1761         // positionToJitterTexScale
1762         parm[0] = 1.0 / ( JITTER_SIZE * r_sb_samples.GetInteger() ) ;
1763         parm[1] = 1.0 / JITTER_SIZE;
1764         parm[2] = 0;
1765         parm[3] = 1;
1766         qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 7, parm );
1767
1768         // jitter tex scale
1769         parm[0] = 
1770         parm[1] = r_sb_jitterScale.GetFloat() * lightBufferSizeFraction;
1771         parm[2] = -r_sb_biasScale.GetFloat();
1772         parm[3] = 0;
1773         qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 8, parm );
1774
1775         // jitter tex offset
1776         if ( r_sb_randomize.GetBool() ) {
1777                 parm[0] = (rand()&255) / 255.0;
1778                 parm[1] = (rand()&255) / 255.0;
1779         } else {
1780                 parm[0] = parm[1] = 0;
1781         }
1782         parm[2] = 0;
1783         parm[3] = 0;
1784         qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 9, parm );
1785         //-----------------------------------------------------
1786
1787
1788
1789         RB_DrawElementsWithCounters( tri );
1790
1791         qglDisable(GL_VERTEX_PROGRAM_ARB);
1792         qglDisable(GL_FRAGMENT_PROGRAM_ARB);
1793
1794         GL_Cull( CT_FRONT_SIDED );
1795 //      qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
1796
1797         qglDepthFunc( GL_LEQUAL );
1798         if ( r_sb_showFrustumPixels.GetBool() ) {
1799                 qglEnable( GL_TEXTURE_2D );
1800                 qglColor3f( 1, 1, 1 );
1801         }
1802
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 );
1807
1808         // we can avoid clearing the stencil buffer by changing the hasLight value for each light
1809 }
1810
1811 /*
1812 ==================
1813 R_EXP_CalcLightAxialSize
1814
1815 all light side projections must currently match, so non-centered
1816 and non-cubic lights must take the largest length
1817 ==================
1818 */
1819 float   R_EXP_CalcLightAxialSize( viewLight_t *vLight ) {
1820         float   max = 0;
1821
1822         if ( !vLight->lightDef->parms.pointLight ) {
1823                 idVec3  dir = vLight->lightDef->parms.target - vLight->lightDef->parms.origin;
1824                 max = dir.Length();
1825                 return max;
1826         }
1827
1828         for ( int i = 0 ; i < 3 ; i++ ) {
1829                 float   dist = fabs(vLight->lightDef->parms.lightCenter[i] );
1830                 dist += vLight->lightDef->parms.lightRadius[i];
1831                 if ( dist > max ) {
1832                         max = dist;
1833                 }
1834         }
1835         return max;
1836 }
1837
1838 /*
1839 ==================
1840 R_EXP_RenderViewDepthImage
1841
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
1844 ==================
1845 */
1846 void RB_T_FillDepthBuffer( const drawSurf_t *surf );
1847
1848 void R_EXP_RenderViewDepthImage( void ) {
1849         if ( !r_sb_screenSpaceShadow.GetBool() ) {
1850                 return;
1851         }
1852
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 );
1859         } else {
1860                 RB_LogComment( "---------- R_EXP_RenderViewDepthImage ----------\n" );
1861
1862                 if ( r_sb_usePbuffer.GetBool() ) {
1863                         GL_CheckErrors();
1864                         // set the current openGL drawable to the shadow buffer
1865                         R_MakeCurrent( viewPbufferDC, win32.hGLRC, NULL /* !@# viewPbuffer */ );
1866                 }
1867
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 );
1873
1874                 // the first texture will be used for alpha tested surfaces
1875                 GL_SelectTexture( 0 );
1876                 qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
1877
1878                 GL_State( GLS_DEPTHFUNC_LESS );
1879
1880                 RB_RenderDrawSurfListWithFunction( backEnd.viewDef->drawSurfs, backEnd.viewDef->numDrawSurfs, RB_T_FillDepthBuffer );
1881
1882                 //
1883                 // copy it to a texture
1884                 //
1885                 viewDepthImage->Bind();
1886                 qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, viewBufferSize, viewBufferHeight );
1887
1888                 if ( r_sb_usePbuffer.GetBool() ) {
1889                         // set the normal screen drawable current
1890                         R_MakeCurrent( win32.hDC, win32.hGLRC, NULL );
1891                 }
1892
1893                 // reset the window clipping
1894                 qglMatrixMode( GL_PROJECTION );
1895                 qglLoadMatrixf( backEnd.viewDef->projectionMatrix );
1896                 qglMatrixMode( GL_MODELVIEW );
1897
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 );
1906
1907                 // the current modelView matrix is not valid
1908                 backEnd.currentSpace = NULL;
1909         }
1910
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 );
1915 }
1916
1917 /*
1918 ==================
1919 RB_EXP_SetNativeBuffer
1920
1921 This is always the back buffer, and scissor is set full screen
1922 ==================
1923 */
1924 void RB_EXP_SetNativeBuffer( void ) {
1925         // set the normal screen drawable current
1926         R_MakeCurrent( win32.hDC, win32.hGLRC, NULL );
1927
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 );
1932
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 );
1939         }
1940 }
1941
1942 /*
1943 ==================
1944 RB_EXP_SetRenderBuffer
1945
1946 This may be to a float pBuffer, and scissor is set to cover only the light
1947 ==================
1948 */
1949 void RB_EXP_SetRenderBuffer( viewLight_t *vLight ) {
1950         if ( r_hdr_useFloats.GetBool() ) {
1951                 R_MakeCurrent( floatPbufferDC, floatContext, floatPbuffer );
1952         } else {
1953                 if ( !qwglMakeCurrent( win32.hDC, win32.hGLRC ) ) {
1954                         GL_CheckErrors();
1955                         common->FatalError( "Couldn't return to normal drawing context" );
1956                 }
1957         }
1958
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 );
1963
1964         if ( !vLight ) {
1965                 backEnd.currentScissor = backEnd.viewDef->viewport;
1966         } else {
1967                 backEnd.currentScissor = vLight->scissorRect;
1968         }
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 );
1974         }
1975 }
1976
1977 /*
1978 ==================
1979 RB_shadowResampleAlpha
1980
1981 ==================
1982 */
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 );
1987
1988         RB_EXP_SetRenderBuffer( backEnd.vLight );
1989
1990 //=====================
1991
1992         qglLoadMatrixf( backEnd.viewDef->worldSpace.modelViewMatrix );
1993
1994         // this uses the full light, not side frustums
1995         const srfTriangles_t *tri = backEnd.vLight->frustumTris;
1996
1997         idDrawVert *ac = (idDrawVert *)vertexCache.Position( tri->ambientCache );
1998         qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() );
1999
2000         // clear stencil buffer
2001         qglEnable( GL_SCISSOR_TEST );
2002         qglEnable( GL_STENCIL_TEST );
2003         qglClearStencil( 1 );
2004         qglClear( GL_STENCIL_BUFFER_BIT );
2005
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 );
2012
2013         // set fragment / vertex program?
2014
2015         RB_DrawElementsWithCounters( tri );
2016         
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
2022
2023         // this pass does all the shadow filtering
2024         qglStencilFunc( GL_EQUAL, 1, 255 );
2025         qglStencilOp( GL_KEEP, GL_KEEP, GL_ZERO );
2026
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 );
2032         } else {
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 );
2038
2039                 // convert 0..viewport-1 sizes to fractions inside the POT screen depth texture
2040                 // shrink by one unit for bilerp
2041                 float   parm[4];
2042                 parm[0] = 1.0 / (maxViewBufferSize+1) * viewBufferSize / maxViewBufferSize;
2043                 parm[1] = parm[0];
2044                 parm[2] = 0;
2045                 parm[3] = 1;
2046                 qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 0, parm );
2047         }
2048
2049         GL_Cull( CT_BACK_SIDED );
2050         qglDepthFunc( GL_GREATER );
2051
2052         RB_DrawElementsWithCounters( tri );
2053
2054         qglDisable(GL_VERTEX_PROGRAM_ARB);
2055         qglDisable(GL_FRAGMENT_PROGRAM_ARB);
2056
2057         GL_Cull( CT_FRONT_SIDED );
2058
2059         qglDepthFunc( GL_LEQUAL );
2060         if ( r_sb_showFrustumPixels.GetBool() ) {
2061                 qglEnable( GL_TEXTURE_2D );
2062                 qglColor3f( 1, 1, 1 );
2063         }
2064
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 );
2069 }
2070
2071
2072 /*
2073 ==================
2074 RB_EXP_CoverScreen
2075 ==================
2076 */
2077 void RB_EXP_CoverScreen( void ) {
2078         // draw a full screen quad
2079         qglMatrixMode( GL_PROJECTION );
2080         qglLoadIdentity(); 
2081         qglOrtho( 0, 1, 0, 1, -1, 1 );
2082         qglMatrixMode( GL_MODELVIEW );
2083         qglLoadIdentity();
2084
2085         qglBegin( GL_TRIANGLE_FAN );
2086         qglVertex2f( 0, 0 );
2087         qglVertex2f( 0, 1 );
2088         qglVertex2f( 1, 1 );
2089         qglVertex2f( 1, 0 );
2090         qglEnd();
2091 }
2092
2093 /*
2094 ==================
2095 RB_EXP_ReadFloatBuffer
2096 ==================
2097 */
2098 void RB_EXP_ReadFloatBuffer( void ) {
2099         int             pixels = glConfig.vidWidth * glConfig.vidHeight;
2100         float   *buf = (float *)R_StaticAlloc( pixels * 4 * sizeof( float ) );
2101
2102         qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_RGBA, GL_FLOAT, buf );
2103
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] ) {
2110                                 mins[j] = v;
2111                         }
2112                         if ( v > maxs[j] ) {
2113                                 maxs[j] = v;
2114                         }
2115                 }
2116         }
2117
2118         RB_EXP_SetNativeBuffer();
2119
2120         qglLoadIdentity();
2121         qglMatrixMode( GL_PROJECTION );
2122         GL_State( GLS_DEPTHFUNC_ALWAYS );
2123         qglColor3f( 1, 1, 1 );
2124         qglPushMatrix();
2125         qglLoadIdentity(); 
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 );
2130         qglPopMatrix();
2131         qglEnable( GL_TEXTURE_2D );
2132         qglMatrixMode( GL_MODELVIEW );
2133
2134         R_StaticFree( buf );
2135 }
2136
2137
2138 void RB_TestGamma( void );
2139
2140 /*
2141 ==================
2142 RB_EXP_GammaDither
2143 ==================
2144 */
2145 void    RB_EXP_GammaDither( void ) {
2146         if ( !r_hdr_useFloats.GetBool() ) {
2147                 return;
2148         }
2149
2150 #if 0
2151 r_testGamma.SetBool( true );
2152 RB_TestGamma();
2153 r_testGamma.SetBool( false );
2154 #endif
2155
2156         RB_EXP_SetNativeBuffer();
2157
2158         /*
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
2162
2163 # writes result.color as the 32 bit dithered and gamma corrected values
2164
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];
2171
2172         */
2173
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);
2178
2179         qglActiveTextureARB( GL_TEXTURE2_ARB );
2180         qglBindTexture( GL_TEXTURE_RECTANGLE_NV, floatPbufferQuarterImage->texnum );
2181         R_BindTexImage( floatPbufferQuarter );
2182
2183         qglActiveTextureARB( GL_TEXTURE1_ARB );
2184         random256Image->BindFragment();
2185
2186         qglActiveTextureARB( GL_TEXTURE0_ARB );
2187         qglBindTexture( GL_TEXTURE_RECTANGLE_NV, floatPbufferImage->texnum );
2188         R_BindTexImage( floatPbuffer );
2189
2190         float   parm[4];
2191
2192         parm[0] = r_hdr_exposure.GetFloat();
2193         parm[1] = 0;
2194         parm[2] = 0;
2195         parm[3] = 0;
2196         qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 0, parm );
2197
2198         parm[0] = r_hdr_gamma.GetFloat();
2199         parm[1] = 0;
2200         parm[2] = 0;
2201         parm[3] = 0;
2202         qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 1, parm );
2203
2204         parm[0] = r_hdr_monitorDither.GetFloat();
2205         parm[1] = 0;
2206         parm[2] = 0;
2207         parm[3] = 0;
2208         qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 2, parm );
2209
2210         parm[0] = 1.0 / 256;
2211         parm[1] = parm[0];
2212         parm[2] = rand()/65535.0;
2213         parm[3] = rand()/65535.0;
2214         qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 3, parm );
2215
2216         parm[0] = 1.0 - r_hdr_bloomFraction.GetFloat();
2217         parm[1] = r_hdr_bloomFraction.GetFloat();
2218         parm[2] = 0;
2219         parm[3] = 0;
2220         qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 4, parm );
2221
2222         parm[0] = 0.25;
2223         parm[1] = 0.25;
2224         parm[2] = 0;
2225         parm[3] = 0;
2226         qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 5, parm );
2227
2228         qglDisable( GL_STENCIL_TEST );
2229         qglDisable( GL_SCISSOR_TEST );
2230         qglDisable( GL_DEPTH_TEST );
2231
2232         RB_EXP_CoverScreen();
2233
2234         qglEnable( GL_DEPTH_TEST );
2235
2236         qglDisable(GL_VERTEX_PROGRAM_ARB);
2237         qglDisable(GL_FRAGMENT_PROGRAM_ARB);
2238 }
2239
2240 /*
2241 ==================
2242 RB_EXP_Bloom
2243 ==================
2244 */
2245 void    RB_EXP_Bloom( void ) {
2246         if ( !r_hdr_useFloats.GetBool() ) {
2247                 return;
2248         }
2249
2250         if ( r_hdr_bloomFraction.GetFloat() == 0 ) {
2251                 return;
2252         }
2253
2254         GL_CheckErrors();
2255
2256         //
2257         // mip map
2258         //
2259
2260         // draw to the second floatPbuffer
2261         R_MakeCurrent( floatPbuffer2DC, floatContext, floatPbuffer2 );
2262
2263         GL_State( 0 );
2264         qglDisable( GL_DEPTH_TEST );
2265         qglDisable( GL_SCISSOR_TEST );
2266
2267         qglEnable(GL_VERTEX_PROGRAM_ARB);
2268         qglEnable(GL_FRAGMENT_PROGRAM_ARB);
2269
2270         qglClearColor( 1.0, 0.5, 0, 0 );
2271         qglClear( GL_COLOR_BUFFER_BIT );
2272         qglViewport( 0, 0, glConfig.vidWidth>>1, glConfig.vidHeight>>1 );
2273
2274         // read from the original floatPbuffer
2275         qglActiveTextureARB( GL_TEXTURE0_ARB );
2276         qglBindTexture( GL_TEXTURE_RECTANGLE_NV, floatPbufferImage->texnum );
2277         R_BindTexImage( floatPbuffer );
2278
2279         qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, downSampleVertexProgram );
2280         qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, downSampleFragmentProgram );
2281
2282         RB_EXP_CoverScreen();
2283
2284         //
2285         // mip map again
2286         //
2287         qglViewport( 0, 0, glConfig.vidWidth>>2, glConfig.vidHeight>>2 );
2288
2289         // draw to the second floatPbuffer
2290         R_MakeCurrent( floatPbufferQuarterDC, floatContext, floatPbufferQuarter );
2291
2292         // read from the original floatPbuffer
2293         qglBindTexture( GL_TEXTURE_RECTANGLE_NV, floatPbuffer2Image->texnum );
2294         R_BindTexImage( floatPbuffer2 );
2295
2296         RB_EXP_CoverScreen();
2297
2298         //
2299         // blur horizontally
2300         //
2301         /*
2302 # texture 0 is the high dynamic range buffer
2303 # writes result.color as the fp16 result of a smeared bloom
2304
2305 PARAM   step =          program.local[0];               # { 1, 0 } or { 0, 1 } for horizontal / vertical separation
2306         */
2307
2308         // draw to the second floatPbuffer
2309         R_MakeCurrent( floatPbuffer2DC, floatContext, floatPbuffer2 );
2310
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);
2315
2316         GL_SelectTextureNoClient( 0 );
2317
2318         // blur horizontally first to the second floatPbuffer
2319         qglBindTexture( GL_TEXTURE_RECTANGLE_NV, floatPbufferQuarterImage->texnum );
2320         R_BindTexImage( floatPbufferQuarter );
2321
2322         float   parm[4];
2323
2324         parm[0] = 1;
2325         parm[1] = 0;
2326         parm[2] = 0;
2327         parm[3] = 0;
2328         qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 0, parm );
2329
2330         RB_EXP_CoverScreen();
2331
2332         //
2333         // now blur vertically back to the quarter pbuffer
2334         //
2335         R_MakeCurrent( floatPbufferQuarterDC, floatContext, floatPbufferQuarter );
2336
2337         qglBindTexture( GL_TEXTURE_RECTANGLE_NV, floatPbuffer2Image->texnum );
2338         R_BindTexImage( floatPbuffer2 );
2339
2340         parm[0] = 0;
2341         parm[1] = 1;
2342         parm[2] = 0;
2343         parm[3] = 0;
2344         qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 0, parm );
2345
2346         RB_EXP_CoverScreen();
2347
2348         //========================
2349
2350         qglEnable( GL_DEPTH_TEST );
2351         qglEnable( GL_SCISSOR_TEST );
2352
2353         qglDisable(GL_VERTEX_PROGRAM_ARB);
2354         qglDisable(GL_FRAGMENT_PROGRAM_ARB);
2355
2356         GL_CheckErrors();
2357 }
2358
2359 /*
2360 ==================
2361 RB_Exp_DrawInteractions
2362 ==================
2363 */
2364 void    RB_Exp_DrawInteractions( void ) {
2365         if ( !initialized ) {
2366                 R_Exp_Allocate();
2367         }
2368
2369         if ( !backEnd.viewDef->viewLights ) {
2370                 return;
2371         }
2372
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 );
2376         }
2377
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 );
2383         }
2384         lightBufferSize = r_sb_lightResolution.GetInteger();
2385         lightBufferSizeFraction = (float)lightBufferSize / maxLightBufferSize;
2386
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 );
2392         }
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;
2399         } else {
2400                 nativeViewBuffer = false;
2401         }
2402         
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 );
2408         } else {
2409                 qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
2410                 qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
2411         }
2412         qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE );
2413
2414         globalImages->BindNull();
2415
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();
2419
2420         GL_SelectTexture( 0 );
2421         qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
2422
2423         // disable stencil shadow test
2424         qglStencilFunc( GL_ALWAYS, 128, 255 );
2425
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();
2432         } else {
2433                 jitterImage1->BindFragment();
2434         }
2435
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 );
2446         }
2447
2448
2449         //
2450         // for each light, perform adding and shadowing
2451         //
2452         for ( viewLight_t *vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) {
2453                 backEnd.vLight = vLight;
2454
2455                 const idMaterial        *lightShader = vLight->lightShader;
2456
2457                 // do fogging later
2458                 if ( lightShader->IsFogLight() ) {
2459                         continue;
2460                 }
2461                 if ( lightShader->IsBlendLight() ) {
2462                         continue;
2463                 }
2464
2465                 if ( !vLight->localInteractions && !vLight->globalInteractions
2466                         && !vLight->translucentInteractions ) {
2467                         continue;
2468                 }
2469
2470                 if ( !vLight->frustumTris->ambientCache ) {
2471                         R_CreateAmbientCache( const_cast<srfTriangles_t *>(vLight->frustumTris), false ); 
2472                 }
2473
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 );
2477
2478                 int     side, sideStop;
2479
2480                 if ( vLight->lightDef->parms.pointLight ) {
2481                         if ( r_sb_singleSide.GetInteger() != -1 ) {
2482                                 side = r_sb_singleSide.GetInteger();
2483                                 sideStop = side+1;
2484                         } else {
2485                                 side = 0;
2486                                 sideStop = 6;
2487                         }
2488                 } else {
2489                         side = -1;
2490                         sideStop = 0;
2491                 }
2492
2493                 for (  ; side < sideStop ; side++ ) {
2494                         // FIXME: check for frustums completely off the screen
2495
2496                         // render a shadow buffer
2497                         RB_RenderShadowBuffer( vLight, side );
2498
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 );
2503                         } else {
2504                                 // to off screen buffer
2505                                 if ( r_sb_usePbuffer.GetBool() ) {
2506                                         GL_CheckErrors();
2507                                         // set the current openGL drawable to the shadow buffer
2508                                         R_MakeCurrent( viewPbufferDC, win32.hGLRC, viewPbuffer );
2509                                 }
2510                                 qglViewport( 0, 0, viewBufferSize, viewBufferHeight );
2511                                 qglScissor( 0, 0, viewBufferSize, viewBufferHeight );   // !@# FIXME: scale light scissor
2512                         }
2513
2514                         // render the shadows into destination alpha on the included pixels
2515                         RB_Exp_SelectFrustum( vLight, side );
2516
2517                         if ( !r_sb_screenSpaceShadow.GetBool() ) {
2518                                 // bind shadow buffer to texture
2519                                 GL_SelectTextureNoClient( 7 );
2520                                 shadowImage[0]->BindFragment();
2521
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;
2527                         }
2528                 }
2529
2530                 // render the native window coordinates interactions
2531                 if ( r_sb_screenSpaceShadow.GetBool() ) {
2532                         if ( !nativeViewBuffer ) {
2533                                 RB_shadowResampleAlpha();
2534                                 qglEnable( GL_STENCIL_TEST );
2535                         } else {
2536                                 RB_EXP_SetRenderBuffer( vLight );
2537 if ( r_ignore.GetBool() ) {
2538 qglEnable( GL_STENCIL_TEST );   //!@#
2539 } else {
2540 qglDisable( GL_STENCIL_TEST );  //!@#
2541 }
2542                         }
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;
2548                 }
2549         }
2550
2551         GL_SelectTexture( 0 );
2552         qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
2553
2554         // experimental transfer function
2555         for ( int i = 7 ; i >= 0 ; i-- ) {
2556                 GL_SelectTextureNoClient( i );
2557                 globalImages->BindNull();
2558         }
2559         GL_State( 0 );
2560
2561         RB_EXP_Bloom();
2562         RB_EXP_GammaDither();
2563
2564         // these haven't been state saved
2565         for ( int i = 0 ; i < 8 ; i++ ) {
2566                 backEnd.glState.tmu[i].current2DMap = -1;
2567         }
2568
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 );
2572
2573
2574 }
2575
2576
2577
2578 /*
2579 ==================
2580 R_Exp_Init
2581 ==================
2582 */
2583 void R_Exp_Init( void ) {
2584         glConfig.allowExpPath = false;
2585
2586         common->Printf( "---------- R_Exp_Init ----------\n" );
2587
2588         if ( !glConfig.ARBVertexProgramAvailable || !glConfig.ARBFragmentProgramAvailable ) {
2589                 common->Printf( "Not available.\n" );
2590                 return;
2591         }
2592 RB_CreateBloomTable();
2593 #if 0
2594         if ( !R_CheckExtension( "GL_NV_float_buffer" ) ) {
2595                 common->Printf( "Not available.\n" );
2596                 return;
2597         }
2598         if ( !R_CheckExtension( "GL_NV_texture_rectangle" ) ) {
2599                 common->Printf( "Not available.\n" );
2600                 return;
2601         }
2602 #endif
2603
2604 #if 0
2605         qglCombinerParameterfvNV = (void (APIENTRY *)( GLenum pname, const GLfloat *params ))
2606                 GLimp_ExtensionPointer( "glCombinerParameterfvNV" );
2607 #endif
2608
2609         common->Printf( "Available.\n" );
2610
2611         if ( !idStr::Icmp( r_renderer.GetString(), "exp" ) ) {
2612                 R_Exp_Allocate();
2613         }
2614
2615         common->Printf( "--------------------------------------------\n" );
2616
2617         glConfig.allowExpPath = true;
2618 }