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