Forum

Doom 3 engine release and game code

Discuss programming topics for any language, any source base. If it is programming related but doesn't fit in one of the below categories, it goes here.

Moderator: InsideQC Admins

Re: Doom 3 engine release and game code

Postby Irritant » Tue Dec 13, 2011 4:08 am

mh wrote:
nbohr1more wrote:Not to spam this thread with tech demos (etc)... but what do you think of Humus's "Shadows that Rock" implementation for Shadow Mapping?

http://www.humus.name/index.php?page=3D&ID=28


Bad aliasing on the shadow edges.

These demos typically only use a single light source and a relatively low poly count ("shadows that rock" actually has two lights). That's fine for a demo but Doom 3 can have multiple light sources and a much higher poly count so I'd question if it's reasonable to implement such a technique. It would also require a raising of the hardware specs beyond what the original engine required.


I agree. The biggest problem I always had with trying to get proper shadowmapping for static lights, was that there are so many sources. I was never able to get anything that was both accurate and fast. It's fine for dynamic lights, or outdoor scenes with a light source like the sun though, and that is what we did in CRX with shadowmapping. For static lights though, we did stencil volumes, blitted them into an FBO, used GLSL to blur them, and rendered it on a quad over the scene, to achieve soft shadows.
http://red.planetarena.org - Alien Arena and the CRX engine
Irritant
 
Posts: 250
Joined: Mon May 19, 2008 2:54 pm
Location: Maryland

Re: Doom 3 engine release and game code

Postby nbohr1more » Tue Dec 13, 2011 9:55 pm

mh wrote:Doom 3 doesn't use branching in it's shaders, but there are a few other tricks you can do to simulate branching, like the MAX and MIN instructions.

Big problem with dynamic branching simulation using alpha test or stencil test is that it won't work with early-Z rejection as it depends on the fragment shaders executing. You'd get better performance out of Doom 3 by tweaking it to be early-Z friendly (in particular as it does a Z prepass and so is otherwise ideally set up for it - just that pesky stencil buffer use for everything kinda ruins it ).

None of that would have been an option when Doom 3 was originally developed as early Z in hardware didn't really exist at the time.

Second big problem about simulating branching with alpha test or stencil test is that it has to coexist peacefully with any other alpha test or stencil test that the engine does - and Doom 3 does a lot of both.

All academic however as the OpenGL asm shaders that Doom 3 used don't support branching anyway, and so Doom 3 doesn't need to use any kind of dynamic branching tricks.


Thanks again.

(I'm a little puzzled still as Nvidia's documentation says that Z-Cull was available as of Geforce 3 (the render path for Geforce 2 and Geforce 4MX DX7 hardware notwithstanding...) and the Radeon 8500's hierarchical z could also perform this functionality (with caveats) while the Radeon 9xxx (R300) has a PDF about it here: http://developer.amd.com/media/gpu_asse ... EarlyZ.pdf ... Is the perception that ATI didn't have this functionality till X1000 hardware a byproduct of the "required gotchas to utilize it" or effective misinformation from Nvidia developer relations? :? )

Your reply is indicative that you are not intending any radical changes to the engine but rather possibly trying to extend it's design philosophy to newer but similar methodology? If that take is correct, we can view your stance to be more akin to an archival preservation role rather than (likely inflated) hopes for a radical revisionist in the spirit of your Quake source projects?

It seems that ARB assembly is off the plate currently for standalone projects as id Software did not supply the default shaders along with the GPL package (pending, of course, the possibility of GPL versions that work as well ). To my knowledge we are yet awaiting GLSL replacement versions with Raynorpat being the only publicly known contributor for this endeavor. So my inquiries were more towards the spirit of a more liberal treatment of the engine... Tr3B appears to be investigating such concepts as changing the renderer to a Deferred method so (if that comes to fruition) the more radical overhauls will eventually be out there.
nbohr1more
 
Posts: 54
Joined: Fri Dec 09, 2011 7:04 am

Re: Doom 3 engine release and game code

Postby mh » Tue Dec 13, 2011 10:21 pm

The info I had was more the other way around - ATI were the ones with early-Z and NV without. That was based on a .plan from reasonably early in the development of the engine, so it may have been subsequently invalidated, of course. Doom 3 can't use early-Z anyway as it needs to keep the stencil test active for all stages of it's interaction render.

My current intentions for the engine are nothing; I have other priorities and I'm just playing around with the code in spare time. A possible goal is to write an ARB asm to HLSL converter and do a D3D port, but right now it's way off in the future, if at all.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
User avatar
mh
 
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Re: Doom 3 engine release and game code

Postby nbohr1more » Tue Dec 13, 2011 11:08 pm

Looks like the matter of hierarchical-z behavior in Doom 3 is far from a clear matter even for the luminaries over at Beyond3D:

http://forum.beyond3d.com/showthread.php?t=12535

...with the latest (from a member who is believed to be an ATI insider) clarifying the issue as best as allowed?

ATI stores the farthest Z value. So if an incoming tile is completely behind this value, you can trivially reject it. Trivial rejection is much more useful than trivial accept. (note that this also means that if a triangle partly covers a tile marked as cleared, that tile is effectively "lost")


The Z-fail method now means that, if (the stencil test passes and) the Z test fails, you increase/decrease the stencil value. So even if hierZ knows that all pixels fail the Z test, it can't reject pixels because there's still work to be done for those pixels.


I'm glad you've done as much investigation as you have mh. Thanks. (Though I hope something in the code sparks your interest to keep going... )
nbohr1more
 
Posts: 54
Joined: Fri Dec 09, 2011 7:04 am

Re: Doom 3 engine release and game code

Postby mh » Wed Dec 14, 2011 1:18 am

That's quite a curious thread, with - unfortunately - quite a bit of conspiracy theory in it that is sadly reminiscent of some of the recent hoo-hah over Rage.

The only really relevant post is - I believe - the one you've quoted, but even that only tells a small part of the story. The nature of stencil test is that when it's enabled any form of early-Z won't work because stencil test comes after the per-fragment part of the pipeline, so whether it's z-pass or z-fail is irrelevant, there will always still be work to do (the same applies to alpha test and traditional depth testing). It's possible that an intelligent driver may be able to figure out from the stencil op that it can skip the stencil test under certain circumstances (e.g. with glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP)), but that's driver-dependent and shouldn't be relied on.

Now, Doom 3 keeps the stencil test enabled for all of it's drawing: shadows, light interactions, old-style drawing (used for trans surfaces, skyboxes, some overlay effects, etc) meaning that the only thing you can rely on is the worst-case scenario, which is that early-Z won't work.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
User avatar
mh
 
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Re: Doom 3 engine release and game code

Postby Spike » Wed Dec 14, 2011 4:20 am

aye, if its actually testing the stencil buffer then you've already lost your early-z optimisation - its already rasterizing per pixel.

however, generating stencil shadow volumes doesn't test the stencil buffer, it only updates it, so for these passes, you should be able to keep any early-z optimisations on the condition that the first and middle argument of glStencilOp is GL_KEEP (zfail requires inc and dec for the front or back, while zpass has the inc/dec for the 3rd argument instead).
Its only the actual rendering which tests the stencil buffer, but in this case, the depthtest is also required to pass, so there's no reason for the stencil to be tested if its the depth will fail anyway, so early-z should apply for these passes without a problem.
for skys and unlit things, even if doom3 leaves stencil testing enabled, I would expect that it reset StencilOp to full GL_KEEPs and StencilFunc to GL_ALWAYS, both combined basically leave the stencil buffer untouched regardless of glEnables, so early-z testing should still apply.

