Doom 3 engine release and game code
Moderator: InsideQC Admins
Re: Doom 3 engine release and game code
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
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
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.
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
We knew the words, we knew the score, we knew what we were fighting for
-

mh - Posts: 2292
- Joined: Sat Jan 12, 2008 1:38 am
Re: Doom 3 engine release and game code
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?
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... )
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
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.
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
We knew the words, we knew the score, we knew what we were fighting for
-

mh - Posts: 2292
- Joined: Sat Jan 12, 2008 1:38 am
Re: Doom 3 engine release and game code
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.
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
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.
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
We knew the words, we knew the score, we knew what we were fighting for
-

mh - Posts: 2292
- Joined: Sat Jan 12, 2008 1:38 am
Re: Doom 3 engine release and game code
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.
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
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.
-

revelator - Posts: 2567
- Joined: Thu Jan 24, 2008 12:04 pm
- Location: inside tha debugger
Re: Doom 3 engine release and game code
- 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.
-

revelator - Posts: 2567
- Joined: Thu Jan 24, 2008 12:04 pm
- Location: inside tha debugger
Re: Doom 3 engine release and game code
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.
-

revelator - Posts: 2567
- Joined: Thu Jan 24, 2008 12:04 pm
- Location: inside tha debugger
Re: Doom 3 engine release and game code
ok here we go.
replace these functions in draw_common.cpp with the one i post below.
and in RenderSystem_init.cpp
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 ->
and put this in RenderSystem_init.cpp at the top with the other cvars
and in tr_local.h
bingo youre done

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

Productivity is a state of mind.
-

revelator - Posts: 2567
- Joined: Thu Jan 24, 2008 12:04 pm
- Location: inside tha debugger
Re: Doom 3 engine release and game code
guess peeps are busy with newyear 
Productivity is a state of mind.
-

revelator - Posts: 2567
- Joined: Thu Jan 24, 2008 12:04 pm
- Location: inside tha debugger
Re: Doom 3 engine release and game code
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
aw
well i refined the code some more ill post changes later
well i refined the code some more ill post changes later
Productivity is a state of mind.
-

revelator - Posts: 2567
- Joined: Thu Jan 24, 2008 12:04 pm
- Location: inside tha debugger
Re: Doom 3 engine release and game code
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
Who is online
Users browsing this forum: No registered users and 1 guest