void Pass::setup(GLRenderer *) { vec4_t ambient = { sunLight.ambient[0] * 0.8, sunLight.ambient[1] * 0.8, sunLight.ambient[2] * 0.95, 1 }; GLSL_reset(); shader = NULL; lightCount = 0; glPushAttrib(attrib_bits); //GL_Enable(GL_SCISSOR_TEST); GL_SwitchTexUnit(GL_TEXTURE0_ARB); //defaults for pass GL_Enable(GL_BLEND); GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); GL_Enable(GL_CULL_FACE); GL_Enable(GL_ALPHA_TEST); //glAlphaFunc(GL_GREATER, 0.0); GL_ResetColor(); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); //enable the lights for this pass by default if(allowLighting()) { if(gfx_GLSLQuality.integer <= 1) M_MultVec3(ambient, 1.5, ambient); GL_Enable(GL_LIGHTING); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, true); glShadeModel(GL_SMOOTH); } //GL_Enable(GL_NORMALIZE); //framebuffer if(gfx_postProcessing.integer) { if(!target) target = glScreen; target->makeTarget(); } else { glScreen->makeTarget(); } //depth GL_Enable(GL_DEPTH_TEST); GL_DepthMask(depthMask); GL_DepthFunc(depthFunc); if(preclearDepth) { glClearDepth(1.0); glClear(GL_DEPTH_BUFFER_BIT); } if(viewer) { vec4_t rect; //FIXME: probably should be a data member for configurable pass "windows" SET_VEC4(rect, 0, 0, viewer->width, viewer->height); Scene_SetFrustum(viewer, rect); Scene_BuildOccluderList(viewer); if(gfx_debugCamera.integer>0) { camera_t debugcam; vec3_t back; M_MultVec3(viewer->viewaxis[AXIS_FORWARD], -gfx_debugCamera.integer, back); memcpy(&debugcam, viewer, sizeof(camera_t)); M_AddVec3(debugcam.origin, back, debugcam.origin); GL_PushCamera(&debugcam); } else { GL_PushCamera(viewer); //scene_cam = viewer; } //fog if (viewer->fog_far > 0 && gfx_fog.integer) { vec4_t fog_color = { gfx_fogr.value, gfx_fogg.value, gfx_fogb.value, 0 }; GL_Enable(GL_FOG); if(gfx_nicerFog.integer) { glFogf(GL_FOG_MODE, GL_EXP2); glFogf(GL_FOG_DENSITY, 1.5 / viewer->fog_far); // Notaus: old value was fixed at 0.00072 and not appropriate for very foggy maps } else { glFogf(GL_FOG_MODE, GL_LINEAR); } glHint(GL_FOG_HINT, GL_NICEST); if (viewer->fog_near > 0 && viewer->fog_far >= viewer->fog_near) { glFogf(GL_FOG_START, viewer->fog_near); glFogf(GL_FOG_END, viewer->fog_far); fog_near = viewer->fog_near; fog_far = viewer->fog_far; } else { glFogf(GL_FOG_START, gfx_fog_near.value); glFogf(GL_FOG_END, gfx_fog_far.value); fog_near = gfx_fog_near.value; fog_far = gfx_fog_far.value; } glFogfv(GL_FOG_COLOR, fog_color); } else if (gfx_fog.integer==0) { GL_Enable(GL_FOG); glFogf(GL_FOG_START, 90000); glFogf(GL_FOG_END, 100000); //shaders make it better just to set this ridiculously far out } else { GL_Disable(GL_FOG); } } else { GL_Disable(GL_FOG); } if(gfx_GLSL.integer) Cvar_SetVarValue(&gfx_GLSLPass, 1); else GL_TexModulate(2.0); #ifdef DEBUG GLSL_catchLastError("Pass::setup()"); #endif }
/** * @brief This routine is responsible for setting the most commonly changed state in Q3. */ void GL_State(uint32_t stateBits) { uint32_t diff = stateBits ^ glState.glStateBits; if (!diff) { return; } // check depthFunc bits if (diff & GLS_DEPTHFUNC_BITS) { switch (stateBits & GLS_DEPTHFUNC_BITS) { default: GL_DepthFunc(GL_LEQUAL); break; case GLS_DEPTHFUNC_LESS: GL_DepthFunc(GL_LESS); break; case GLS_DEPTHFUNC_EQUAL: GL_DepthFunc(GL_EQUAL); break; } } // check blend bits if (diff & (GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS)) { GLenum srcFactor, dstFactor; if (stateBits & (GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS)) { switch (stateBits & GLS_SRCBLEND_BITS) { case GLS_SRCBLEND_ZERO: srcFactor = GL_ZERO; break; case GLS_SRCBLEND_ONE: srcFactor = GL_ONE; break; case GLS_SRCBLEND_DST_COLOR: srcFactor = GL_DST_COLOR; break; case GLS_SRCBLEND_ONE_MINUS_DST_COLOR: srcFactor = GL_ONE_MINUS_DST_COLOR; break; case GLS_SRCBLEND_SRC_ALPHA: srcFactor = GL_SRC_ALPHA; break; case GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA: srcFactor = GL_ONE_MINUS_SRC_ALPHA; break; case GLS_SRCBLEND_DST_ALPHA: srcFactor = GL_DST_ALPHA; break; case GLS_SRCBLEND_ONE_MINUS_DST_ALPHA: srcFactor = GL_ONE_MINUS_DST_ALPHA; break; case GLS_SRCBLEND_ALPHA_SATURATE: srcFactor = GL_SRC_ALPHA_SATURATE; break; default: srcFactor = GL_ONE; // to get warning to shut up Ren_Drop("GL_State: invalid src blend state bits\n"); break; } switch (stateBits & GLS_DSTBLEND_BITS) { case GLS_DSTBLEND_ZERO: dstFactor = GL_ZERO; break; case GLS_DSTBLEND_ONE: dstFactor = GL_ONE; break; case GLS_DSTBLEND_SRC_COLOR: dstFactor = GL_SRC_COLOR; break; case GLS_DSTBLEND_ONE_MINUS_SRC_COLOR: dstFactor = GL_ONE_MINUS_SRC_COLOR; break; case GLS_DSTBLEND_SRC_ALPHA: dstFactor = GL_SRC_ALPHA; break; case GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA: dstFactor = GL_ONE_MINUS_SRC_ALPHA; break; case GLS_DSTBLEND_DST_ALPHA: dstFactor = GL_DST_ALPHA; break; case GLS_DSTBLEND_ONE_MINUS_DST_ALPHA: dstFactor = GL_ONE_MINUS_DST_ALPHA; break; default: dstFactor = GL_ONE; // to get warning to shut up Ren_Drop("GL_State: invalid dst blend state bits\n"); break; } glEnable(GL_BLEND); GL_BlendFunc(srcFactor, dstFactor); } else { glDisable(GL_BLEND); } } // check colormask if (diff & GLS_COLORMASK_BITS) { if (stateBits & GLS_COLORMASK_BITS) { GL_ColorMask((stateBits & GLS_REDMASK_FALSE) ? GL_FALSE : GL_TRUE, (stateBits & GLS_GREENMASK_FALSE) ? GL_FALSE : GL_TRUE, (stateBits & GLS_BLUEMASK_FALSE) ? GL_FALSE : GL_TRUE, (stateBits & GLS_ALPHAMASK_FALSE) ? GL_FALSE : GL_TRUE); } else { GL_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } } // check depthmask if (diff & GLS_DEPTHMASK_TRUE) { if (stateBits & GLS_DEPTHMASK_TRUE) { GL_DepthMask(GL_TRUE); } else { GL_DepthMask(GL_FALSE); } } // fill/line mode if (diff & GLS_POLYMODE_LINE) { if (stateBits & GLS_POLYMODE_LINE) { GL_PolygonMode(GL_FRONT_AND_BACK, GL_LINE); } else { GL_PolygonMode(GL_FRONT_AND_BACK, GL_FILL); } } // depthtest if (diff & GLS_DEPTHTEST_DISABLE) { if (stateBits & GLS_DEPTHTEST_DISABLE) { glDisable(GL_DEPTH_TEST); } else { glEnable(GL_DEPTH_TEST); } } // alpha test - deprecated in OpenGL 3.0 #if 0 if (diff & GLS_ATEST_BITS) { switch (stateBits & GLS_ATEST_BITS) { case GLS_ATEST_GT_0: case GLS_ATEST_LT_128: case GLS_ATEST_GE_128: //case GLS_ATEST_GT_CUSTOM: glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE); break; default: case 0: glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); break; } } #endif /* if(diff & GLS_ATEST_BITS) { switch (stateBits & GLS_ATEST_BITS) { case 0: glDisable(GL_ALPHA_TEST); break; case GLS_ATEST_GT_0: glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.0f); break; case GLS_ATEST_LT_80: glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_LESS, 0.5f); break; case GLS_ATEST_GE_80: glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GEQUAL, 0.5f); break; case GLS_ATEST_GT_CUSTOM: // FIXME glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.5f); break; default: assert(0); break; } } */ // stenciltest if (diff & GLS_STENCILTEST_ENABLE) { if (stateBits & GLS_STENCILTEST_ENABLE) { glEnable(GL_STENCIL_TEST); } else { glDisable(GL_STENCIL_TEST); } } glState.glStateBits = stateBits; }
/* ============= R_DrawAliasVolumeShadow based on code from BeefQuake R6 ============= */ void R_DrawAliasVolumeShadow (maliasmodel_t *paliashdr, vec3_t bbox[8]) { vec3_t light, temp, vecAdd; float dist, highest, lowest, projected_distance; float angle, cosp, sinp, cosy, siny, cosr, sinr, ix, iy, iz; int i, lnum; dlight_t *dl; dl = r_newrefdef.dlights; VectorSet(vecAdd, 680,0,1024); // set base vector, was 576,0,1024 // compute average light vector from dlights for (i=0, lnum=0; i<r_newrefdef.num_dlights; i++, dl++) { if (VectorCompare(dl->origin, currententity->origin)) continue; VectorSubtract(dl->origin, currententity->origin, temp); dist = dl->intensity - VectorLength(temp); if (dist <= 0) continue; lnum++; // Factor in the intensity of a dlight VectorScale (temp, dist*0.25, temp); VectorAdd (vecAdd, temp, vecAdd); } VectorNormalize(vecAdd); VectorScale(vecAdd, 1024, vecAdd); // get projection distance from lightspot height highest = lowest = bbox[0][2]; for (i=0; i<8; i++) { if (bbox[i][2] > highest) highest = bbox[i][2]; if (bbox[i][2] < lowest) lowest = bbox[i][2]; } projected_distance = (fabs(highest - lightspot[2]) + (highest-lowest)) / vecAdd[2]; VectorCopy(vecAdd, light); /*cosy = cos(-currententity->angles[YAW] / 180 * M_PI); siny = sin(-currententity->angles[YAW] / 180 * M_PI); ix = light[0], iy = light[1]; light[0] = (cosy * (ix - 0) + siny * (0 - iy) + 0); light[1] = (cosy * (iy - 0) + siny * (ix - 0) + 0); light[2] += 8;*/ // reverse-rotate light vector based on angles angle = -currententity->angles[PITCH] / 180 * M_PI; cosp = cos(angle), sinp = sin(angle); angle = -currententity->angles[YAW] / 180 * M_PI; cosy = cos(angle), siny = sin(angle); angle = currententity->angles[ROLL] / 180 * M_PI; // roll is backwards cosr = cos(angle), sinr = sin(angle); // rotate for yaw (z axis) ix = light[0], iy = light[1]; light[0] = cosy * ix - siny * iy + 0; light[1] = siny * ix + cosy * iy + 0; // rotate for pitch (y axis) ix = light[0], iz = light[2]; light[0] = cosp * ix + 0 + sinp * iz; light[2] = -sinp * ix + 0 + cosp * iz; // rotate for roll (x axis) iy = light[1], iz = light[2]; light[1] = 0 + cosr * iy - sinr * iz; light[2] = 0 + sinr * iy + cosr * iz; // set up stenciling if (!r_shadowvolumes->value) { qglPushAttrib(GL_STENCIL_BUFFER_BIT); // save stencil buffer qglClear(GL_STENCIL_BUFFER_BIT); qglColorMask(0,0,0,0); GL_DepthMask(0); GL_DepthFunc(GL_LESS); GL_Enable(GL_STENCIL_TEST); qglStencilFunc(GL_ALWAYS, 0, 255); // qglStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); // qglStencilMask (255); } // build shadow volumes and render each to stencil buffer for (i=0; i<paliashdr->num_meshes; i++) { if (paliashdr->meshes[i].skins[currententity->skinnum].renderparms.nodraw || paliashdr->meshes[i].skins[currententity->skinnum].renderparms.alphatest || paliashdr->meshes[i].skins[currententity->skinnum].renderparms.noshadow) continue; R_BuildShadowVolume (paliashdr, i, light, projected_distance, r_shadowvolumes->value); GL_LockArrays (shadow_va); if (!r_shadowvolumes->value) { if (gl_config.atiSeparateStencil && gl_config.extStencilWrap) // Barnes ATI stenciling { GL_Disable(GL_CULL_FACE); qglStencilOpSeparateATI (GL_BACK, GL_KEEP, GL_INCR_WRAP_EXT, GL_KEEP); qglStencilOpSeparateATI (GL_FRONT, GL_KEEP, GL_DECR_WRAP_EXT, GL_KEEP); R_DrawShadowVolume (); GL_Enable(GL_CULL_FACE); } else if (gl_config.extStencilTwoSide && gl_config.extStencilWrap) // Echon's two-sided stenciling { GL_Disable(GL_CULL_FACE); qglEnable (GL_STENCIL_TEST_TWO_SIDE_EXT); qglActiveStencilFaceEXT (GL_BACK); qglStencilOp (GL_KEEP, GL_INCR_WRAP_EXT, GL_KEEP); qglActiveStencilFaceEXT (GL_FRONT); qglStencilOp (GL_KEEP, GL_DECR_WRAP_EXT, GL_KEEP); R_DrawShadowVolume (); qglDisable (GL_STENCIL_TEST_TWO_SIDE_EXT); GL_Enable(GL_CULL_FACE); } else { // increment stencil if backface is behind depthbuffer GL_CullFace(GL_BACK); // quake is backwards, this culls front faces qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP); R_DrawShadowVolume (); // decrement stencil if frontface is behind depthbuffer GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP); R_DrawShadowVolume (); } } else R_DrawShadowVolume (); GL_UnlockArrays (); } // end stenciling and draw stenciled volume if (!r_shadowvolumes->value) { GL_CullFace(GL_FRONT); GL_Disable(GL_STENCIL_TEST); GL_DepthFunc(GL_LEQUAL); GL_DepthMask(1); qglColorMask(1,1,1,1); // draw shadows for this model now R_ShadowBlend (aliasShadowAlpha * currententity->alpha); // was r_shadowalpha->value qglPopAttrib(); // restore stencil buffer } }