Of course, hardware and drivers may have limitations that could give worse characteristics, but if they don't, I disagree with mh.
Zpass volume generation, where the stencil is only updated when the depth pass also succeeds should fully benefit from any early-z tests without needing to resort to specific pixels, while generation of z-fail volumes where the stencil is updated even if the depth fails will need to iterate over the pixels themselves.
Of course, this is pretty much a moot point as z-pass is faster anyway due to no front/back cap rendering. You'd only want to use z-fail where z-pass is inadequete anyway - any decent engine would want to use z-pass where it can. Any arguing would be over the amount of speed you can get by doing so (and whether its enough for it to be worth detecting if you can get away with z-pass).

Is the way I see it, anyway.
Spike
 
Posts: 2892
Joined: Fri Nov 05, 2004 3:12 am
Location: UK

Re: Doom 3 engine release and game code

Postby mh » Wed Dec 14, 2011 6:56 pm

Well a lot of it depends on the hardware; early-Z is part of neither the OpenGL nor D3D specs so drivers aren't even under any obligation to implement it at all (and an engine can definitely be set up to take advantage of it where possible/reasonable, but should never assume that it's there). Those that do may do so in any way that the engineers see fit, and that meets the actual requirements of the specs (most specifically that an early-Z optimization doesn't change the final output from the fragment/pixel shader).

A few of the earlier ATI papers on it that I've read seem to imply that it won't run if stencil test was enabled at all. That would indicate that they operated it on a coarser level than per-fragment (say, per-triangle or block of fragments - guess) and consequently it would have been possible for individual fragments to pass early-Z but still fail a real Z test. Other hardware may differ, but the key point remains that it is very hardware-dependent and so shouldn't be relied on.

One thing I found both amusing and annoying from that Beyond3D thread was the accusations of id deliberately nerfing ATI. Of course it's the case that if they hadn't implemented z-fail they would have had to do two passes, so what would have been gained from early-Z would have been lost from the second pass. All the more so as the first preload pass for when the view was inside the shadow volume still needed a zfail condition. And ironic because id had included ATI-specific code (the old two-sided stencil extension, as well as ATI_fragment_shader) so they shouldn't have even been accused of trying to nobble ATI.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
User avatar
mh
 
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Re: Doom 3 engine release and game code

Postby revelator » Thu Dec 29, 2011 2:57 am

Well i finally managed to stumble upon something that works. Big thanks to a guy named leith.

part of the shadow code might be patented but also includes ati and nvidia dual pass paths which are not. The patented portion might be replaced with mh's.

Code: Select all
   // possibly patented ?
   if ( !external ) {
      if (glConfig.twoSidedStencilAvailable && r_useTwoSidedStencil.GetBool()) {
         qglActiveStencilFaceEXT( backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK );
         qglStencilOp( GL_KEEP, tr.stencilDecr, GL_KEEP );
         qglActiveStencilFaceEXT( backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT );
         qglStencilOp( GL_KEEP, tr.stencilIncr, GL_KEEP );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );
      } else if(r_useTwoSidedStencil.GetBool() && glConfig.atiTwoSidedStencilAvailable) {
         qglStencilOpSeparateATI( backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK, GL_KEEP, tr.stencilDecr, GL_KEEP );
         qglStencilOpSeparateATI( backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT, GL_KEEP, tr.stencilIncr, GL_KEEP );
         GL_Cull( CT_TWO_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );
      } else {
         qglStencilOp( GL_KEEP, tr.stencilDecr, GL_KEEP );
         GL_Cull( CT_FRONT_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );

         qglStencilOp( GL_KEEP, tr.stencilIncr, GL_KEEP );
         GL_Cull( CT_BACK_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );
      }
   } else {
      // traditional depth-pass stencil shadows
      if (glConfig.twoSidedStencilAvailable && r_useTwoSidedStencil.GetBool()) {
         qglActiveStencilFaceEXT( backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK );
         qglStencilOp( GL_KEEP, GL_KEEP, tr.stencilIncr );
         qglActiveStencilFaceEXT( backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT );
         qglStencilOp( GL_KEEP, GL_KEEP, tr.stencilDecr );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );
      } else if(r_useTwoSidedStencil.GetBool() && glConfig.atiTwoSidedStencilAvailable) {
         qglStencilOpSeparateATI( backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK, GL_KEEP, GL_KEEP, tr.stencilIncr );
         qglStencilOpSeparateATI( backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT, GL_KEEP, GL_KEEP, tr.stencilDecr );
         GL_Cull( CT_TWO_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );
      } else {
         qglStencilOp( GL_KEEP, GL_KEEP, tr.stencilIncr );
         GL_Cull( CT_FRONT_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );

         qglStencilOp( GL_KEEP, GL_KEEP, tr.stencilDecr );
         GL_Cull( CT_BACK_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );
      }
   }


this is the bulk of it, you also need to make a check for nvdepthclamp and call it in the function below the one containing this.

if mh can throw his parts in where this one hurts we can make a tut for others :)
Productivity is a state of mind.
User avatar
revelator
 
Posts: 2567
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: Doom 3 engine release and game code

Postby revelator » Thu Dec 29, 2011 6:17 pm

Code: Select all
/*
=====================
RB_T_Shadow

the shadow volumes face INSIDE
=====================
*/
static void RB_T_Shadow( const drawSurf_t *surf ) {
   const srfTriangles_t   *tri;

   // set the light position if we are using a vertex program to project the rear surfaces
   if ( tr.backEndRendererHasVertexPrograms && r_useShadowVertexProgram.GetBool()
      && surf->space != backEnd.currentSpace ) {
      idVec4 localLight;

      R_GlobalPointToLocal( surf->space->modelMatrix, backEnd.vLight->globalLightOrigin, localLight.ToVec3() );
      localLight.w = 0.0f;
      qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_ORIGIN, localLight.ToFloatPtr() );
   }

   tri = surf->geo;

   if ( !tri->shadowCache ) {
      return;
   }

   qglVertexPointer( 4, GL_FLOAT, sizeof( shadowCache_t ), vertexCache.Position(tri->shadowCache) );

   // we always draw the sil planes, but we may not need to draw the front or rear caps
   int   numIndexes;
   bool external = false;

   if ( !r_useExternalShadows.GetInteger() ) {
      numIndexes = tri->numIndexes;
   } else if ( r_useExternalShadows.GetInteger() == 2 ) { // force to no caps for testing
      numIndexes = tri->numShadowIndexesNoCaps;
      external = true;
   }  else if ( ( glConfig.depthClampAvailable && r_useDepthClamp.GetBool() ) || !(surf->dsFlags & DSF_VIEW_INSIDE_SHADOW) ) {
      // if we aren't inside the shadow projection, no caps are ever needed needed
      // LEITH: also if depth clamp is enabled the near and far clip planes are disabled removing the need for any caps
      numIndexes = tri->numShadowIndexesNoCaps;
      external = true;
   } else if ( !backEnd.vLight->viewInsideLight && !(surf->geo->shadowCapPlaneBits & SHADOW_CAP_INFINITE) ) {
      // if we are inside the shadow projection, but outside the light, and drawing
      // a non-infinite shadow, we can skip some caps
      if ( backEnd.vLight->viewSeesShadowPlaneBits & surf->geo->shadowCapPlaneBits ) {
         // we can see through a rear cap, so we need to draw it, but we can skip the
         // caps on the actual surface
         numIndexes = tri->numShadowIndexesNoFrontCaps;
      } else {
         // we don't need to draw any caps
         numIndexes = tri->numShadowIndexesNoCaps;
      }
      external = true;
   } else {
      // must draw everything
      numIndexes = tri->numIndexes;
   }

   // set depth bounds
   if( glConfig.depthBoundsTestAvailable && r_useDepthBoundsTest.GetBool() ) {
      qglDepthBoundsEXT( surf->scissorRect.zmin, surf->scissorRect.zmax );
   }

   // debug visualization
   if ( r_showShadows.GetInteger() ) {
      if ( r_showShadows.GetInteger() == 3 ) {
         if ( external ) {
            qglColor3f( 0.1/backEnd.overBright, 1/backEnd.overBright, 0.1/backEnd.overBright );
         } else {
            // these are the surfaces that require the reverse
            qglColor3f( 1/backEnd.overBright, 0.1/backEnd.overBright, 0.1/backEnd.overBright );
         }
      } else {
         // draw different color for turboshadows
         if ( surf->geo->shadowCapPlaneBits & SHADOW_CAP_INFINITE ) {
            if ( numIndexes == tri->numIndexes ) {
               qglColor3f( 1/backEnd.overBright, 0.1/backEnd.overBright, 0.1/backEnd.overBright );
            } else {
               qglColor3f( 1/backEnd.overBright, 0.4/backEnd.overBright, 0.1/backEnd.overBright );
            }
         } else {
            if ( numIndexes == tri->numIndexes ) {
               qglColor3f( 0.1/backEnd.overBright, 1/backEnd.overBright, 0.1/backEnd.overBright );
            } else if ( numIndexes == tri->numShadowIndexesNoFrontCaps ) {
               qglColor3f( 0.1/backEnd.overBright, 1/backEnd.overBright, 0.6/backEnd.overBright );
            } else {
               qglColor3f( 0.6/backEnd.overBright, 1/backEnd.overBright, 0.1/backEnd.overBright );
            }
         }
      }

      qglStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
      qglDisable( GL_STENCIL_TEST );
      GL_Cull( CT_TWO_SIDED );
      RB_DrawShadowElementsWithCounters( tri, numIndexes );
      GL_Cull( CT_FRONT_SIDED );
      qglEnable( GL_STENCIL_TEST );

      return;
   }
   
   // possibly patented ?
   if ( !external ) {
      if (glConfig.twoSidedStencilAvailable && r_useTwoSidedStencil.GetBool()) {
         if (glConfig.glVersion >= 2.0) {
            qglStencilOpSeparate(backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK, GL_KEEP, tr.stencilIncr, GL_KEEP);
            qglStencilOpSeparate(backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT, GL_KEEP, tr.stencilDecr, GL_KEEP);
            GL_Cull( CT_TWO_SIDED );
            RB_DrawShadowElementsWithCounters( tri, numIndexes );
         } else {
            qglActiveStencilFaceEXT( backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK );
            qglStencilOp( GL_KEEP, tr.stencilDecr, GL_KEEP );
            qglActiveStencilFaceEXT( backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT );
            qglStencilOp( GL_KEEP, tr.stencilIncr, GL_KEEP );
            RB_DrawShadowElementsWithCounters( tri, numIndexes );
         }
      } else if(r_useTwoSidedStencil.GetBool() && glConfig.atiTwoSidedStencilAvailable) {
         qglStencilOpSeparateATI( backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK, GL_KEEP, tr.stencilDecr, GL_KEEP );
         qglStencilOpSeparateATI( backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT, GL_KEEP, tr.stencilIncr, GL_KEEP );
         GL_Cull( CT_TWO_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );
      } else {
         qglStencilOp( GL_KEEP, tr.stencilDecr, GL_KEEP );
         GL_Cull( CT_FRONT_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );

         qglStencilOp( GL_KEEP, tr.stencilIncr, GL_KEEP );
         GL_Cull( CT_BACK_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );
      }
   } else {
      // traditional depth-pass stencil shadows
      if (glConfig.twoSidedStencilAvailable && r_useTwoSidedStencil.GetBool()) {
         if (glConfig.glVersion >= 2.0) {
            qglStencilOpSeparate(backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK, GL_KEEP, GL_KEEP, tr.stencilIncr);
            qglStencilOpSeparate(backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT, GL_KEEP, GL_KEEP, tr.stencilDecr);
            GL_Cull( CT_TWO_SIDED );
            RB_DrawShadowElementsWithCounters( tri, numIndexes );
         } else {
            qglActiveStencilFaceEXT( backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK );
            qglStencilOp( GL_KEEP, GL_KEEP, tr.stencilIncr );
            qglActiveStencilFaceEXT( backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT );
            qglStencilOp( GL_KEEP, GL_KEEP, tr.stencilDecr );
            RB_DrawShadowElementsWithCounters( tri, numIndexes );
         }
      } else if(r_useTwoSidedStencil.GetBool() && glConfig.atiTwoSidedStencilAvailable) {
         qglStencilOpSeparateATI( backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK, GL_KEEP, GL_KEEP, tr.stencilIncr );
         qglStencilOpSeparateATI( backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT, GL_KEEP, GL_KEEP, tr.stencilDecr );
         GL_Cull( CT_TWO_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );
      } else {
         qglStencilOp( GL_KEEP, GL_KEEP, tr.stencilIncr );
         GL_Cull( CT_FRONT_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );

         qglStencilOp( GL_KEEP, GL_KEEP, tr.stencilDecr );
         GL_Cull( CT_BACK_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );
      }
   }
}

/*
=====================
RB_StencilShadowPass

Stencil test should already be enabled, and the stencil buffer should have
been set to 128 on any surfaces that might receive shadows
=====================
*/
void RB_StencilShadowPass( const drawSurf_t *drawSurfs ) {
   if ( !r_shadows.GetBool() ) {
      return;
   }

   if ( !drawSurfs ) {
      return;
   }

   RB_LogComment( "---------- RB_StencilShadowPass ----------\n" );

   globalImages->BindNull();
   qglDisableClientState( GL_TEXTURE_COORD_ARRAY );

   // for visualizing the shadows
   if ( r_showShadows.GetInteger() ) {
      if ( r_showShadows.GetInteger() == 2 ) {
         // draw filled in
         GL_State( GLS_DEPTHMASK | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_LESS  );
      } else {
         // draw as lines, filling the depth buffer
         GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_POLYMODE_LINE | GLS_DEPTHFUNC_ALWAYS  );
      }
   } else {
      // don't write to the color buffer, just the stencil buffer
      GL_State( GLS_DEPTHMASK | GLS_COLORMASK | GLS_ALPHAMASK | GLS_DEPTHFUNC_LESS );
   }

   if ( r_shadowPolygonFactor.GetFloat() || r_shadowPolygonOffset.GetFloat() ) {
      qglPolygonOffset( r_shadowPolygonFactor.GetFloat(), -r_shadowPolygonOffset.GetFloat() );
      qglEnable( GL_POLYGON_OFFSET_FILL );
   }
   qglStencilFunc( GL_ALWAYS, 1, 255 );

   if ( glConfig.depthBoundsTestAvailable && r_useDepthBoundsTest.GetBool() ) {
      qglEnable( GL_DEPTH_BOUNDS_TEST_EXT );
   }

   // LEITH: enable NVIDIA two sided stencil ops
   if ( glConfig.twoSidedStencilAvailable && r_useTwoSidedStencil.GetBool() ) {
      qglEnable( GL_STENCIL_TEST_TWO_SIDE_EXT );
   }

   // LEITH: enable NVIDIA depth clamp
   if ( glConfig.depthClampAvailable && r_useDepthClamp.GetBool() ) {
      qglEnable( GL_DEPTH_CLAMP_NV );
   }
   RB_RenderDrawSurfChainWithFunction( drawSurfs, RB_T_Shadow );

   GL_Cull( CT_FRONT_SIDED );

   if ( r_shadowPolygonFactor.GetFloat() || r_shadowPolygonOffset.GetFloat() ) {
      qglDisable( GL_POLYGON_OFFSET_FILL );
   }

   if ( glConfig.depthBoundsTestAvailable && r_useDepthBoundsTest.GetBool() ) {
      qglDisable( GL_DEPTH_BOUNDS_TEST_EXT );
   }

   // LEITH: disable NVIDIA depth clamp
   if ( glConfig.depthClampAvailable && r_useDepthClamp.GetBool() ) {
      qglDisable( GL_DEPTH_CLAMP_NV );
   }
   qglEnableClientState( GL_TEXTURE_COORD_ARRAY );

   qglStencilFunc( GL_GEQUAL, 128, 255 );
   qglStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
}


final version with most changes. Im going to make a diff against the unmodified version so peeps wont have a hard time doing it by hand .
Works flawlessly and shadows are much more subtle with this.
Productivity is a state of mind.
User avatar
revelator
 
Posts: 2567
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: Doom 3 engine release and game code

Postby revelator » Fri Dec 30, 2011 12:33 am

Small error snuck up on me while making this version, correct code below->

Code: Select all
   // possibly patented ?
   if ( !external ) {
      if (glConfig.twoSidedStencilAvailable && r_useTwoSidedStencil.GetBool()) {
         if (glConfig.glVersion >= 2.0) {
            // whoops i mistakenly inverted these :S
            qglStencilOpSeparate(backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK, GL_KEEP, tr.stencilDecr, GL_KEEP);
            qglStencilOpSeparate(backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT, GL_KEEP, tr.stencilIncr, GL_KEEP);
            // whoops end
            GL_Cull( CT_TWO_SIDED );
            RB_DrawShadowElementsWithCounters( tri, numIndexes );
         } else {
            qglActiveStencilFaceEXT( backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK );
            qglStencilOp( GL_KEEP, tr.stencilDecr, GL_KEEP );
            qglActiveStencilFaceEXT( backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT );
            qglStencilOp( GL_KEEP, tr.stencilIncr, GL_KEEP );
            RB_DrawShadowElementsWithCounters( tri, numIndexes );
         }
      } else if(r_useTwoSidedStencil.GetBool() && glConfig.atiTwoSidedStencilAvailable) {
         qglStencilOpSeparateATI( backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK, GL_KEEP, tr.stencilDecr, GL_KEEP );
         qglStencilOpSeparateATI( backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT, GL_KEEP, tr.stencilIncr, GL_KEEP );
         GL_Cull( CT_TWO_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );
      } else {
         qglStencilOp( GL_KEEP, tr.stencilDecr, GL_KEEP );
         GL_Cull( CT_FRONT_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );

         qglStencilOp( GL_KEEP, tr.stencilIncr, GL_KEEP );
         GL_Cull( CT_BACK_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );
      }
   } else {
      // traditional depth-pass stencil shadows
      if (glConfig.twoSidedStencilAvailable && r_useTwoSidedStencil.GetBool()) {
         if (glConfig.glVersion >= 2.0) {
            qglStencilOpSeparate(backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK, GL_KEEP, GL_KEEP, tr.stencilIncr);
            qglStencilOpSeparate(backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT, GL_KEEP, GL_KEEP, tr.stencilDecr);
            GL_Cull( CT_TWO_SIDED );
            RB_DrawShadowElementsWithCounters( tri, numIndexes );
         } else {
            qglActiveStencilFaceEXT( backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK );
            qglStencilOp( GL_KEEP, GL_KEEP, tr.stencilIncr );
            qglActiveStencilFaceEXT( backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT );
            qglStencilOp( GL_KEEP, GL_KEEP, tr.stencilDecr );
            RB_DrawShadowElementsWithCounters( tri, numIndexes );
         }
      } else if(r_useTwoSidedStencil.GetBool() && glConfig.atiTwoSidedStencilAvailable) {
         qglStencilOpSeparateATI( backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK, GL_KEEP, GL_KEEP, tr.stencilIncr );
         qglStencilOpSeparateATI( backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT, GL_KEEP, GL_KEEP, tr.stencilDecr );
         GL_Cull( CT_TWO_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );
      } else {
         qglStencilOp( GL_KEEP, GL_KEEP, tr.stencilIncr );
         GL_Cull( CT_FRONT_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );

         qglStencilOp( GL_KEEP, GL_KEEP, tr.stencilDecr );
         GL_Cull( CT_BACK_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );
      }
   }
Productivity is a state of mind.
User avatar
revelator
 
Posts: 2567
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: Doom 3 engine release and game code

Postby revelator » Fri Dec 30, 2011 8:02 am

ok here we go.

replace these functions in draw_common.cpp with the one i post below.

Code: Select all
/*
=====================
RB_T_Shadow

the shadow volumes face INSIDE
=====================
*/
static void RB_T_Shadow( const drawSurf_t *surf ) {
   const srfTriangles_t   *tri;

   // set the light position if we are using a vertex program to project the rear surfaces
   if ( tr.backEndRendererHasVertexPrograms && r_useShadowVertexProgram.GetBool() && surf->space != backEnd.currentSpace ) {
      idVec4 localLight;

      R_GlobalPointToLocal( surf->space->modelMatrix, backEnd.vLight->globalLightOrigin, localLight.ToVec3() );
      localLight.w = 0.0f;
      qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_ORIGIN, localLight.ToFloatPtr() );
   }
   tri = surf->geo;

   if ( !tri->shadowCache ) {
      return;
   }
   qglVertexPointer( 4, GL_FLOAT, sizeof( shadowCache_t ), vertexCache.Position(tri->shadowCache) );

   // we always draw the sil planes, but we may not need to draw the front or rear caps
   int   numIndexes;
   bool external = false;

   if ( !r_useExternalShadows.GetInteger() ) {
      numIndexes = tri->numIndexes;
   } else if ( r_useExternalShadows.GetInteger() == 2 ) { // force to no caps for testing
      numIndexes = tri->numShadowIndexesNoCaps;
      external = true;
   } else if ( ( glConfig.depthClampAvailable && r_useDepthClamp.GetBool() ) || !(surf->dsFlags & DSF_VIEW_INSIDE_SHADOW) ) {
      // if we aren't inside the shadow projection, no caps are ever needed
      // LEITH: also if depth clamp is enabled the near and far clip planes are disabled removing the need for any caps
      numIndexes = tri->numShadowIndexesNoCaps;
      external = true;
   } else if ( !backEnd.vLight->viewInsideLight && !(surf->geo->shadowCapPlaneBits & SHADOW_CAP_INFINITE) ) {
      // if we are inside the shadow projection, but outside the light, and drawing
      // a non-infinite shadow, we can skip some caps
      if ( backEnd.vLight->viewSeesShadowPlaneBits & surf->geo->shadowCapPlaneBits ) {
         // we can see through a rear cap, so we need to draw it, but we can skip the
         // caps on the actual surface
         numIndexes = tri->numShadowIndexesNoFrontCaps;
      } else {
         // we don't need to draw any caps
         numIndexes = tri->numShadowIndexesNoCaps;
      }
      external = true;
   } else {
      // must draw everything
      numIndexes = tri->numIndexes;
   }

   // set depth bounds
   if( glConfig.depthBoundsTestAvailable && r_useDepthBoundsTest.GetBool() ) {
      qglDepthBoundsEXT( surf->scissorRect.zmin, surf->scissorRect.zmax );
   }

   // debug visualization
   if ( r_showShadows.GetInteger() ) {
      if ( r_showShadows.GetInteger() == 3 ) {
         if ( external ) {
            qglColor3f( 0.1/backEnd.overBright, 1/backEnd.overBright, 0.1/backEnd.overBright );
         } else {
            // these are the surfaces that require the reverse
            qglColor3f( 1/backEnd.overBright, 0.1/backEnd.overBright, 0.1/backEnd.overBright );
         }
      } else {
         // draw different color for turboshadows
         if ( surf->geo->shadowCapPlaneBits & SHADOW_CAP_INFINITE ) {
            if ( numIndexes == tri->numIndexes ) {
               qglColor3f( 1/backEnd.overBright, 0.1/backEnd.overBright, 0.1/backEnd.overBright );
            } else {
               qglColor3f( 1/backEnd.overBright, 0.4/backEnd.overBright, 0.1/backEnd.overBright );
            }
         } else {
            if ( numIndexes == tri->numIndexes ) {
               qglColor3f( 0.1/backEnd.overBright, 1/backEnd.overBright, 0.1/backEnd.overBright );
            } else if ( numIndexes == tri->numShadowIndexesNoFrontCaps ) {
               qglColor3f( 0.1/backEnd.overBright, 1/backEnd.overBright, 0.6/backEnd.overBright );
            } else {
               qglColor3f( 0.6/backEnd.overBright, 1/backEnd.overBright, 0.1/backEnd.overBright );
            }
         }
      }

      qglStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
      qglDisable( GL_STENCIL_TEST );
      GL_Cull( CT_TWO_SIDED );
      RB_DrawShadowElementsWithCounters( tri, numIndexes );
      GL_Cull( CT_FRONT_SIDED );
      qglEnable( GL_STENCIL_TEST );

      return;
   }

   // flippin hell it finally works !!
   if ( !external ) {
      // glStencilOpSeparate if your card supports OpenGL2
      if (glConfig.twoSidedStencilAvailable && r_useTwoSidedStencil.GetBool() && glConfig.glVersion >= 2.0) {
         qglStencilOpSeparate( backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK, GL_KEEP, tr.stencilDecr, GL_KEEP );
         qglStencilOpSeparate( backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT, GL_KEEP, tr.stencilIncr, GL_KEEP );
         GL_Cull( CT_TWO_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );
      } else if (glConfig.twoSidedStencilAvailable && r_useTwoSidedStencil.GetBool()) {
         // else fall back to old pre OpenGL2 twosided stencil.
         qglActiveStencilFaceEXT( backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK );
         qglStencilOp( GL_KEEP, tr.stencilDecr, GL_KEEP );
         qglActiveStencilFaceEXT( backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT );
         qglStencilOp( GL_KEEP, tr.stencilIncr, GL_KEEP );
         GL_Cull( CT_TWO_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );
      } else if (glConfig.atiTwoSidedStencilAvailable && r_useTwoSidedStencil.GetBool()) {
         // if you got a newer ATI card use the ATI version of the OpenGL2 functions.
         qglStencilOpSeparateATI( backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK, GL_KEEP, tr.stencilDecr, GL_KEEP );
         qglStencilOpSeparateATI( backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT, GL_KEEP, tr.stencilIncr, GL_KEEP );
         GL_Cull( CT_TWO_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );
      } else {
         // if you got here your card is ancient good luck.
         qglStencilOp( GL_KEEP, tr.stencilDecr, GL_KEEP );
         GL_Cull( CT_FRONT_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );

         qglStencilOp( GL_KEEP, tr.stencilIncr, GL_KEEP );
         GL_Cull( CT_BACK_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );
      }
   } else {
      // traditional depth-pass stencil shadows
      if (glConfig.twoSidedStencilAvailable && r_useTwoSidedStencil.GetBool() && glConfig.glVersion >= 2.0 ) {
         qglStencilOpSeparate( backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK, GL_KEEP, GL_KEEP, tr.stencilIncr );
         qglStencilOpSeparate( backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT, GL_KEEP, GL_KEEP, tr.stencilDecr );
         GL_Cull( CT_TWO_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );
      } else if (glConfig.twoSidedStencilAvailable && r_useTwoSidedStencil.GetBool()) {
         qglActiveStencilFaceEXT( backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK );
         qglStencilOp( GL_KEEP, GL_KEEP, tr.stencilIncr );
         qglActiveStencilFaceEXT( backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT );
         qglStencilOp( GL_KEEP, GL_KEEP, tr.stencilDecr );
         GL_Cull( CT_TWO_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );
      } else if(glConfig.atiTwoSidedStencilAvailable && r_useTwoSidedStencil.GetBool()) {
         qglStencilOpSeparateATI( backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK, GL_KEEP, GL_KEEP, tr.stencilIncr );
         qglStencilOpSeparateATI( backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT, GL_KEEP, GL_KEEP, tr.stencilDecr );
         GL_Cull( CT_TWO_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );
      } else {
         qglStencilOp( GL_KEEP, GL_KEEP, tr.stencilIncr );
         GL_Cull( CT_FRONT_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );

         qglStencilOp( GL_KEEP, GL_KEEP, tr.stencilDecr );
         GL_Cull( CT_BACK_SIDED );
         RB_DrawShadowElementsWithCounters( tri, numIndexes );
      }
   }
}

/*
=====================
RB_StencilShadowPass

Stencil test should already be enabled, and the stencil buffer should have
been set to 128 on any surfaces that might receive shadows
=====================
*/
void RB_StencilShadowPass( const drawSurf_t *drawSurfs ) {
   if ( !r_shadows.GetBool() ) {
      return;
   }

   if ( !drawSurfs ) {
      return;
   }

   RB_LogComment( "---------- RB_StencilShadowPass ----------\n" );

   globalImages->BindNull();
   qglDisableClientState( GL_TEXTURE_COORD_ARRAY );

   // for visualizing the shadows
   if ( r_showShadows.GetInteger() ) {
      if ( r_showShadows.GetInteger() == 2 ) {
         // draw filled in
         GL_State( GLS_DEPTHMASK | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_LESS  );
      } else {
         // draw as lines, filling the depth buffer
         GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_POLYMODE_LINE | GLS_DEPTHFUNC_ALWAYS  );
      }
   } else {
      // don't write to the color buffer, just the stencil buffer
      GL_State( GLS_DEPTHMASK | GLS_COLORMASK | GLS_ALPHAMASK | GLS_DEPTHFUNC_LESS );
   }

   if ( r_shadowPolygonFactor.GetFloat() || r_shadowPolygonOffset.GetFloat() ) {
      qglPolygonOffset( r_shadowPolygonFactor.GetFloat(), -r_shadowPolygonOffset.GetFloat() );
      qglEnable( GL_POLYGON_OFFSET_FILL );
   }
   qglStencilFunc( GL_ALWAYS, 1, 255 );

   if ( glConfig.depthBoundsTestAvailable && r_useDepthBoundsTest.GetBool() ) {
      qglEnable( GL_DEPTH_BOUNDS_TEST_EXT );
   }

   // LEITH: enable two sided stencil ops (not if using OpenGL2 !!!)
   if ( glConfig.twoSidedStencilAvailable && r_useTwoSidedStencil.GetBool() && glConfig.glVersion < 2.0 ) {
      qglEnable( GL_STENCIL_TEST_TWO_SIDE_EXT );
   }

   // LEITH: enable depth clamp (not if using OpenGL2 !!!)
   // RECKLESS: use ARB depth clamp instead of NV only (breaks if using OpenGL2).
   if ( glConfig.depthClampAvailable && r_useDepthClamp.GetBool() && glConfig.glVersion < 2.0 ) {
      qglEnable( GL_DEPTH_CLAMP );
   }
   RB_RenderDrawSurfChainWithFunction( drawSurfs, RB_T_Shadow );

   GL_Cull( CT_FRONT_SIDED );

   if ( r_shadowPolygonFactor.GetFloat() || r_shadowPolygonOffset.GetFloat() ) {
      qglDisable( GL_POLYGON_OFFSET_FILL );
   }

   if ( glConfig.depthBoundsTestAvailable && r_useDepthBoundsTest.GetBool() ) {
      qglDisable( GL_DEPTH_BOUNDS_TEST_EXT );
   }

   // LEITH: disable depth clamp
   if ( glConfig.depthClampAvailable && r_useDepthClamp.GetBool() && glConfig.glVersion < 2.0 ) {
      qglDisable( GL_DEPTH_CLAMP );
   }
   qglEnableClientState( GL_TEXTURE_COORD_ARRAY );

   qglStencilFunc( GL_GEQUAL, 128, 255 );
   qglStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
}


and in RenderSystem_init.cpp

Code: Select all
/*
==================
R_CheckPortableExtensions

==================
*/
static void R_CheckPortableExtensions( void ) {
   glConfig.glVersion = atof( glConfig.version_string );

   // GL_ARB_multitexture
   glConfig.multitextureAvailable = R_CheckExtension( "GL_ARB_multitexture" );
   if ( glConfig.multitextureAvailable ) {
      qglMultiTexCoord2fARB = (void(APIENTRY *)(GLenum, GLfloat, GLfloat))GLimp_ExtensionPointer( "glMultiTexCoord2fARB" );
      qglMultiTexCoord2fvARB = (void(APIENTRY *)(GLenum, GLfloat *))GLimp_ExtensionPointer( "glMultiTexCoord2fvARB" );
      qglActiveTextureARB = (void(APIENTRY *)(GLenum))GLimp_ExtensionPointer( "glActiveTextureARB" );
      qglClientActiveTextureARB = (void(APIENTRY *)(GLenum))GLimp_ExtensionPointer( "glClientActiveTextureARB" );
      qglGetIntegerv( GL_MAX_TEXTURE_UNITS_ARB, (GLint *)&glConfig.maxTextureUnits );
      if ( glConfig.maxTextureUnits > MAX_MULTITEXTURE_UNITS ) {
         glConfig.maxTextureUnits = MAX_MULTITEXTURE_UNITS;
      }
      if ( glConfig.maxTextureUnits < 2 ) {
         glConfig.multitextureAvailable = false;   // shouldn't ever happen
      }
      qglGetIntegerv( GL_MAX_TEXTURE_COORDS_ARB, (GLint *)&glConfig.maxTextureCoords );
      qglGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS_ARB, (GLint *)&glConfig.maxTextureImageUnits );
   }

   // GL_ARB_texture_env_combine
   glConfig.textureEnvCombineAvailable = R_CheckExtension( "GL_ARB_texture_env_combine" );

   // GL_ARB_texture_cube_map
   glConfig.cubeMapAvailable = R_CheckExtension( "GL_ARB_texture_cube_map" );

   // GL_ARB_texture_env_dot3
   glConfig.envDot3Available = R_CheckExtension( "GL_ARB_texture_env_dot3" );

   // GL_ARB_texture_env_add
   glConfig.textureEnvAddAvailable = R_CheckExtension( "GL_ARB_texture_env_add" );

   // GL_ARB_texture_non_power_of_two
   glConfig.textureNonPowerOfTwoAvailable = R_CheckExtension( "GL_ARB_texture_non_power_of_two" );

   // GL_ARB_texture_compression + GL_S3_s3tc
   // DRI drivers may have GL_ARB_texture_compression but no GL_EXT_texture_compression_s3tc
   if ( R_CheckExtension( "GL_ARB_texture_compression" ) && R_CheckExtension( "GL_EXT_texture_compression_s3tc" ) ) {
      glConfig.textureCompressionAvailable = true;
      qglCompressedTexImage2DARB = (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)GLimp_ExtensionPointer( "glCompressedTexImage2DARB" );
      qglGetCompressedTexImageARB = (PFNGLGETCOMPRESSEDTEXIMAGEARBPROC)GLimp_ExtensionPointer( "glGetCompressedTexImageARB" );
   } else {
      glConfig.textureCompressionAvailable = false;
   }

   // GL_EXT_texture_filter_anisotropic
   glConfig.anisotropicAvailable = R_CheckExtension( "GL_EXT_texture_filter_anisotropic" );
   if ( glConfig.anisotropicAvailable ) {
      qglGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glConfig.maxTextureAnisotropy );
      common->Printf( "   maxTextureAnisotropy: %f\n", glConfig.maxTextureAnisotropy );
   } else {
      glConfig.maxTextureAnisotropy = 1;
   }

   // GL_EXT_texture_lod_bias
   // The actual extension is broken as specificed, storing the state in the texture unit instead
   // of the texture object.  The behavior in GL 1.4 is the behavior we use.
   if ( glConfig.glVersion >= 1.4 || R_CheckExtension( "GL_EXT_texture_lod" ) ) {
      common->Printf( "...using %s\n", "GL_1.4_texture_lod_bias" );
      glConfig.textureLODBiasAvailable = true;
   } else {
      common->Printf( "X..%s not found\n", "GL_1.4_texture_lod_bias" );
      glConfig.textureLODBiasAvailable = false;
   }

   // GL_EXT_shared_texture_palette
   glConfig.sharedTexturePaletteAvailable = R_CheckExtension( "GL_EXT_shared_texture_palette" );
   if ( glConfig.sharedTexturePaletteAvailable ) {
      qglColorTableEXT = ( void ( APIENTRY * ) ( int, int, int, int, int, const void * ) ) GLimp_ExtensionPointer( "glColorTableEXT" );
   }

   // GL_EXT_texture3D (not currently used for anything)
   glConfig.texture3DAvailable = R_CheckExtension( "GL_EXT_texture3D" );
   if ( glConfig.texture3DAvailable ) {
      qglTexImage3D =
         (void (APIENTRY *)(GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *) )
         GLimp_ExtensionPointer( "glTexImage3D" );
   }

   // EXT_stencil_wrap
   // This isn't very important, but some pathological case might cause a clamp error and give a shadow bug.
   // Nvidia also believes that future hardware may be able to run faster with this enabled to avoid the
   // serialization of clamping.
   if ( R_CheckExtension( "GL_EXT_stencil_wrap" ) ) {
      tr.stencilIncr = GL_INCR_WRAP_EXT;
      tr.stencilDecr = GL_DECR_WRAP_EXT;
   } else {
      tr.stencilIncr = GL_INCR;
      tr.stencilDecr = GL_DECR;
   }

   // GL_NV_register_combiners
   glConfig.registerCombinersAvailable = R_CheckExtension( "GL_NV_register_combiners" );
   if ( glConfig.registerCombinersAvailable ) {
      qglCombinerParameterfvNV = (void (APIENTRY *)( GLenum pname, const GLfloat *params ))
         GLimp_ExtensionPointer( "glCombinerParameterfvNV" );
      qglCombinerParameterivNV = (void (APIENTRY *)( GLenum pname, const GLint *params ))
         GLimp_ExtensionPointer( "glCombinerParameterivNV" );
      qglCombinerParameterfNV = (void (APIENTRY *)( GLenum pname, const GLfloat param ))
         GLimp_ExtensionPointer( "glCombinerParameterfNV" );
      qglCombinerParameteriNV = (void (APIENTRY *)( GLenum pname, const GLint param ))
         GLimp_ExtensionPointer( "glCombinerParameteriNV" );
      qglCombinerInputNV = (void (APIENTRY *)( GLenum stage, GLenum portion, GLenum variable, GLenum input,
                                      GLenum mapping, GLenum componentUsage ))
         GLimp_ExtensionPointer( "glCombinerInputNV" );
      qglCombinerOutputNV = (void (APIENTRY *)( GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput,
                                       GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct,
                                       GLboolean cdDotProduct, GLboolean muxSum ))
         GLimp_ExtensionPointer( "glCombinerOutputNV" );
      qglFinalCombinerInputNV = (void (APIENTRY *)( GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage ))
         GLimp_ExtensionPointer( "glFinalCombinerInputNV" );
   }

   // GL_EXT_stencil_two_side
   glConfig.twoSidedStencilAvailable = R_CheckExtension( "GL_EXT_stencil_two_side" );
   if ( glConfig.twoSidedStencilAvailable && glConfig.glVersion >= 2.0) {
      qglStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)GLimp_ExtensionPointer ("glStencilOpSeparate");
   } else if ( glConfig.twoSidedStencilAvailable &&  glConfig.glVersion) {
      qglActiveStencilFaceEXT = (PFNGLACTIVESTENCILFACEEXTPROC)GLimp_ExtensionPointer( "glActiveStencilFaceEXT" );
   } else {
      glConfig.atiTwoSidedStencilAvailable = R_CheckExtension( "GL_ATI_separate_stencil" );
      if ( glConfig.atiTwoSidedStencilAvailable ) {
         qglStencilFuncSeparateATI  = (PFNGLSTENCILFUNCSEPARATEATIPROC)GLimp_ExtensionPointer( "glStencilFuncSeparateATI" );
         qglStencilOpSeparateATI = (PFNGLSTENCILOPSEPARATEATIPROC)GLimp_ExtensionPointer( "glStencilOpSeparateATI" );
      }
   }

   // GL_ATI_fragment_shader
   glConfig.atiFragmentShaderAvailable = R_CheckExtension( "GL_ATI_fragment_shader" );
   if (! glConfig.atiFragmentShaderAvailable ) {
      // only on OSX: ATI_fragment_shader is faked through ATI_text_fragment_shader (macosx_glimp.cpp)
      glConfig.atiFragmentShaderAvailable = R_CheckExtension( "GL_ATI_text_fragment_shader" );
   }
   if ( glConfig.atiFragmentShaderAvailable ) {
      qglGenFragmentShadersATI = (PFNGLGENFRAGMENTSHADERSATIPROC)GLimp_ExtensionPointer( "glGenFragmentShadersATI" );
      qglBindFragmentShaderATI = (PFNGLBINDFRAGMENTSHADERATIPROC)GLimp_ExtensionPointer( "glBindFragmentShaderATI" );
      qglDeleteFragmentShaderATI = (PFNGLDELETEFRAGMENTSHADERATIPROC)GLimp_ExtensionPointer( "glDeleteFragmentShaderATI" );
      qglBeginFragmentShaderATI = (PFNGLBEGINFRAGMENTSHADERATIPROC)GLimp_ExtensionPointer( "glBeginFragmentShaderATI" );
      qglEndFragmentShaderATI = (PFNGLENDFRAGMENTSHADERATIPROC)GLimp_ExtensionPointer( "glEndFragmentShaderATI" );
      qglPassTexCoordATI = (PFNGLPASSTEXCOORDATIPROC)GLimp_ExtensionPointer( "glPassTexCoordATI" );
      qglSampleMapATI = (PFNGLSAMPLEMAPATIPROC)GLimp_ExtensionPointer( "glSampleMapATI" );
      qglColorFragmentOp1ATI = (PFNGLCOLORFRAGMENTOP1ATIPROC)GLimp_ExtensionPointer( "glColorFragmentOp1ATI" );
      qglColorFragmentOp2ATI = (PFNGLCOLORFRAGMENTOP2ATIPROC)GLimp_ExtensionPointer( "glColorFragmentOp2ATI" );
      qglColorFragmentOp3ATI = (PFNGLCOLORFRAGMENTOP3ATIPROC)GLimp_ExtensionPointer( "glColorFragmentOp3ATI" );
      qglAlphaFragmentOp1ATI = (PFNGLALPHAFRAGMENTOP1ATIPROC)GLimp_ExtensionPointer( "glAlphaFragmentOp1ATI" );
      qglAlphaFragmentOp2ATI = (PFNGLALPHAFRAGMENTOP2ATIPROC)GLimp_ExtensionPointer( "glAlphaFragmentOp2ATI" );
      qglAlphaFragmentOp3ATI = (PFNGLALPHAFRAGMENTOP3ATIPROC)GLimp_ExtensionPointer( "glAlphaFragmentOp3ATI" );
      qglSetFragmentShaderConstantATI = (PFNGLSETFRAGMENTSHADERCONSTANTATIPROC)GLimp_ExtensionPointer( "glSetFragmentShaderConstantATI" );
   }

   // ARB_vertex_buffer_object
   glConfig.ARBVertexBufferObjectAvailable = R_CheckExtension( "GL_ARB_vertex_buffer_object" );
   if(glConfig.ARBVertexBufferObjectAvailable) {
      qglBindBufferARB = (PFNGLBINDBUFFERARBPROC)GLimp_ExtensionPointer( "glBindBufferARB");
      qglDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)GLimp_ExtensionPointer( "glDeleteBuffersARB");
      qglGenBuffersARB = (PFNGLGENBUFFERSARBPROC)GLimp_ExtensionPointer( "glGenBuffersARB");
      qglIsBufferARB = (PFNGLISBUFFERARBPROC)GLimp_ExtensionPointer( "glIsBufferARB");
      qglBufferDataARB = (PFNGLBUFFERDATAARBPROC)GLimp_ExtensionPointer( "glBufferDataARB");
      qglBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC)GLimp_ExtensionPointer( "glBufferSubDataARB");
      qglGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC)GLimp_ExtensionPointer( "glGetBufferSubDataARB");
      qglMapBufferARB = (PFNGLMAPBUFFERARBPROC)GLimp_ExtensionPointer( "glMapBufferARB");
      qglUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC)GLimp_ExtensionPointer( "glUnmapBufferARB");
      qglGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC)GLimp_ExtensionPointer( "glGetBufferParameterivARB");
      qglGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC)GLimp_ExtensionPointer( "glGetBufferPointervARB");
   }

   // ARB_vertex_program
   glConfig.ARBVertexProgramAvailable = R_CheckExtension( "GL_ARB_vertex_program" );
   if (glConfig.ARBVertexProgramAvailable) {
      qglVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC)GLimp_ExtensionPointer( "glVertexAttribPointerARB" );
      qglEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC)GLimp_ExtensionPointer( "glEnableVertexAttribArrayARB" );
      qglDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)GLimp_ExtensionPointer( "glDisableVertexAttribArrayARB" );
      qglProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC)GLimp_ExtensionPointer( "glProgramStringARB" );
      qglBindProgramARB = (PFNGLBINDPROGRAMARBPROC)GLimp_ExtensionPointer( "glBindProgramARB" );
      qglGenProgramsARB = (PFNGLGENPROGRAMSARBPROC)GLimp_ExtensionPointer( "glGenProgramsARB" );
      qglProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC)GLimp_ExtensionPointer( "glProgramEnvParameter4fvARB" );
      qglProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)GLimp_ExtensionPointer( "glProgramLocalParameter4fvARB" );
   }

   // ARB_fragment_program
   if ( r_inhibitFragmentProgram.GetBool() ) {
      glConfig.ARBFragmentProgramAvailable = false;
   } else {
      glConfig.ARBFragmentProgramAvailable = R_CheckExtension( "GL_ARB_fragment_program" );
      if (glConfig.ARBFragmentProgramAvailable) {
         // these are the same as ARB_vertex_program
         qglProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC)GLimp_ExtensionPointer( "glProgramStringARB" );
         qglBindProgramARB = (PFNGLBINDPROGRAMARBPROC)GLimp_ExtensionPointer( "glBindProgramARB" );
         qglProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC)GLimp_ExtensionPointer( "glProgramEnvParameter4fvARB" );
         qglProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)GLimp_ExtensionPointer( "glProgramLocalParameter4fvARB" );
      }
   }

   // check for minimum set
   if ( !glConfig.multitextureAvailable || !glConfig.textureEnvCombineAvailable || !glConfig.cubeMapAvailable || !glConfig.envDot3Available ) {
         common->Error( common->GetLanguageDict()->GetString( "#str_06780" ) );
   }

    // GL_EXT_depth_bounds_test
    glConfig.depthBoundsTestAvailable = R_CheckExtension( "EXT_depth_bounds_test" );
    if ( glConfig.depthBoundsTestAvailable ) {
       qglDepthBoundsEXT = (PFNGLDEPTHBOUNDSEXTPROC)GLimp_ExtensionPointer( "glDepthBoundsEXT" );
    }

   // LEITH: GL_NV_depth_clamp
   glConfig.depthClampAvailable = R_CheckExtension( "NV_depth_clamp" );
}


now get the latest glext.h and wglext.h from the opengl site and replace the ones in the renderer folder.

in RenderSystem.h replace this ->

Code: Select all
// Contains variables specific to the OpenGL configuration being run right now.
// These are constant once the OpenGL subsystem is initialized.
typedef struct glconfig_s {
   const char         *renderer_string;
   const char         *vendor_string;
   const char         *version_string;
   const char         *extensions_string;
   const char         *wgl_extensions_string;

   float            glVersion;            // atof( version_string )


   int               maxTextureSize;         // queried from GL
   int               maxTextureUnits;
   int               maxTextureCoords;
   int               maxTextureImageUnits;
   float            maxTextureAnisotropy;

   int               colorBits, depthBits, stencilBits;

   bool            multitextureAvailable;
   bool            textureCompressionAvailable;
   bool            anisotropicAvailable;
   bool            textureLODBiasAvailable;
   bool            textureEnvAddAvailable;
   bool            textureEnvCombineAvailable;
   bool            registerCombinersAvailable;
   bool            cubeMapAvailable;
   bool            envDot3Available;
   bool            texture3DAvailable;
   bool            sharedTexturePaletteAvailable;
   bool            ARBVertexBufferObjectAvailable;
   bool            ARBVertexProgramAvailable;
   bool            ARBFragmentProgramAvailable;
   bool            twoSidedStencilAvailable;
   bool            textureNonPowerOfTwoAvailable;
   bool            depthBoundsTestAvailable;
   bool            depthClampAvailable;

   // ati r200 extensions
   bool            atiFragmentShaderAvailable;

   // ati r300
   bool            atiTwoSidedStencilAvailable;

   int               vidWidth, vidHeight;   // passed to R_BeginFrame

   int               displayFrequency;

   bool            isFullscreen;

   bool            allowNV30Path;
   bool            allowNV20Path;
   bool            allowNV10Path;
   bool            allowR200Path;
   bool            allowARB2Path;

   bool            isInitialized;
} glconfig_t;


and put this in RenderSystem_init.cpp at the top with the other cvars

Code: Select all
idCVar r_useTwoSidedStencil( "r_useTwoSidedStencil", "1", CVAR_RENDERER | CVAR_BOOL, "do stencil shadows in one pass with different ops on each side" );
idCVar r_useDepthClamp( "r_useDepthClamp", "1", CVAR_RENDERER | CVAR_BOOL, "use depth clamp to remove near and far clip planes" );


and in tr_local.h

Code: Select all
extern idCVar r_useTwoSidedStencil;      // 1 = do stencil shadows in one pass with different ops on each side
extern idCVar r_useDepthClamp;         // use depth clamp to remove near and far clip planes


bingo youre done :)

Image
Productivity is a state of mind.
User avatar
revelator
 
Posts: 2567
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: Doom 3 engine release and game code

Postby revelator » Fri Dec 30, 2011 11:29 pm

guess peeps are busy with newyear :)
Productivity is a state of mind.
User avatar
revelator
 
Posts: 2567
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: Doom 3 engine release and game code

Postby leileilol » Sat Dec 31, 2011 11:05 pm

I don't even own Doom 3 anymore. I would have tried this
i should not be here
leileilol
 
Posts: 2783
Joined: Fri Oct 15, 2004 3:23 am

Re: Doom 3 engine release and game code

Postby revelator » Sun Jan 01, 2012 7:16 am

aw :(

well i refined the code some more ill post changes later :)
Productivity is a state of mind.
User avatar
revelator
 
Posts: 2567
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: Doom 3 engine release and game code

Postby New Horizon » Sun Jan 01, 2012 9:31 pm

reckless wrote:aw :(

well i refined the code some more ill post changes later :)


Hi reckless. I'm going to try this out with our mod "The Dark Mod" and let you know how it works.

Should I expect this to give back the performance lost with the removal of Carmack's Reverse?
New Horizon
 
Posts: 6
Joined: Sat Nov 26, 2011 3:24 am

PreviousNext

Return to General Programming

Who is online

Users browsing this forum: No registered users and 1 guest