/* ================== RB_RenderDrawSurfList ================== */ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { shader_t *shader, *oldShader; int fogNum, oldFogNum; int entityNum, oldEntityNum; int dlighted, oldDlighted; int pshadowed, oldPshadowed; int cubemapIndex, oldCubemapIndex; qboolean depthRange, oldDepthRange, isCrosshair, wasCrosshair; int i; drawSurf_t *drawSurf; int oldSort; float originalTime; FBO_t* fbo = NULL; qboolean inQuery = qfalse; float depth[2]; // save original time for entity shader offsets originalTime = backEnd.refdef.floatTime; fbo = glState.currentFBO; // draw everything oldEntityNum = -1; backEnd.currentEntity = &tr.worldEntity; oldShader = NULL; oldFogNum = -1; oldDepthRange = qfalse; wasCrosshair = qfalse; oldDlighted = qfalse; oldPshadowed = qfalse; oldCubemapIndex = -1; oldSort = -1; depth[0] = 0.f; depth[1] = 1.f; backEnd.pc.c_surfaces += numDrawSurfs; for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) { if ( drawSurf->sort == oldSort && drawSurf->cubemapIndex == oldCubemapIndex) { if (backEnd.depthFill && shader && shader->sort != SS_OPAQUE) continue; // fast path, same as previous sort rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); continue; } oldSort = drawSurf->sort; R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed ); cubemapIndex = drawSurf->cubemapIndex; // // change the tess parameters if needed // a "entityMergable" shader is a shader that can have surfaces from seperate // entities merged into a single batch, like smoke and blood puff sprites if ( shader != NULL && ( shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || pshadowed != oldPshadowed || cubemapIndex != oldCubemapIndex || ( entityNum != oldEntityNum && !shader->entityMergable ) ) ) { if (oldShader != NULL) { RB_EndSurface(); } RB_BeginSurface( shader, fogNum, cubemapIndex ); backEnd.pc.c_surfBatches++; oldShader = shader; oldFogNum = fogNum; oldDlighted = dlighted; oldPshadowed = pshadowed; oldCubemapIndex = cubemapIndex; } if (backEnd.depthFill && shader && shader->sort != SS_OPAQUE) continue; // // change the modelview matrix if needed // if ( entityNum != oldEntityNum ) { qboolean sunflare = qfalse; depthRange = isCrosshair = qfalse; if ( entityNum != REFENTITYNUM_WORLD ) { backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; // we have to reset the shaderTime as well otherwise image animations start // from the wrong frame tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; // set up the transformation matrix R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.or ); // set up the dynamic lighting if needed if ( backEnd.currentEntity->needDlights ) { R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); } if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK) { // hack the depth range to prevent view model from poking into walls depthRange = qtrue; if(backEnd.currentEntity->e.renderfx & RF_CROSSHAIR) isCrosshair = qtrue; } } else { backEnd.currentEntity = &tr.worldEntity; backEnd.refdef.floatTime = originalTime; backEnd.or = backEnd.viewParms.world; // we have to reset the shaderTime as well otherwise image animations on // the world (like water) continue with the wrong frame tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); } GL_SetModelviewMatrix( backEnd.or.modelMatrix ); // // change depthrange. Also change projection matrix so first person weapon does not look like coming // out of the screen. // if (oldDepthRange != depthRange || wasCrosshair != isCrosshair) { if (depthRange) { if(backEnd.viewParms.stereoFrame != STEREO_CENTER) { if(isCrosshair) { if(oldDepthRange) { // was not a crosshair but now is, change back proj matrix GL_SetProjectionMatrix( backEnd.viewParms.projectionMatrix ); } } else { viewParms_t temp = backEnd.viewParms; R_SetupProjection(&temp, r_znear->value, 0, qfalse); GL_SetProjectionMatrix( temp.projectionMatrix ); } } if(!oldDepthRange) { depth[0] = 0; depth[1] = 0.3f; qglDepthRange (depth[0], depth[1]); } } else { if(!wasCrosshair && backEnd.viewParms.stereoFrame != STEREO_CENTER) { GL_SetProjectionMatrix( backEnd.viewParms.projectionMatrix ); } if (!sunflare) qglDepthRange (0, 1); depth[0] = 0; depth[1] = 1; } oldDepthRange = depthRange; wasCrosshair = isCrosshair; } oldEntityNum = entityNum; } // add the triangles for this surface rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); } backEnd.refdef.floatTime = originalTime; // draw the contents of the last shader batch if (oldShader != NULL) { RB_EndSurface(); } if (inQuery) { qglEndQueryARB(GL_SAMPLES_PASSED_ARB); } if (glRefConfig.framebufferObject) FBO_Bind(fbo); // go back to the world modelview matrix GL_SetModelviewMatrix( backEnd.viewParms.world.modelMatrix ); qglDepthRange (0, 1); }
void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { shader_t *shader, *oldShader; int fogNum, oldFogNum; int entityNum, oldEntityNum; int dlighted, oldDlighted; int depthRange, oldDepthRange; int i; drawSurf_t *drawSurf; unsigned int oldSort; float originalTime; trRefEntity_t *curEnt; postRender_t *pRender; bool didShadowPass = false; #ifdef __MACOS__ int macEventTime; Sys_PumpEvents(); // crutch up the mac's limited buffer queue size // we don't want to pump the event loop too often and waste time, so // we are going to check every shader change macEventTime = ri.Milliseconds() + MAC_EVENT_PUMP_MSEC; #endif if (g_bRenderGlowingObjects) { //only shadow on initial passes didShadowPass = true; } // save original time for entity shader offsets originalTime = backEnd.refdef.floatTime; // clear the z buffer, set the modelview, etc RB_BeginDrawingView (); // draw everything oldEntityNum = -1; backEnd.currentEntity = &tr.worldEntity; oldShader = NULL; oldFogNum = -1; oldDepthRange = qfalse; oldDlighted = qfalse; oldSort = (unsigned int) -1; depthRange = qfalse; backEnd.pc.c_surfaces += numDrawSurfs; for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) { if ( drawSurf->sort == oldSort ) { // fast path, same as previous sort rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); continue; } R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted ); // If we're rendering glowing objects, but this shader has no stages with glow, skip it! if ( g_bRenderGlowingObjects && !shader->hasGlow ) { shader = oldShader; entityNum = oldEntityNum; fogNum = oldFogNum; dlighted = oldDlighted; continue; } oldSort = drawSurf->sort; // // change the tess parameters if needed // a "entityMergable" shader is a shader that can have surfaces from seperate // entities merged into a single batch, like smoke and blood puff sprites if (entityNum != TR_WORLDENT && g_numPostRenders < MAX_POST_RENDERS) { if ( (backEnd.refdef.entities[entityNum].e.renderfx & RF_DISTORTION)/* || (backEnd.refdef.entities[entityNum].e.renderfx & RF_FORCE_ENT_ALPHA)*/) //not sure if we need this alpha fix for sp or not, leaving it out for now -rww { //must render last curEnt = &backEnd.refdef.entities[entityNum]; pRender = &g_postRenders[g_numPostRenders]; g_numPostRenders++; depthRange = 0; //figure this stuff out now and store it if ( curEnt->e.renderfx & RF_NODEPTH ) { depthRange = 2; } else if ( curEnt->e.renderfx & RF_DEPTHHACK ) { depthRange = 1; } pRender->depthRange = depthRange; //It is not necessary to update the old* values because //we are not updating now with the current values. depthRange = oldDepthRange; //store off the ent num pRender->entNum = entityNum; //remember the other values necessary for rendering this surf pRender->drawSurf = drawSurf; pRender->dlighted = dlighted; pRender->fogNum = fogNum; pRender->shader = shader; //assure the info is back to the last set state shader = oldShader; entityNum = oldEntityNum; fogNum = oldFogNum; dlighted = oldDlighted; oldSort = (unsigned int)-1; //invalidate this thing, cause we may want to postrender more surfs of the same sort //continue without bothering to begin a draw surf continue; } } if (shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || ( entityNum != oldEntityNum && !shader->entityMergable ) ) { if (oldShader != NULL) { #ifdef __MACOS__ // crutch up the mac's limited buffer queue size int t; t = ri.Milliseconds(); if ( t > macEventTime ) { macEventTime = t + MAC_EVENT_PUMP_MSEC; Sys_PumpEvents(); } #endif RB_EndSurface(); if (!didShadowPass && shader && shader->sort > SS_BANNER) { RB_ShadowFinish(); didShadowPass = true; } } RB_BeginSurface( shader, fogNum ); oldShader = shader; oldFogNum = fogNum; oldDlighted = dlighted; } // // change the modelview matrix if needed // if ( entityNum != oldEntityNum ) { depthRange = qfalse; if ( entityNum != TR_WORLDENT ) { backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; // set up the transformation matrix R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.ori ); // set up the dynamic lighting if needed if ( backEnd.currentEntity->needDlights ) { #ifdef VV_LIGHTING VVLightMan.R_TransformDlights( &backEnd.ori ); #else R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.ori ); #endif } if ( backEnd.currentEntity->e.renderfx & RF_NODEPTH ) { // No depth at all, very rare but some things for seeing through walls depthRange = 2; } else if ( backEnd.currentEntity->e.renderfx & RF_DEPTHHACK ) { // hack the depth range to prevent view model from poking into walls depthRange = qtrue; } } else { backEnd.currentEntity = &tr.worldEntity; backEnd.refdef.floatTime = originalTime; backEnd.ori = backEnd.viewParms.world; #ifdef VV_LIGHTING VVLightMan.R_TransformDlights( &backEnd.ori ); #else R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.ori ); #endif } qglLoadMatrixf( backEnd.ori.modelMatrix ); // // change depthrange if needed // if ( oldDepthRange != depthRange ) { switch ( depthRange ) { default: case 0: qglDepthRange (0, 1); break; case 1: qglDepthRange (0, .3); break; case 2: qglDepthRange (0, 0); break; } oldDepthRange = depthRange; } oldEntityNum = entityNum; } // add the triangles for this surface rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); } // draw the contents of the last shader batch if (oldShader != NULL) { RB_EndSurface(); } if (tr_stencilled && tr_distortionPrePost) { //ok, cap it now RB_CaptureScreenImage(); RB_DistortionFill(); } //render distortion surfs (or anything else that needs to be post-rendered) if (g_numPostRenders > 0) { int lastPostEnt = -1; while (g_numPostRenders > 0) { g_numPostRenders--; pRender = &g_postRenders[g_numPostRenders]; RB_BeginSurface( pRender->shader, pRender->fogNum ); backEnd.currentEntity = &backEnd.refdef.entities[pRender->entNum]; backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; // set up the transformation matrix R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.ori ); // set up the dynamic lighting if needed if ( backEnd.currentEntity->needDlights ) { #ifdef VV_LIGHTING VVLightMan.R_TransformDlights( &backEnd.ori ); #else R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.ori ); #endif } qglLoadMatrixf( backEnd.ori.modelMatrix ); depthRange = pRender->depthRange; switch ( depthRange ) { default: case 0: qglDepthRange (0, 1); break; case 1: qglDepthRange (0, .3); break; case 2: qglDepthRange (0, 0); break; } if ((backEnd.currentEntity->e.renderfx & RF_DISTORTION) && lastPostEnt != pRender->entNum) { //do the capture now, we only need to do it once per ent int x, y; int rad = backEnd.currentEntity->e.radius; //We are going to just bind this, and then the CopyTexImage is going to //stomp over this texture num in texture memory. GL_Bind( tr.screenImage ); if (R_WorldCoordToScreenCoord( backEnd.currentEntity->e.origin, &x, &y )) { int cX, cY; cX = glConfig.vidWidth-x-(rad/2); cY = glConfig.vidHeight-y-(rad/2); if (cX+rad > glConfig.vidWidth) { //would it go off screen? cX = glConfig.vidWidth-rad; } else if (cX < 0) { //cap it off at 0 cX = 0; } if (cY+rad > glConfig.vidHeight) { //would it go off screen? cY = glConfig.vidHeight-rad; } else if (cY < 0) { //cap it off at 0 cY = 0; } //now copy a portion of the screen to this texture qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, cX, cY, rad, rad, 0); lastPostEnt = pRender->entNum; } } rb_surfaceTable[ *pRender->drawSurf->surface ]( pRender->drawSurf->surface ); RB_EndSurface(); } } // go back to the world modelview matrix qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); if ( depthRange ) { qglDepthRange (0, 1); } #if 0 RB_DrawSun(); #endif if (tr_stencilled && !tr_distortionPrePost) { //draw in the stencil buffer's cutout RB_DistortionFill(); } if (!didShadowPass) { // darken down any stencil shadows RB_ShadowFinish(); didShadowPass = true; } // add light flares on lights that aren't obscured // RB_RenderFlares(); #ifdef __MACOS__ Sys_PumpEvents(); // crutch up the mac's limited buffer queue size #endif }
void R_DrawAliasModel ( entity_t *e ) { int i; dmdl_t *paliashdr; float an; vec3_t bbox [ 8 ]; image_t *skin; if ( !( e->flags & RF_WEAPONMODEL ) ) { if ( R_CullAliasModel( bbox, e ) ) { return; } } if ( e->flags & RF_WEAPONMODEL ) { if ( gl_lefthand->value == 2 ) { return; } } paliashdr = (dmdl_t *) currentmodel->extradata; /* get lighting information */ if ( currententity->flags & ( RF_SHELL_HALF_DAM | RF_SHELL_GREEN | RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE ) ) { VectorClear( shadelight ); if ( currententity->flags & RF_SHELL_HALF_DAM ) { shadelight [ 0 ] = 0.56; shadelight [ 1 ] = 0.59; shadelight [ 2 ] = 0.45; } if ( currententity->flags & RF_SHELL_DOUBLE ) { shadelight [ 0 ] = 0.9; shadelight [ 1 ] = 0.7; } if ( currententity->flags & RF_SHELL_RED ) { shadelight [ 0 ] = 1.0; } if ( currententity->flags & RF_SHELL_GREEN ) { shadelight [ 1 ] = 1.0; } if ( currententity->flags & RF_SHELL_BLUE ) { shadelight [ 2 ] = 1.0; } } else if ( currententity->flags & RF_FULLBRIGHT ) { for ( i = 0; i < 3; i++ ) { shadelight [ i ] = 1.0; } } else { R_LightPoint( currententity->origin, shadelight ); /* player lighting hack for communication back to server */ if ( currententity->flags & RF_WEAPONMODEL ) { /* pick the greatest component, which should be the same as the mono value returned by software */ if ( shadelight [ 0 ] > shadelight [ 1 ] ) { if ( shadelight [ 0 ] > shadelight [ 2 ] ) { gl_lightlevel->value = 150 * shadelight [ 0 ]; } else { gl_lightlevel->value = 150 * shadelight [ 2 ]; } } else { if ( shadelight [ 1 ] > shadelight [ 2 ] ) { gl_lightlevel->value = 150 * shadelight [ 1 ]; } else { gl_lightlevel->value = 150 * shadelight [ 2 ]; } } } } if ( currententity->flags & RF_MINLIGHT ) { for ( i = 0; i < 3; i++ ) { if ( shadelight [ i ] > 0.1 ) { break; } } if ( i == 3 ) { shadelight [ 0 ] = 0.1; shadelight [ 1 ] = 0.1; shadelight [ 2 ] = 0.1; } } if ( currententity->flags & RF_GLOW ) { /* bonus items will pulse with time */ float scale; float min; scale = 0.1 * sin( r_newrefdef.time * 7 ); for ( i = 0; i < 3; i++ ) { min = shadelight [ i ] * 0.8; shadelight [ i ] += scale; if ( shadelight [ i ] < min ) { shadelight [ i ] = min; } } } /* ir goggles color override */ if ( r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE ) { shadelight [ 0 ] = 1.0; shadelight [ 1 ] = 0.0; shadelight [ 2 ] = 0.0; } shadedots = r_avertexnormal_dots [ ( (int) ( currententity->angles [ 1 ] * ( SHADEDOT_QUANT / 360.0 ) ) ) & ( SHADEDOT_QUANT - 1 ) ]; an = currententity->angles [ 1 ] / 180 * M_PI; shadevector [ 0 ] = cos( -an ); shadevector [ 1 ] = sin( -an ); shadevector [ 2 ] = 1; VectorNormalize( shadevector ); /* locate the proper data */ c_alias_polys += paliashdr->num_tris; /* draw all the triangles */ if ( currententity->flags & RF_DEPTHHACK ) /* hack the depth range to prevent view model from poking into walls */ { qglDepthRange( gldepthmin, gldepthmin + 0.3 * ( gldepthmax - gldepthmin ) ); } if ( ( currententity->flags & RF_WEAPONMODEL ) && ( gl_lefthand->value == 1.0F ) ) { extern void R_MYgluPerspective ( GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar ); qglMatrixMode( GL_PROJECTION ); qglPushMatrix(); qglLoadIdentity(); qglScalef( -1, 1, 1 ); R_MYgluPerspective( r_newrefdef.fov_y, (float) r_newrefdef.width / r_newrefdef.height, 4, 4096 ); qglMatrixMode( GL_MODELVIEW ); qglCullFace( GL_BACK ); } qglPushMatrix(); e->angles [ PITCH ] = -e->angles [ PITCH ]; R_RotateForEntity( e ); e->angles [ PITCH ] = -e->angles [ PITCH ]; /* select skin */ if ( currententity->skin ) { skin = currententity->skin; /* custom player skin */ } else { if ( currententity->skinnum >= MAX_MD2SKINS ) { skin = currentmodel->skins [ 0 ]; } else { skin = currentmodel->skins [ currententity->skinnum ]; if ( !skin ) { skin = currentmodel->skins [ 0 ]; } } } if ( !skin ) { skin = r_notexture; /* fallback... */ } R_Bind( skin->texnum ); /* draw it */ qglShadeModel( GL_SMOOTH ); R_TexEnv( GL_MODULATE ); if ( currententity->flags & RF_TRANSLUCENT ) { qglEnable( GL_BLEND ); } if ( ( currententity->frame >= paliashdr->num_frames ) || ( currententity->frame < 0 ) ) { ri.Con_Printf( PRINT_ALL, "R_DrawAliasModel %s: no such frame %d\n", currentmodel->name, currententity->frame ); currententity->frame = 0; currententity->oldframe = 0; } if ( ( currententity->oldframe >= paliashdr->num_frames ) || ( currententity->oldframe < 0 ) ) { ri.Con_Printf( PRINT_ALL, "R_DrawAliasModel %s: no such oldframe %d\n", currentmodel->name, currententity->oldframe ); currententity->frame = 0; currententity->oldframe = 0; } if ( !gl_lerpmodels->value ) { currententity->backlerp = 0; } R_DrawAliasFrameLerp( paliashdr, currententity->backlerp ); R_TexEnv( GL_REPLACE ); qglShadeModel( GL_FLAT ); qglPopMatrix(); if ( ( currententity->flags & RF_WEAPONMODEL ) && ( gl_lefthand->value == 1.0F ) ) { qglMatrixMode( GL_PROJECTION ); qglPopMatrix(); qglMatrixMode( GL_MODELVIEW ); qglCullFace( GL_FRONT ); } if ( currententity->flags & RF_TRANSLUCENT ) { qglDisable( GL_BLEND ); } if ( currententity->flags & RF_DEPTHHACK ) { qglDepthRange( gldepthmin, gldepthmax ); } if ( gl_shadows->value && !( currententity->flags & ( RF_TRANSLUCENT | RF_WEAPONMODEL | RF_NOSHADOW ) ) ) { qglPushMatrix(); /* don't rotate shadows on ungodly axes */ qglTranslatef( e->origin [ 0 ], e->origin [ 1 ], e->origin [ 2 ] ); qglRotatef( e->angles [ 1 ], 0, 0, 1 ); qglDisable( GL_TEXTURE_2D ); qglEnable( GL_BLEND ); qglColor4f( 0, 0, 0, 0.5f ); R_DrawAliasShadow( paliashdr, currententity->frame ); qglEnable( GL_TEXTURE_2D ); qglDisable( GL_BLEND ); qglPopMatrix(); } qglColor4f( 1, 1, 1, 1 ); }
/* ================= R_DrawAliasModel ================= */ void R_DrawAliasModel (entity_t *e) { maliasmodel_t *paliashdr; vec3_t bbox[8]; qboolean mirrormodel = false; int i; // also skip this for viewermodels and cameramodels if ( !(e->flags & RF_WEAPONMODEL || e->flags & RF_VIEWERMODEL || e->renderfx & RF2_CAMERAMODEL) ) { if (R_CullAliasModel(bbox, e)) return; } // mirroring support if (e->flags & RF_WEAPONMODEL) { if (r_lefthand->value == 2) return; else if (r_lefthand->value == 1) mirrormodel = true; } else if (e->renderfx & RF2_CAMERAMODEL) { if (r_lefthand->value==1) mirrormodel = true; } else if (e->flags & RF_MIRRORMODEL) mirrormodel = true; // end mirroring support paliashdr = (maliasmodel_t *)currentmodel->extradata; R_SetShadeLight (); if (e->flags & RF_DEPTHHACK) // hack the depth range to prevent view model from poking into walls { if (r_newrefdef.rdflags & RDF_NOWORLDMODEL) GL_DepthRange (gldepthmin, gldepthmin + 0.01*(gldepthmax-gldepthmin)); else GL_DepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin)); } // mirroring support if (mirrormodel) R_FlipModel(true); for (i=0; i < paliashdr->num_meshes; i++) c_alias_polys += paliashdr->meshes[i].num_tris; qglPushMatrix (); e->angles[ROLL] = -e->angles[ROLL]; // roll is backwards R_RotateForEntity (e, true); e->angles[ROLL] = -e->angles[ROLL]; // roll is backwards GL_ShadeModel (GL_SMOOTH); GL_TexEnv(GL_MODULATE); if ( (e->frame >= paliashdr->num_frames) || (e->frame < 0) ) { VID_Printf (PRINT_ALL, "R_DrawAliasModel %s: no such frame %d\n", currentmodel->name, e->frame); e->frame = 0; e->oldframe = 0; } if ( (e->oldframe >= paliashdr->num_frames) || (e->oldframe < 0)) { VID_Printf (PRINT_ALL, "R_DrawAliasModel %s: no such oldframe %d\n", currentmodel->name, e->oldframe); e->frame = 0; e->oldframe = 0; } if (!r_lerpmodels->value) e->backlerp = 0; R_DrawAliasFrameLerp (paliashdr, e); GL_TexEnv(GL_REPLACE); GL_ShadeModel (GL_FLAT); qglPopMatrix (); // mirroring support if (mirrormodel) R_FlipModel(false); // show model bounding box R_DrawAliasModelBBox (bbox, e); if (e->flags & RF_DEPTHHACK) GL_DepthRange (gldepthmin, gldepthmax); aliasShadowAlpha = R_CalcShadowAlpha(e); if (!(e->flags & (RF_WEAPONMODEL | RF_NOSHADOW)) // no shadows from shells && !( (e->flags & (RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM)) && (e->flags & RF_TRANSLUCENT) ) && r_shadows->value >= 1 && aliasShadowAlpha >= DIV255) { qglPushMatrix (); GL_DisableTexture(0); GL_Enable (GL_BLEND); if (r_shadows->value == 3) { e->angles[ROLL] = -e->angles[ROLL]; // roll is backwards R_RotateForEntity (e, true); e->angles[ROLL] = -e->angles[ROLL]; // roll is backwards R_DrawAliasVolumeShadow (paliashdr, bbox); } else { R_RotateForEntity (e, false); R_DrawAliasPlanarShadow (paliashdr); } GL_Disable (GL_BLEND); GL_EnableTexture(0); qglPopMatrix (); } }
void R_DrawBrushModel(entity_t *e) { int k; vec3_t mins, maxs; model_t *clmodel; bool rotated; int i; extern vec3_t lightcolor; int lnum; vec3_t dist; float add; float modelorg[3]; clmodel = e->model; if (e->angles[0] || e->angles[1] || e->angles[2]) { rotated = true; for (i = 0; i < 3; i++) { mins[i] = e->origin[i] - clmodel->radius; maxs[i] = e->origin[i] + clmodel->radius; } } else { rotated = false; VectorAdd(e->origin, clmodel->mins, mins); VectorAdd(e->origin, clmodel->maxs, maxs); } if (R_CullBox(mins, maxs)) return; //Lighting for model //dynamic lights for non lightmaped bmodels if (clmodel->firstmodelsurface == 0) { R_LightPoint(e->origin); for (lnum = 0; lnum < MAX_DLIGHTS; lnum++) { if (cl_dlights[lnum].die >= cl.time) { VectorSubtract(e->origin, cl_dlights[lnum].origin, dist); add = cl_dlights[lnum].radius - VectorLength(dist); if (add > 0) { lightcolor[0] += add * cl_dlights[lnum].colour[0]; lightcolor[1] += add * cl_dlights[lnum].colour[1]; lightcolor[2] += add * cl_dlights[lnum].colour[2]; } } } VectorScale(lightcolor, 1.0f / 100.0f, lightcolor); if (gl_ammoflash.getBool()) { lightcolor[0] += sin(2 * cl.time * M_PI) / 4; lightcolor[1] += sin(2 * cl.time * M_PI) / 4; lightcolor[2] += sin(2 * cl.time * M_PI) / 4; } glColor3fv(lightcolor); } else { glColor3f(1.0, 1.0, 1.0); memset(lightmap_polys, 0, sizeof (lightmap_polys)); } VectorSubtract(r_refdef.vieworg, e->origin, modelorg); if (rotated) { vec3_t temp; vec3_t forward, right, up; VectorCopy(modelorg, temp); AngleVectors(e->angles, forward, right, up); modelorg[0] = DotProduct(temp, forward); modelorg[1] = -DotProduct(temp, right); modelorg[2] = DotProduct(temp, up); } glPushMatrix(); e->angles[0] = -e->angles[0]; // stupid quake bug R_RotateForEntity(e); e->angles[0] = -e->angles[0]; // stupid quake bug // calculate dynamic lighting for bmodel if it's not an // instanced model if (clmodel->firstmodelsurface != 0 && !gl_flashblend.getBool()) { for (k = 0; k < MAX_DLIGHTS; k++) { if ((cl_dlights[k].die < cl.time) || (!cl_dlights[k].radius)) continue; R_MarkLights(&cl_dlights[k], 1 << k, clmodel->nodes + clmodel->hulls[0].firstclipnode); } } R_DrawBrush(clmodel, &modelorg[0]); glPopMatrix(); }
/* ================== RB_RenderDrawSurfList ================== */ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { shader_t *shader, *oldShader; int fogNum, oldFogNum; int entityNum, oldEntityNum; int frontFace; int dlighted, oldDlighted; qboolean depthRange, oldDepthRange; int i; drawSurf_t *drawSurf; int oldSort; float originalTime; #ifdef __MACOS__ int macEventTime; Sys_PumpEvents(); // crutch up the mac's limited buffer queue size // we don't want to pump the event loop too often and waste time, so // we are going to check every shader change macEventTime = ri.Milliseconds() + MAC_EVENT_PUMP_MSEC; #endif // save original time for entity shader offsets originalTime = backEnd.refdef.floatTime; // clear the z buffer, set the modelview, etc RB_BeginDrawingView(); // draw everything oldEntityNum = -1; backEnd.currentEntity = &tr.worldEntity; oldShader = NULL; oldFogNum = -1; oldDepthRange = qfalse; oldDlighted = qfalse; oldSort = -1; depthRange = qfalse; backEnd.pc.c_surfaces += numDrawSurfs; for ( i = 0, drawSurf = drawSurfs; i < numDrawSurfs; i++, drawSurf++ ) { if ( drawSurf->sort == oldSort ) { // fast path, same as previous sort rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); continue; } oldSort = drawSurf->sort; R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &frontFace, &dlighted ); // // change the tess parameters if needed // an "entityMergable" shader is a shader that can have surfaces from separate // entities merged into a single batch, like smoke and blood puff sprites if ( shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || ( entityNum != oldEntityNum && !shader->entityMergable ) ) { if ( oldShader != NULL ) { #ifdef __MACOS__ // crutch up the mac's limited buffer queue size int t; t = ri.Milliseconds(); if ( t > macEventTime ) { macEventTime = t + MAC_EVENT_PUMP_MSEC; Sys_PumpEvents(); } #endif RB_EndSurface(); } RB_BeginSurface( shader, fogNum ); oldShader = shader; oldFogNum = fogNum; oldDlighted = dlighted; } // // change the modelview matrix if needed // if ( entityNum != oldEntityNum ) { depthRange = qfalse; if ( entityNum != ENTITYNUM_WORLD ) { backEnd.currentEntity = &backEnd.refdef.entities[ entityNum ]; backEnd.refdef.floatTime = originalTime; // - backEnd.currentEntity->e.shaderTime; // JPW NERVE pulled this to match q3ta // we have to reset the shaderTime as well otherwise image animations start // from the wrong frame // tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; // set up the transformation matrix R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.orientation ); // set up the dynamic lighting if needed if ( backEnd.currentEntity->needDlights ) { R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.orientation ); } if ( backEnd.currentEntity->e.renderfx & RF_DEPTHHACK ) { // hack the depth range to prevent view model from poking into walls depthRange = qtrue; } } else { backEnd.currentEntity = &tr.worldEntity; backEnd.refdef.floatTime = originalTime; backEnd.orientation = backEnd.viewParms.world; // we have to reset the shaderTime as well otherwise image animations on // the world (like water) continue with the wrong frame // tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.orientation ); } glLoadMatrixf( backEnd.orientation.modelMatrix ); // // change depthrange if needed // if ( oldDepthRange != depthRange ) { if ( depthRange ) { glDepthRange( 0, 0.3 ); } else { glDepthRange( 0, 1 ); } oldDepthRange = depthRange; } oldEntityNum = entityNum; } // add the triangles for this surface rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); } // draw the contents of the last shader batch if ( oldShader != NULL ) { RB_EndSurface(); } // go back to the world modelview matrix backEnd.currentEntity = &tr.worldEntity; backEnd.refdef.floatTime = originalTime; backEnd.orientation = backEnd.viewParms.world; R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.orientation ); glLoadMatrixf( backEnd.viewParms.world.modelMatrix ); if ( depthRange ) { glDepthRange( 0, 1 ); } // (SA) draw sun RB_DrawSun(); // darken down any stencil shadows RB_ShadowFinish(); // add light flares on lights that aren't obscured RB_RenderFlares(); #ifdef __MACOS__ Sys_PumpEvents(); // crutch up the mac's limited buffer queue size #endif }
/* ================== RB_RenderDrawSurfList ================== */ void RB_RenderDrawSurfList(drawSurf_t *drawSurfs, int numDrawSurfs) { shader_t *shader, *oldShader; int fogNum, oldFogNum; int entityNum, oldEntityNum; int dlighted, oldDlighted; qboolean depthRange, oldDepthRange; int i; drawSurf_t *drawSurf; int oldSort; float originalTime; int oldNumVerts, oldNumIndex; //GR - tessellation flag int atiTess = 0, oldAtiTess; #ifdef __MACOS__ int macEventTime; Sys_PumpEvents(); // crutch up the mac's limited buffer queue size // we don't want to pump the event loop too often and waste time, so // we are going to check every shader change macEventTime = ri.Milliseconds() + MAC_EVENT_PUMP_MSEC; #endif // save original time for entity shader offsets originalTime = backEnd.refdef.floatTime; // clear the z buffer, set the modelview, etc RB_BeginDrawingView(); // draw everything oldEntityNum = -1; backEnd.currentEntity = &tr.worldEntity; oldShader = NULL; oldFogNum = -1; oldDepthRange = qfalse; oldDlighted = qfalse; oldSort = -1; depthRange = qfalse; // GR - tessellation also forces to draw everything oldAtiTess = -1; backEnd.pc.c_surfaces += numDrawSurfs; for(i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) { if(drawSurf->sort == oldSort) { // fast path, same as previous sort oldNumVerts = tess.numVertexes; oldNumIndex = tess.numIndexes; rb_surfaceTable[ *drawSurf->surface ](drawSurf->surface); /* // RF, convert the newly created vertexes into dust particles, and overwrite if (backEnd.currentEntity->e.reFlags & REFLAG_ZOMBIEFX) { RB_ZombieFX( 0, drawSurf, oldNumVerts, oldNumIndex ); } else if (backEnd.currentEntity->e.reFlags & REFLAG_ZOMBIEFX2) { RB_ZombieFX( 1, drawSurf, oldNumVerts, oldNumIndex ); } */ continue; } oldSort = drawSurf->sort; // GR - also extract tesselation flag R_DecomposeSort(drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &atiTess); // // change the tess parameters if needed // a "entityMergable" shader is a shader that can have surfaces from seperate // entities merged into a single batch, like smoke and blood puff sprites if(shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted // GR - force draw on tessellation flag change || (atiTess != oldAtiTess) || (entityNum != oldEntityNum && !shader->entityMergable)) { if(oldShader != NULL) { #ifdef __MACOS__ // crutch up the mac's limited buffer queue size int t; t = ri.Milliseconds(); if(t > macEventTime) { macEventTime = t + MAC_EVENT_PUMP_MSEC; Sys_PumpEvents(); } #endif // GR - pass tessellation flag to the shader command // make sure to use oldAtiTess!!! tess.ATI_tess = (oldAtiTess == ATI_TESS_TRUFORM); RB_EndSurface(); } RB_BeginSurface(shader, fogNum); oldShader = shader; oldFogNum = fogNum; oldDlighted = dlighted; // GR - update old tessellation flag oldAtiTess = atiTess; } // // change the modelview matrix if needed // if(entityNum != oldEntityNum) { depthRange = qfalse; if(entityNum != ENTITYNUM_WORLD) { backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; // we have to reset the shaderTime as well otherwise image animations start // from the wrong frame // tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; // set up the transformation matrix R_RotateForEntity(backEnd.currentEntity, &backEnd.viewParms, &backEnd.or); // set up the dynamic lighting if needed if(backEnd.currentEntity->needDlights) { R_TransformDlights(backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or); } if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK) { // hack the depth range to prevent view model from poking into walls depthRange = qtrue; } } else { backEnd.currentEntity = &tr.worldEntity; backEnd.refdef.floatTime = originalTime; backEnd.or = backEnd.viewParms.world; // we have to reset the shaderTime as well otherwise image animations on // the world (like water) continue with the wrong frame // tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; R_TransformDlights(backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or); } qglLoadMatrixf(backEnd.or.modelMatrix); // // change depthrange if needed // if(oldDepthRange != depthRange) { if(depthRange) { qglDepthRange(0, 0.3); } else { qglDepthRange(0, 1); } oldDepthRange = depthRange; } oldEntityNum = entityNum; } // RF, ZOMBIEFX, store the tess indexes, so we can grab the calculated // vertex positions and normals, and convert them into dust particles oldNumVerts = tess.numVertexes; oldNumIndex = tess.numIndexes; // add the triangles for this surface rb_surfaceTable[ *drawSurf->surface ](drawSurf->surface); // RF, convert the newly created vertexes into dust particles, and overwrite if(backEnd.currentEntity->e.reFlags & REFLAG_ZOMBIEFX) { RB_ZombieFX(0, drawSurf, oldNumVerts, oldNumIndex); } else if(backEnd.currentEntity->e.reFlags & REFLAG_ZOMBIEFX2) { RB_ZombieFX(1, drawSurf, oldNumVerts, oldNumIndex); } } // draw the contents of the last shader batch if(oldShader != NULL) { // GR - pass tessellation flag to the shader command // make sure to use oldAtiTess!!! tess.ATI_tess = (oldAtiTess == ATI_TESS_TRUFORM); RB_EndSurface(); } // go back to the world modelview matrix backEnd.currentEntity = &tr.worldEntity; backEnd.refdef.floatTime = originalTime; backEnd.or = backEnd.viewParms.world; R_TransformDlights(backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or); qglLoadMatrixf(backEnd.viewParms.world.modelMatrix); if(depthRange) { qglDepthRange(0, 1); } // (SA) draw sun RB_DrawSun(); // darken down any stencil shadows RB_ShadowFinish(); // add light flares on lights that aren't obscured RB_RenderFlares(); #ifdef __MACOS__ Sys_PumpEvents(); // crutch up the mac's limited buffer queue size #endif }
void R_DrawAliasModel(entity_t *e) { extern void AddFire(vec3_t org, float size); int lnum; vec3_t dist; float add; model_t *clmodel; vec3_t mins, maxs; aliashdr_t *paliashdr; float an; //s, t, int anim; md2_t *pheader; // LH / muff int shell; //QMB :model shells //not implemented yet // byte c, *color; //QMB :color map //does the model need a shell? if (cl.items & IT_QUAD && e == &cl.viewent) shell = true; else shell = false; //set get the model from the e clmodel = e->model; //work out its max and mins VectorAdd(e->origin, clmodel->mins, mins); VectorAdd(e->origin, clmodel->maxs, maxs); //make sure its in screen if (R_CullBox(mins, maxs) && e != &cl.viewent) return; //QMB: FIXME //should use a particle emitter linked to the model for its org //needs to be linked when the model is created and distroyed when //the entity is distroyed //check if its a fire and add the particle effect if (!strcmp(clmodel->name, "progs/flame.mdl")) AddFire(e->origin, 4); if (!strcmp(clmodel->name, "progs/flame2.mdl")) { AddFire(e->origin, 10); return; //do not draw the big fire model, its just a place holder for the particles } // get lighting information //QMB: FIXME //SHOULD CHANGE TO A PASSED VAR //get vertex normals (for lighting and shells) shadedots = r_avertexnormal_dots[((int) (e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; //make a default lighting direction an = e->angles[1] / 180 * M_PI; shadevector[0] = cos(-an); shadevector[1] = sin(-an); shadevector[2] = 1; //e->angles[0]; VectorNormalize(shadevector); //get the light for the model R_LightPoint(e->origin); // LordHavoc: lightcolor is all that matters from this //work out lighting from the dynamic lights for (lnum = 0; lnum < MAX_DLIGHTS; lnum++) { //if the light is alive if (cl_dlights[lnum].die >= cl.time) { //work out the distance to the light VectorSubtract(e->origin, cl_dlights[lnum].origin, dist); add = cl_dlights[lnum].radius - VectorLength(dist); //if its close enough add light from it if (add > 0) { lightcolor[0] += add * cl_dlights[lnum].colour[0]; lightcolor[1] += add * cl_dlights[lnum].colour[1]; lightcolor[2] += add * cl_dlights[lnum].colour[2]; } } } //scale lighting to floating point VectorScale(lightcolor, 1.0f / 200.0f, lightcolor); // locate the proper data glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); if (gl_n_patches && gl_npatches.getBool()) { glEnable(GL_PN_TRIANGLES_ATI); glPNTrianglesiATI(GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI, gl_npatches.getInt()); if (true) glPNTrianglesiATI(GL_PN_TRIANGLES_POINT_MODE_ATI, GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI); else glPNTrianglesiATI(GL_PN_TRIANGLES_POINT_MODE_ATI, GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI); if (true) glPNTrianglesiATI(GL_PN_TRIANGLES_NORMAL_MODE_ATI, GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI); else glPNTrianglesiATI(GL_PN_TRIANGLES_NORMAL_MODE_ATI, GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI); } if (clmodel->aliastype == MD3IDHEADER) { //do nothing for testing if (!r_modeltexture.getBool()) { GL_DisableTMU(GL_TEXTURE0_ARB); }//disable texture if needed R_DrawQ3Model(e, false, false); if (!r_modeltexture.getBool()) { GL_EnableTMU(GL_TEXTURE0_ARB); }//enable texture if needed if (r_celshading.getBool() || r_outline.getBool()) { glCullFace(GL_BACK); glEnable(GL_BLEND); glPolygonMode(GL_FRONT, GL_LINE); if (e == &cl.viewent) { glLineWidth(1.0f); } else { glLineWidth(5.0f); } glEnable(GL_LINE_SMOOTH); GL_DisableTMU(GL_TEXTURE0_ARB); glColor3f(0.0, 0.0, 0.0); R_DrawQ3Model(e, false, true); glColor3f(1.0, 1.0, 1.0); GL_EnableTMU(GL_TEXTURE0_ARB); glPolygonMode(GL_FRONT, GL_FILL); glDisable(GL_BLEND); glCullFace(GL_FRONT); } if (shell) { glBindTexture(GL_TEXTURE_2D, quadtexture); glColor4f(1.0, 1.0, 1.0, 0.5); glEnable(GL_BLEND); R_DrawQ3Model(e, true, false); glDisable(GL_BLEND); glColor3f(1.0, 1.0, 1.0); } } else if (clmodel->aliastype != ALIASTYPE_MD2) { paliashdr = (aliashdr_t *) Mod_Extradata(e->model); c_alias_polys += paliashdr->numtris; glPushMatrix(); //interpolate unless its the viewmodel if (e != &cl.viewent) R_BlendedRotateForEntity(e); else R_RotateForEntity(e); glTranslatef(paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]); glScalef(paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]); anim = (int) (cl.time * 10) & 3; glBindTexture(GL_TEXTURE_2D, paliashdr->gl_texturenum[e->skinnum][anim]); // draw all the triangles if (!r_modeltexture.getBool()) { GL_DisableTMU(GL_TEXTURE0_ARB); } else { //highlighting test code if (0 && gl_textureunits > 2) { GL_EnableTMU(GL_TEXTURE1_ARB); glBindTexture(GL_TEXTURE_2D, TextureManager::highlighttexture); glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); //need correct mode glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD); glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0); //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD); } } glColor3fv(lightcolor); R_SetupAliasBlendedFrame(e->frame, paliashdr, e, false, false); glDisable(GL_TEXTURE_1D); if (r_celshading.getBool() || r_outline.getBool()) { glColor3f(0.0, 0.0, 0.0); R_SetupAliasBlendedFrame(e->frame, paliashdr, e, false, true); glColor3f(1.0, 1.0, 1.0); } if (!r_modeltexture.getBool()) { GL_EnableTMU(GL_TEXTURE0_ARB); } else { if (0 && gl_textureunits > 2) { //highlighting test code glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); GL_DisableTMU(GL_TEXTURE1_ARB); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } } glActiveTexture(GL_TEXTURE0_ARB); //colour map code... not working yet... /* if (e->colormap != vid.colormap && !gl_nocolors.value) { if (paliashdr->gl_texturenumColorMap&&paliashdr->gl_texturenumColorMap){ glBindTexture(GL_TEXTURE_2D,paliashdr->gl_texturenumColorMap); c = (byte)e->colormap & 0xF0; c += (c >= 128 && c < 224) ? 4 : 12; // 128-224 are backwards ranges color = (byte *) (&d_8to24table[c]); //glColor3fv(color); glColor3f(1.0,1.0,1.0); } }*/ if (shell) { glBindTexture(GL_TEXTURE_2D, quadtexture); glColor4f(1.0, 1.0, 1.0, 0.5); glEnable(GL_BLEND); R_SetupAliasBlendedFrame(e->frame, paliashdr, e, true, false); glDisable(GL_BLEND); glColor3f(1.0, 1.0, 1.0); } glPopMatrix(); } else { pheader = (md2_t *) Mod_Extradata(e->model); c_alias_polys += pheader->num_tris; glBindTexture(GL_TEXTURE_2D, pheader->gl_texturenum[e->skinnum]); R_SetupQ2AliasFrame(e, pheader); } if (gl_n_patches && gl_npatches.getBool()) { glDisable(GL_PN_TRIANGLES_ATI); } glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); }
/* * R_DrawAliasFrameLerp * * Interpolates between two frames and origins */ static void R_DrawAliasFrameLerp( const meshbuffer_t *mb, float backlerp ) { int i, meshnum; int features; float backv[3], frontv[3]; vec3_t normal, oldnormal; qboolean calcVerts, calcNormals, calcSTVectors; vec3_t move; maliasframe_t *frame, *oldframe; maliasmesh_t *mesh; maliasvertex_t *v, *ov; entity_t *e; model_t *mod; maliasmodel_t *model; shader_t *shader; MB_NUM2ENTITY( mb->sortkey, e ); mod = Mod_ForHandle( mb->LODModelHandle ); model = ( maliasmodel_t * )mod->extradata; meshnum = -mb->infokey - 1; if( meshnum < 0 || meshnum >= model->nummeshes ) return; mesh = model->meshes + meshnum; frame = model->frames + e->frame; oldframe = model->frames + e->oldframe; for( i = 0; i < 3; i++ ) move[i] = frame->translate[i] + ( oldframe->translate[i] - frame->translate[i] ) * backlerp; MB_NUM2SHADER( mb->shaderkey, shader ); features = MF_NONBATCHED | shader->features; if( !mb->vboIndex ) { features &= ~MF_HARDWARE; } if( ri.params & RP_SHADOWMAPVIEW ) { features &= ~( MF_COLORS|MF_SVECTORS|MF_ENABLENORMALS ); if( !( shader->features & MF_DEFORMVS ) ) features &= ~MF_NORMALS; } else { if( features & MF_SVECTORS ) features |= MF_NORMALS; #ifdef HARDWARE_OUTLINES if( e->outlineHeight ) features |= MF_NORMALS|(glConfig.ext.GLSL ? MF_ENABLENORMALS : 0); #endif } calcNormals = calcSTVectors = qfalse; calcNormals = ( ( features & MF_NORMALS ) != 0 ) && ( ( e->frame != 0 ) || ( e->oldframe != 0 ) ); calcSTVectors = ( ( features & MF_SVECTORS ) != 0 ) && calcNormals; if( mb->vboIndex != 0 ) { calcVerts = calcNormals = calcSTVectors = qfalse; } else { if( !e->frame && !e->oldframe ) { calcVerts = qfalse; if( calcNormals ) { v = mesh->vertexes; for( i = 0; i < mesh->numverts; i++, v++ ) R_LatLongToNorm( v->latlong, inNormalsArray[i] ); } } else if( e->frame == e->oldframe ) { calcVerts = qtrue; for( i = 0; i < 3; i++ ) frontv[i] = frame->scale[i]; v = mesh->vertexes + e->frame * mesh->numverts; for( i = 0; i < mesh->numverts; i++, v++ ) { Vector4Set( inVertsArray[i], move[0] + v->point[0]*frontv[0], move[1] + v->point[1]*frontv[1], move[2] + v->point[2]*frontv[2], 1 ); if( calcNormals ) R_LatLongToNorm( v->latlong, inNormalsArray[i] ); } } else { calcVerts = qtrue; for( i = 0; i < 3; i++ ) { backv[i] = backlerp * oldframe->scale[i]; frontv[i] = ( 1.0f - backlerp ) * frame->scale[i]; } v = mesh->vertexes + e->frame * mesh->numverts; ov = mesh->vertexes + e->oldframe * mesh->numverts; for( i = 0; i < mesh->numverts; i++, v++, ov++ ) { Vector4Set( inVertsArray[i], move[0] + v->point[0]*frontv[0] + ov->point[0]*backv[0], move[1] + v->point[1]*frontv[1] + ov->point[1]*backv[1], move[2] + v->point[2]*frontv[2] + ov->point[2]*backv[2], 1 ); if( calcNormals ) { R_LatLongToNorm( v->latlong, normal ); R_LatLongToNorm( ov->latlong, oldnormal ); VectorSet( inNormalsArray[i], normal[0] + ( oldnormal[0] - normal[0] ) * backlerp, normal[1] + ( oldnormal[1] - normal[1] ) * backlerp, normal[2] + ( oldnormal[2] - normal[2] ) * backlerp ); } } } if( calcSTVectors ) R_BuildTangentVectors( mesh->numverts, inVertsArray, inNormalsArray, mesh->stArray, mesh->numtris, mesh->elems, inSVectorsArray ); } alias_mesh.xyzArray = calcVerts ? inVertsArray : mesh->xyzArray; alias_mesh.elems = mesh->elems; alias_mesh.numElems = mesh->numtris * 3; alias_mesh.numVerts = mesh->numverts; alias_mesh.stArray = mesh->stArray; if( features & MF_NORMALS ) alias_mesh.normalsArray = calcNormals ? inNormalsArray : mesh->normalsArray; if( features & MF_SVECTORS ) alias_mesh.sVectorsArray = calcSTVectors ? inSVectorsArray : mesh->sVectorsArray; R_RotateForEntity( e ); R_PushMesh( &alias_mesh, mb->vboIndex != 0, features ); R_RenderMeshBuffer( mb, NULL ); }
/* ================== RB_RenderDrawSurfList ================== */ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { shader_t *shader, *oldShader; int fogNum, oldFogNum; int entityNum, oldEntityNum; int dlighted, oldDlighted; qboolean depthRange, oldDepthRange, isCrosshair, wasCrosshair; int i; drawSurf_t *drawSurf; int oldSort; float originalTime; int oldNumVerts, oldNumIndex; //GR - tessellation flag int atiTess = 0, oldAtiTess; // save original time for entity shader offsets originalTime = backEnd.refdef.floatTime; // clear the z buffer, set the modelview, etc RB_BeginDrawingView(); // draw everything oldEntityNum = -1; backEnd.currentEntity = &tr.worldEntity; oldShader = NULL; oldFogNum = -1; oldDepthRange = qfalse; wasCrosshair = qfalse; oldDlighted = qfalse; oldSort = -1; depthRange = qfalse; // GR - tessellation also forces to draw everything oldAtiTess = -1; backEnd.pc.c_surfaces += numDrawSurfs; for ( i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++ ) { if ( drawSurf->sort == oldSort ) { // fast path, same as previous sort oldNumVerts = tess.numVertexes; oldNumIndex = tess.numIndexes; rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); // RF, convert the newly created vertexes into dust particles, and overwrite if (backEnd.currentEntity->e.reFlags & REFLAG_ZOMBIEFX) { RB_ZombieFX( 0, drawSurf, oldNumVerts, oldNumIndex ); } else if (backEnd.currentEntity->e.reFlags & REFLAG_ZOMBIEFX2) { RB_ZombieFX( 1, drawSurf, oldNumVerts, oldNumIndex ); } continue; } oldSort = drawSurf->sort; // GR - also extract tesselation flag R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &atiTess ); // // change the tess parameters if needed // a "entityMergable" shader is a shader that can have surfaces from seperate // entities merged into a single batch, like smoke and blood puff sprites if ( shader != NULL && ( shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted // GR - force draw on tessellation flag change || ( atiTess != oldAtiTess ) || ( entityNum != oldEntityNum && !shader->entityMergable ) ) ){ if ( oldShader != NULL ) { // GR - pass tessellation flag to the shader command // make sure to use oldAtiTess!!! tess.ATI_tess = ( oldAtiTess == ATI_TESS_TRUFORM ); RB_EndSurface(); } RB_BeginSurface( shader, fogNum ); oldShader = shader; oldFogNum = fogNum; oldDlighted = dlighted; // GR - update old tessellation flag oldAtiTess = atiTess; } // // change the modelview matrix if needed // if ( entityNum != oldEntityNum ) { depthRange = isCrosshair = qfalse; if ( entityNum != REFENTITYNUM_WORLD ) { backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; // we have to reset the shaderTime as well otherwise image animations start // from the wrong frame // tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; // set up the transformation matrix R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.or ); // set up the dynamic lighting if needed if ( backEnd.currentEntity->needDlights ) { R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); } if ( backEnd.currentEntity->e.renderfx & RF_DEPTHHACK ) { // hack the depth range to prevent view model from poking into walls depthRange = qtrue; if(backEnd.currentEntity->e.renderfx & RF_CROSSHAIR) isCrosshair = qtrue; } } else { backEnd.currentEntity = &tr.worldEntity; backEnd.refdef.floatTime = originalTime; backEnd.or = backEnd.viewParms.world; // we have to reset the shaderTime as well otherwise image animations on // the world (like water) continue with the wrong frame // tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); } qglLoadMatrixf( backEnd.or.modelMatrix ); // // change depthrange. Also change projection matrix so first person weapon does not look like coming // out of the screen. // if (oldDepthRange != depthRange || wasCrosshair != isCrosshair) { if (depthRange) { if(backEnd.viewParms.stereoFrame != STEREO_CENTER) { if(isCrosshair) { if(oldDepthRange) { // was not a crosshair but now is, change back proj matrix qglMatrixMode(GL_PROJECTION); qglLoadMatrixf(backEnd.viewParms.projectionMatrix); qglMatrixMode(GL_MODELVIEW); } } else { viewParms_t temp = backEnd.viewParms; R_SetupProjection(&temp, r_znear->value, qfalse); qglMatrixMode(GL_PROJECTION); qglLoadMatrixf(temp.projectionMatrix); qglMatrixMode(GL_MODELVIEW); } } if(!oldDepthRange) qglDepthRange (0, 0.3); } else { if(!wasCrosshair && backEnd.viewParms.stereoFrame != STEREO_CENTER) { qglMatrixMode(GL_PROJECTION); qglLoadMatrixf(backEnd.viewParms.projectionMatrix); qglMatrixMode(GL_MODELVIEW); } qglDepthRange( 0, 1 ); } oldDepthRange = depthRange; wasCrosshair = isCrosshair; } oldEntityNum = entityNum; } // RF, ZOMBIEFX, store the tess indexes, so we can grab the calculated // vertex positions and normals, and convert them into dust particles oldNumVerts = tess.numVertexes; oldNumIndex = tess.numIndexes; // add the triangles for this surface rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); // RF, convert the newly created vertexes into dust particles, and overwrite if ( backEnd.currentEntity->e.reFlags & REFLAG_ZOMBIEFX ) { RB_ZombieFX( 0, drawSurf, oldNumVerts, oldNumIndex ); } else if ( backEnd.currentEntity->e.reFlags & REFLAG_ZOMBIEFX2 ) { RB_ZombieFX( 1, drawSurf, oldNumVerts, oldNumIndex ); } } // draw the contents of the last shader batch if ( oldShader != NULL ) { // GR - pass tessellation flag to the shader command // make sure to use oldAtiTess!!! tess.ATI_tess = ( oldAtiTess == ATI_TESS_TRUFORM ); RB_EndSurface(); } // go back to the world modelview matrix backEnd.currentEntity = &tr.worldEntity; backEnd.refdef.floatTime = originalTime; backEnd.or = backEnd.viewParms.world; R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); if ( depthRange ) { qglDepthRange( 0, 1 ); } if (r_drawSun->integer) { RB_DrawSun(0.2, tr.sunShader); } // darken down any stencil shadows RB_ShadowFinish(); // add light flares on lights that aren't obscured RB_RenderFlares(); }
/* ================= R_DrawQ3Model Modified Dr Labmans md3 code splitting it up to make it easier to add dynamic lighting code ================= */ void R_DrawQ3Model (entity_t *e) { md3header_t *header; //md3shader_t *shader; md3surface_t *surf; /* if (!gl_notrans.value) // always true if not -nehahra { r_modelalpha = e->transparency; if (r_modelalpha == 0) r_modelalpha = 1.0; } else { r_modelalpha = 1.0; } */ /*************** FIXME: combine with alias model code! ***************/ R_CalcMD3Lighting (e, e->model); // Get the model data header = (md3header_t *)Mod_Extradata (e->model); // locate the proper data "huh surface related"! surf = (md3surface_t *)((byte *)header + header->surface_offs); c_alias_polys += surf->num_surf_tris; /*******JDH******* //get pointer to shaders shader = (md3shader_t *)((byte *)surf + surf->shader_offs); //shaders = shader[(currententity->skinnum%surf->num_surf_shaders)].texnum; shaders = shader[ e->skinnum % surf->num_surf_shaders ].index; if (shaders) { GL_Bind(shaders); } else { GL_Bind(0); } *******JDH*******/ glPushMatrix(); //interpolate unless its the viewmodel if (gl_interpolate_animation.value && (e != &cl.viewent)) { R_BlendedRotateForEntity (e); } else { R_RotateForEntity (e); } if (gl_smoothmodels.value) glShadeModel (GL_SMOOTH); if (gl_affinemodels.value) glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); R_SetupQ3AliasFrame (e->frame, header, e, gl_mtexable); glShadeModel (GL_FLAT); if (gl_affinemodels.value) glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glPopMatrix(); }
/* ================= R_ShadowPassDrawBrushModel ================= */ void R_ShadowPassDrawBrushModel( cl_entity_t *e, const plight_t *pl ) { Vector mins, maxs; model_t *clmodel; bool rotated; clmodel = e->model; if( e->angles != g_vecZero ) { for( int i = 0; i < 3; i++ ) { mins[i] = e->origin[i] - clmodel->radius; maxs[i] = e->origin[i] + clmodel->radius; } rotated = true; } else { mins = e->origin + clmodel->mins; maxs = e->origin + clmodel->maxs; rotated = false; } if( R_CullBox( mins, maxs, RI.clipFlags )) return; if( RI.params & ( RP_SKYPORTALVIEW|RP_PORTALVIEW|RP_SCREENVIEW )) { if( rotated ) { if( R_VisCullSphere( e->origin, clmodel->radius )) return; } else { if( R_VisCullBox( mins, maxs )) return; } } if( rotated ) R_RotateForEntity( e ); else R_TranslateForEntity( e ); if( rotated ) tr.modelorg = RI.objectMatrix.VectorITransform( RI.vieworg ); else tr.modelorg = RI.vieworg - e->origin; // accumulate lit surfaces msurface_t *psurf = &clmodel->surfaces[clmodel->firstmodelsurface]; for( int i = 0; i < clmodel->nummodelsurfaces; i++, psurf++ ) { float *v; int k; if( psurf->flags & (SURF_DRAWTILED|SURF_PORTAL|SURF_REFLECT)) continue; R_AddToGrassChain( psurf, pl->frustum, pl->clipflags, false ); if( R_CullSurfaceExt( psurf, pl->frustum, 0 )) continue; // draw depth-mask on transparent textures if( psurf->flags & SURF_TRANSPARENT ) { pglEnable( GL_ALPHA_TEST ); pglEnable( GL_TEXTURE_2D ); pglAlphaFunc( GL_GREATER, 0.0f ); GL_Bind( GL_TEXTURE0, psurf->texinfo->texture->gl_texturenum ); } pglBegin( GL_POLYGON ); for( k = 0, v = psurf->polys->verts[0]; k < psurf->polys->numverts; k++, v += VERTEXSIZE ) { if( psurf->flags & SURF_TRANSPARENT ) pglTexCoord2f( v[3], v[4] ); pglVertex3fv( v ); } pglEnd(); if( psurf->flags & SURF_TRANSPARENT ) { pglDisable( GL_ALPHA_TEST ); pglDisable( GL_TEXTURE_2D ); } } R_LoadIdentity(); // restore worldmatrix }
/* ================== RB_RenderDrawSurfList ================== */ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { shader_t *shader; int fogNum; qboolean depthRange, oldDepthRange; int i; drawSurf_t *drawSurf; int oldSort; const surfaceType_t *surface; // clear the z buffer, set the modelview, etc RB_BeginDrawingView (); // Prepare initial values that will trigger the needed settings backEnd.currentModel = (sceneModel_t*)-1; oldDepthRange = qfalse; oldSort = -1; depthRange = qfalse; // Clear for endsurface first run tess.numIndexes = 0; backEnd.pc.c_surfaces += numDrawSurfs; if (!(backEnd.refdef->rdflags & RDF_NOWORLDMODEL)) { backEnd.sceneZfar = backEnd.viewParms.zFar; } for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) { /* Rendering a model? */ if ( drawSurf->sort & QSORT_HAVEMODEL_MASK ) { const drawModel_t *drawModel; unsigned int index; RB_EndSurface(); oldSort = drawSurf->sort; drawModel = (drawModel_t*) drawSurf->data; backEnd.currentModel = drawModel->model; index = R_SortToIndex( oldSort ); surface = drawModel->surface[index]; // set up the transformation matrix R_RotateForEntity( backEnd.currentModel, &backEnd.viewParms, &backEnd.or ); R_TransformDlights( backEnd.refdef->numDlights, backEnd.refdef->dlights, &backEnd.or ); //Load the temporary matrix to show the model qglLoadMatrixf( backEnd.or.modelMatrix ); depthRange = 0; //figure this stuff out now and store it if ( backEnd.currentModel->renderfx & RF_NODEPTH ) { depthRange = 2; } else if ( backEnd.currentModel->renderfx & RF_DEPTHHACK ) { depthRange = 1; } if ( oldDepthRange != depthRange ) { oldDepthRange = depthRange; switch ( depthRange ) { default: case 0: qglDepthRange (0, 1); break; case 1: qglDepthRange (0, .3); break; case 2: qglDepthRange (0, 0); break; } } shader = R_SortToShader( oldSort ); fogNum = R_SortToFog( oldSort ); RB_BeginSurface( shader, fogNum ); if ( mme_saveStencil->integer == 1) { if ( backEnd.currentModel->renderfx & RF_STENCIL) { if (!backEnd.doingStencil) { qglStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE ); backEnd.doingStencil = qtrue; } } else { if (backEnd.doingStencil) { qglStencilOp( GL_KEEP, GL_KEEP, GL_ZERO ); backEnd.doingStencil = qfalse; } } } rb_surfaceTable[ *surface ]( surface ); continue; } if ( drawSurf->sort == oldSort ) { // fast path, same as previous sort rb_surfaceTable[ *((byte *)drawSurf->data) ]( drawSurf->data ); continue; } RB_EndSurface(); oldSort = drawSurf->sort; shader = R_SortToShader( oldSort ); fogNum = R_SortToFog( oldSort ); RB_BeginSurface( shader, fogNum ); if ( backEnd.currentModel ) { if (backEnd.doingStencil) { qglStencilOp( GL_KEEP, GL_KEEP, GL_ZERO ); backEnd.doingStencil = qfalse; } backEnd.currentModel = 0; backEnd.or = backEnd.viewParms.world; R_TransformDlights( backEnd.refdef->numDlights, backEnd.refdef->dlights, &backEnd.or ); qglLoadMatrixf( backEnd.or.modelMatrix ); if ( oldDepthRange ) { depthRange = 0; oldDepthRange = 0; qglDepthRange (0, 1); } } rb_surfaceTable[ *((byte *)drawSurf->data) ]( drawSurf->data ); if ( mme_saveStencil->integer == 1) { if (backEnd.currentModel && backEnd.currentModel->renderfx & RF_STENCIL) { if (!backEnd.doingStencil) { qglStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE ); backEnd.doingStencil = qtrue; } } else { if (backEnd.doingStencil) { qglStencilOp( GL_KEEP, GL_KEEP, GL_ZERO ); backEnd.doingStencil = qfalse; } } } // add the triangles for this surface } // if ( backEnd.currentModel && tess.numVertexes ) // Com_Printf( "Shader batch for a model?\n" ); // draw the contents of the last shader batch RB_EndSurface(); // go back to the world modelview matrix qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); if ( depthRange ) { qglDepthRange (0, 1); } #if 0 RB_DrawSun(); #endif // darken down any stencil shadows RB_ShadowFinish(); // add light flares on lights that aren't obscured RB_RenderFlares(); }
/* ================= R_DrawAliasModelShadow Just draws the shadow for a model ================= */ void R_DrawAliasModelShadow (entity_t *e) { maliasmodel_t *paliashdr; vec3_t bbox[8]; qboolean mirrormodel = false; if (!r_shadows->value) return; if (e->flags & (RF_WEAPONMODEL | RF_NOSHADOW)) return; // no shadows from shells if ( (e->flags & (RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM)) && (e->flags & RF_TRANSLUCENT) ) return; // also skip this for viewermodels and cameramodels if ( !(e->flags & RF_WEAPONMODEL || e->flags & RF_VIEWERMODEL || e->renderfx & RF2_CAMERAMODEL) ) { if (R_CullAliasModel(bbox, e)) return; } aliasShadowAlpha = R_CalcShadowAlpha(e); if (aliasShadowAlpha < DIV255) // out of range return; if (e->renderfx & RF2_CAMERAMODEL) { if (r_lefthand->value==1) mirrormodel = true; } else if (e->flags & RF_MIRRORMODEL) mirrormodel = true; paliashdr = (maliasmodel_t *)currentmodel->extradata; // mirroring support // if (mirrormodel) // R_FlipModel(true); if ( (e->frame >= paliashdr->num_frames) || (e->frame < 0) ) { e->frame = 0; e->oldframe = 0; } if ( (e->oldframe >= paliashdr->num_frames) || (e->oldframe < 0)) { e->frame = 0; e->oldframe = 0; } //if ( !r_lerpmodels->value ) // e->backlerp = 0; qglPushMatrix (); GL_DisableTexture(0); GL_Enable (GL_BLEND); if (r_shadows->value == 3) { e->angles[ROLL] = -e->angles[ROLL]; // roll is backwards R_RotateForEntity (e, true); e->angles[ROLL] = -e->angles[ROLL]; // roll is backwards R_DrawAliasVolumeShadow (paliashdr, bbox); } else { R_RotateForEntity (e, false); R_DrawAliasPlanarShadow (paliashdr); } GL_Disable (GL_BLEND); GL_EnableTexture(0); qglPopMatrix (); // mirroring support // if (mirrormodel) // R_FlipModel(false); }
/* ================= R_DrawAliasModel ================= */ void R_DrawAliasModel (entity_t *e) { int i, j; int lnum; vec3_t dist; float add; model_t *clmodel; vec3_t mins, maxs; aliashdr_t *paliashdr; trivertx_t *verts, *v; int index; float s, t, an; int anim; clmodel = currententity->model; VectorAdd (currententity->origin, clmodel->mins, mins); VectorAdd (currententity->origin, clmodel->maxs, maxs); if (R_CullBox (mins, maxs)) return; VectorCopy (currententity->origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); // // get lighting information // ambientlight = shadelight = R_LightPoint (currententity->origin); // allways give the gun some light if (e == &cl.viewent && ambientlight < 24) ambientlight = shadelight = 24; for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++) { if (cl_dlights[lnum].die >= cl.time) { VectorSubtract (currententity->origin, cl_dlights[lnum].origin, dist); add = cl_dlights[lnum].radius - Length(dist); if (add > 0) { ambientlight += add; //ZOID models should be affected by dlights as well shadelight += add; } } } // clamp lighting so it doesn't overbright as much if (ambientlight > 128) ambientlight = 128; if (ambientlight + shadelight > 192) shadelight = 192 - ambientlight; // ZOID: never allow players to go totally black i = currententity - cl_entities; if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */) if (ambientlight < 8) ambientlight = shadelight = 8; // HACK HACK HACK -- no fullbright colors, so make torches full light if (!strcmp (clmodel->name, "progs/flame2.mdl") || !strcmp (clmodel->name, "progs/flame.mdl") ) ambientlight = shadelight = 256; shadedots = r_avertexnormal_dots[((int)(e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; shadelight = shadelight / 200.0; an = e->angles[1]/180*M_PI; shadevector[0] = cos(-an); shadevector[1] = sin(-an); shadevector[2] = 1; VectorNormalize (shadevector); // // locate the proper data // paliashdr = (aliashdr_t *)Mod_Extradata (currententity->model); c_alias_polys += paliashdr->numtris; // // draw all the triangles // GL_DisableMultitexture(); glPushMatrix (); R_RotateForEntity (e); if (!strcmp (clmodel->name, "progs/eyes.mdl") && gl_doubleeyes.value) { glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2] - (22 + 8)); // double size of eyes, since they are really hard to see in gl glScalef (paliashdr->scale[0]*2, paliashdr->scale[1]*2, paliashdr->scale[2]*2); } else { glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]); glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]); } anim = (int)(cl.time*10) & 3; GL_Bind(paliashdr->gl_texturenum[currententity->skinnum][anim]); // we can't dynamically colormap textures, so they are cached // seperately for the players. Heads are just uncolored. if (currententity->colormap != vid.colormap && !gl_nocolors.value) { i = currententity - cl_entities; if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */) GL_Bind(playertextures - 1 + i); } if (gl_smoothmodels.value) glShadeModel (GL_SMOOTH); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); if (gl_affinemodels.value) glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); R_SetupAliasFrame (currententity->frame, paliashdr); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glShadeModel (GL_FLAT); if (gl_affinemodels.value) glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glPopMatrix (); if (r_shadows.value) { glPushMatrix (); R_RotateForEntity (e); glDisable (GL_TEXTURE_2D); glEnable (GL_BLEND); glColor4f (0,0,0,0.5); GL_DrawAliasShadow (paliashdr, lastposenum); glEnable (GL_TEXTURE_2D); glDisable (GL_BLEND); glColor4f (1,1,1,1); glPopMatrix (); } }
/* ================= R_DrawAliasModel -- johnfitz -- almost completely rewritten ================= */ void R_DrawAliasModel (entity_t *e) { aliashdr_t *paliashdr; int i, anim; gltexture_t *tx, *fb; lerpdata_t lerpdata; // // setup pose/lerp data -- do it first so we don't miss updates due to culling // paliashdr = (aliashdr_t *)Mod_Extradata (e->model); R_SetupAliasFrame (paliashdr, e->frame, &lerpdata); R_SetupEntityTransform (e, &lerpdata); // // cull it // if (R_CullModelForEntity(e)) return; // // transform it // glPushMatrix (); R_RotateForEntity (lerpdata.origin, lerpdata.angles); glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]); glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]); // // random stuff // if (gl_smoothmodels.value && !r_drawflat_cheatsafe) glShadeModel (GL_SMOOTH); if (gl_affinemodels.value) glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); overbright = gl_overbright_models.value; shading = true; // // set up for alpha blending // if (r_drawflat_cheatsafe || r_lightmap_cheatsafe) //no alpha in drawflat or lightmap mode entalpha = 1; else entalpha = ENTALPHA_DECODE(e->alpha); if (entalpha == 0) goto cleanup; if (entalpha < 1) { if (!gl_texture_env_combine) overbright = false; //overbright can't be done in a single pass without combiners glDepthMask(GL_FALSE); glEnable(GL_BLEND); } // // set up lighting // rs_aliaspolys += paliashdr->numtris; R_SetupAliasLighting (e); // // set up textures // GL_DisableMultitexture(); anim = (int)(cl.time*10) & 3; tx = paliashdr->gltextures[e->skinnum][anim]; fb = paliashdr->fbtextures[e->skinnum][anim]; if (e->colormap != vid.colormap && !gl_nocolors.value) { i = e - cl_entities; if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */) tx = playertextures[i - 1]; } if (!gl_fullbrights.value) fb = NULL; // // draw it // if (r_drawflat_cheatsafe) { glDisable (GL_TEXTURE_2D); GL_DrawAliasFrame (paliashdr, lerpdata); glEnable (GL_TEXTURE_2D); srand((int) (cl.time * 1000)); //restore randomness } else if (r_fullbright_cheatsafe) { GL_Bind (tx); shading = false; glColor4f(1,1,1,entalpha); GL_DrawAliasFrame (paliashdr, lerpdata); if (fb) { glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); GL_Bind(fb); glEnable(GL_BLEND); glBlendFunc (GL_ONE, GL_ONE); glDepthMask(GL_FALSE); glColor3f(entalpha,entalpha,entalpha); Fog_StartAdditive (); GL_DrawAliasFrame (paliashdr, lerpdata); Fog_StopAdditive (); glDepthMask(GL_TRUE); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); } } else if (r_lightmap_cheatsafe) { glDisable (GL_TEXTURE_2D); shading = false; glColor3f(1,1,1); GL_DrawAliasFrame (paliashdr, lerpdata); glEnable (GL_TEXTURE_2D); } else if (overbright) { if (gl_texture_env_combine && gl_mtexable && gl_texture_env_add && fb) //case 1: everything in one pass { GL_Bind (tx); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f); GL_EnableMultitexture(); // selects TEXTURE1 GL_Bind (fb); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD); glEnable(GL_BLEND); GL_DrawAliasFrame (paliashdr, lerpdata); glDisable(GL_BLEND); GL_DisableMultitexture(); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } else if (gl_texture_env_combine) //case 2: overbright in one pass, then fullbright pass { // first pass GL_Bind(tx); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f); GL_DrawAliasFrame (paliashdr, lerpdata); glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0f); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // second pass if (fb) { glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); GL_Bind(fb); glEnable(GL_BLEND); glBlendFunc (GL_ONE, GL_ONE); glDepthMask(GL_FALSE); shading = false; glColor3f(entalpha,entalpha,entalpha); Fog_StartAdditive (); GL_DrawAliasFrame (paliashdr, lerpdata); Fog_StopAdditive (); glDepthMask(GL_TRUE); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } } else //case 3: overbright in two passes, then fullbright pass { // first pass GL_Bind(tx); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); GL_DrawAliasFrame (paliashdr, lerpdata); // second pass -- additive with black fog, to double the object colors but not the fog color glEnable(GL_BLEND); glBlendFunc (GL_ONE, GL_ONE); glDepthMask(GL_FALSE); Fog_StartAdditive (); GL_DrawAliasFrame (paliashdr, lerpdata); Fog_StopAdditive (); glDepthMask(GL_TRUE); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); // third pass if (fb) { glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); GL_Bind(fb); glEnable(GL_BLEND); glBlendFunc (GL_ONE, GL_ONE); glDepthMask(GL_FALSE); shading = false; glColor3f(entalpha,entalpha,entalpha); Fog_StartAdditive (); GL_DrawAliasFrame (paliashdr, lerpdata); Fog_StopAdditive (); glDepthMask(GL_TRUE); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } } } else { if (gl_mtexable && gl_texture_env_add && fb) //case 4: fullbright mask using multitexture { GL_DisableMultitexture(); // selects TEXTURE0 GL_Bind (tx); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); GL_EnableMultitexture(); // selects TEXTURE1 GL_Bind (fb); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD); glEnable(GL_BLEND); GL_DrawAliasFrame (paliashdr, lerpdata); glDisable(GL_BLEND); GL_DisableMultitexture(); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } else //case 5: fullbright mask without multitexture { // first pass GL_Bind(tx); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); GL_DrawAliasFrame (paliashdr, lerpdata); // second pass if (fb) { GL_Bind(fb); glEnable(GL_BLEND); glBlendFunc (GL_ONE, GL_ONE); glDepthMask(GL_FALSE); shading = false; glColor3f(entalpha,entalpha,entalpha); Fog_StartAdditive (); GL_DrawAliasFrame (paliashdr, lerpdata); Fog_StopAdditive (); glDepthMask(GL_TRUE); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); } } } cleanup: glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glShadeModel (GL_FLAT); glDepthMask(GL_TRUE); glDisable(GL_BLEND); glColor3f(1,1,1); glPopMatrix (); }
/* ================= R_GetPortalOrientation entityNum is the entity that the portal surface is a part of, which may be moving and rotating. Returns qtrue if it should be mirrored ================= */ qboolean R_GetPortalOrientations( drawSurf_t *drawSurf, int entityNum, orientation_t *surface, orientation_t *camera, vec3_t pvsOrigin, qboolean *mirror ) { int i; cplane_t originalPlane, plane; trRefEntity_t *e; float d; vec3_t transformed; // create plane axis for the portal we are seeing R_PlaneForSurface( drawSurf->surface, &originalPlane ); // rotate the plane if necessary if ( entityNum != TR_WORLDENT ) { tr.currentEntityNum = entityNum; tr.currentEntity = &tr.refdef.entities[entityNum]; // get the orientation of the entity R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.or ); // rotate the plane, but keep the non-rotated version for matching // against the portalSurface entities R_LocalNormalToWorld( originalPlane.normal, plane.normal ); plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.or.origin ); // translate the original plane originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin ); } else { plane = originalPlane; } VectorCopy( plane.normal, surface->axis[0] ); PerpendicularVector( surface->axis[1], surface->axis[0] ); CrossProduct( surface->axis[0], surface->axis[1], surface->axis[2] ); // locate the portal entity closest to this plane. // origin will be the origin of the portal, origin2 will be // the origin of the camera for ( i = 0 ; i < tr.refdef.num_entities ; i++ ) { e = &tr.refdef.entities[i]; if ( e->e.reType != RT_PORTALSURFACE ) { continue; } d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist; if ( d > 64 || d < -64) { continue; } // get the pvsOrigin from the entity VectorCopy( e->e.oldorigin, pvsOrigin ); // if the entity is just a mirror, don't use as a camera point if ( e->e.oldorigin[0] == e->e.origin[0] && e->e.oldorigin[1] == e->e.origin[1] && e->e.oldorigin[2] == e->e.origin[2] ) { VectorScale( plane.normal, plane.dist, surface->origin ); VectorCopy( surface->origin, camera->origin ); VectorSubtract( vec3_origin, surface->axis[0], camera->axis[0] ); VectorCopy( surface->axis[1], camera->axis[1] ); VectorCopy( surface->axis[2], camera->axis[2] ); *mirror = qtrue; return qtrue; } // project the origin onto the surface plane to get // an origin point we can rotate around d = DotProduct( e->e.origin, plane.normal ) - plane.dist; VectorMA( e->e.origin, -d, surface->axis[0], surface->origin ); // now get the camera origin and orientation VectorCopy( e->e.oldorigin, camera->origin ); AxisCopy( e->e.axis, camera->axis ); VectorSubtract( vec3_origin, camera->axis[0], camera->axis[0] ); VectorSubtract( vec3_origin, camera->axis[1], camera->axis[1] ); // optionally rotate if ( e->e.frame ) { // continuous rotate d = (tr.refdef.time/1000.0f) * e->e.frame; VectorCopy( camera->axis[1], transformed ); RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); } else if (e->e.skinNum){ // bobbing rotate //d = 4 * sin( tr.refdef.time * 0.003 ); d = e->e.skinNum; VectorCopy( camera->axis[1], transformed ); RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); } *mirror = qfalse; return qtrue; } // if we didn't locate a portal entity, don't render anything. // We don't want to just treat it as a mirror, because without a // portal entity the server won't have communicated a proper entity set // in the snapshot // unfortunately, with local movement prediction it is easily possible // to see a surface before the server has communicated the matching // portal surface entity, so we don't want to print anything here... //VID_Printf( PRINT_ALL, "Portal surface without a portal entity\n" ); return qfalse; }
void GL_DrawAliasShadow (entity_t *e, dmdl_t *paliashdr, int posenum) { dtrivertx_t *verts; int *order; vec3_t point; float height, lheight; int count; daliasframe_t *frame; lheight = currententity->origin[2] - lightspot[2]; frame = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames + currententity->frame * paliashdr->framesize); verts = frame->verts; // height = 0; order = (int *)((byte *)paliashdr + paliashdr->ofs_glcmds); height = -lheight + 0.1f; // was 1.0f, lowered shadows to ground more - MrG // Knightmare- don't draw shadow above entity if ((currententity->origin[2]+height) > currententity->origin[2]) return; // Knightmare- don't draw shadows above view origin if (r_newrefdef.vieworg[2] < (currententity->origin[2] + height)) return; qglPushMatrix (); R_RotateForEntity (e, false); qglDisable (GL_TEXTURE_2D); qglEnable (GL_BLEND); qglColor4f (0, 0, 0, gl_shadowalpha->value); // was 0.5 // Knightmare- Stencil shadows by MrG if (gl_config.have_stencil) { qglEnable(GL_STENCIL_TEST); qglStencilFunc(GL_EQUAL, 1, 2); qglStencilOp(GL_KEEP,GL_KEEP,GL_INCR); } // End Stencil shadows - MrG while (1) { // get the vertex count and primitive type count = *order++; if (!count) break; // done if (count < 0) { count = -count; qglBegin (GL_TRIANGLE_FAN); } else qglBegin (GL_TRIANGLE_STRIP); do { // normals and vertexes come from the frame list /* point[0] = verts[order[2]].v[0] * frame->scale[0] + frame->translate[0]; point[1] = verts[order[2]].v[1] * frame->scale[1] + frame->translate[1]; point[2] = verts[order[2]].v[2] * frame->scale[2] + frame->translate[2]; */ memcpy( point, s_lerped[order[2]], sizeof( point ) ); point[0] -= shadevector[0]*(point[2]+lheight); point[1] -= shadevector[1]*(point[2]+lheight); point[2] = height; // height -= 0.001; qglVertex3fv (point); order += 3; // verts++; } while (--count); qglEnd (); } // Knightmare- disable Stencil shadows if (gl_config.have_stencil) qglDisable(GL_STENCIL_TEST); qglColor4f (1,1,1,1); qglEnable (GL_TEXTURE_2D); qglDisable (GL_BLEND); qglPopMatrix (); }
/* ================== RB_RenderDrawSurfList ================== */ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { shader_t *shader, *oldShader; int fogNum, oldFogNum; int entityNum, oldEntityNum; int dlighted, oldDlighted; qboolean depthRange, oldDepthRange, isCrosshair, wasCrosshair; int i; drawSurf_t *drawSurf; int oldSort; float originalTime; // save original time for entity shader offsets originalTime = backEnd.refdef.floatTime; // clear the z buffer, set the modelview, etc RB_BeginDrawingView (); // draw everything oldEntityNum = -1; backEnd.currentEntity = &tr.worldEntity; oldShader = NULL; oldFogNum = -1; oldDepthRange = qfalse; wasCrosshair = qfalse; oldDlighted = qfalse; oldSort = -1; depthRange = qfalse; backEnd.pc.c_surfaces += numDrawSurfs; for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) { if ( drawSurf->sort == oldSort ) { // fast path, same as previous sort rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); continue; } oldSort = drawSurf->sort; R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted ); // // change the tess parameters if needed // a "entityMergable" shader is a shader that can have surfaces from seperate // entities merged into a single batch, like smoke and blood puff sprites if (shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || ( entityNum != oldEntityNum && !shader->entityMergable ) ) { if (oldShader != NULL) { RB_EndSurface(); } RB_BeginSurface( shader, fogNum ); oldShader = shader; oldFogNum = fogNum; oldDlighted = dlighted; } // // change the modelview matrix if needed // if ( entityNum != oldEntityNum ) { depthRange = isCrosshair = qfalse; if ( entityNum != ENTITYNUM_WORLD ) { backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; // we have to reset the shaderTime as well otherwise image animations start // from the wrong frame tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; // set up the transformation matrix R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.or ); // set up the dynamic lighting if needed if ( backEnd.currentEntity->needDlights ) { R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); } if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK) { // hack the depth range to prevent view model from poking into walls depthRange = qtrue; if(backEnd.currentEntity->e.renderfx & RF_CROSSHAIR) isCrosshair = qtrue; } } else { backEnd.currentEntity = &tr.worldEntity; backEnd.refdef.floatTime = originalTime; backEnd.or = backEnd.viewParms.world; // we have to reset the shaderTime as well otherwise image animations on // the world (like water) continue with the wrong frame tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); } qglLoadMatrixf( backEnd.or.modelMatrix ); // // change depthrange. Also change projection matrix so first person weapon does not look like coming // out of the screen. // if (oldDepthRange != depthRange || wasCrosshair != isCrosshair) { if (depthRange) { if(backEnd.viewParms.stereoFrame != STEREO_CENTER) { if(isCrosshair) { if(oldDepthRange) { // was not a crosshair but now is, change back proj matrix qglMatrixMode(GL_PROJECTION); qglLoadMatrixf(backEnd.viewParms.projectionMatrix); qglMatrixMode(GL_MODELVIEW); } } else { viewParms_t temp = backEnd.viewParms; R_SetupProjection(&temp, r_znear->value, qfalse); qglMatrixMode(GL_PROJECTION); qglLoadMatrixf(temp.projectionMatrix); qglMatrixMode(GL_MODELVIEW); } } if(!oldDepthRange) qglDepthRange (0, 0.3); } else { if(!wasCrosshair && backEnd.viewParms.stereoFrame != STEREO_CENTER) { qglMatrixMode(GL_PROJECTION); qglLoadMatrixf(backEnd.viewParms.projectionMatrix); qglMatrixMode(GL_MODELVIEW); } qglDepthRange (0, 1); } oldDepthRange = depthRange; wasCrosshair = isCrosshair; } oldEntityNum = entityNum; } // add the triangles for this surface rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); } backEnd.refdef.floatTime = originalTime; // draw the contents of the last shader batch if (oldShader != NULL) { RB_EndSurface(); } // go back to the world modelview matrix qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); if ( depthRange ) { qglDepthRange (0, 1); } #if 0 RB_DrawSun(); #endif // darken down any stencil shadows RB_ShadowFinish(); // add light flares on lights that aren't obscured RB_RenderFlares(); }
/* ================= R_DrawAliasModel ================= */ void R_DrawAliasModel (entity_t *e) { int i; dmdl_t *paliashdr; float an; vec3_t bbox[8]; image_t *skin; if ( !( e->flags & RF_WEAPONMODEL ) ) { if ( R_CullAliasModel( bbox, e ) ) return; } if ( e->flags & RF_WEAPONMODEL ) { if ( r_lefthand->value == 2 ) return; } paliashdr = (dmdl_t *)currentmodel->extradata; // // get lighting information // // PMM - rewrote, reordered to handle new shells & mixing // PMM - 3.20 code .. replaced with original way of doing it to keep mod authors happy // if ( currententity->flags & ( RF_SHELL_HALF_DAM | RF_SHELL_GREEN | RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE ) ) { VectorClear (shadelight); if (currententity->flags & RF_SHELL_HALF_DAM) { shadelight[0] = 0.56; shadelight[1] = 0.59; shadelight[2] = 0.45; } if ( currententity->flags & RF_SHELL_DOUBLE ) { shadelight[0] = 0.9; shadelight[1] = 0.7; } if ( currententity->flags & RF_SHELL_RED ) shadelight[0] = 1.0; if ( currententity->flags & RF_SHELL_GREEN ) shadelight[1] = 1.0; if ( currententity->flags & RF_SHELL_BLUE ) shadelight[2] = 1.0; } /* // PMM -special case for godmode if ( (currententity->flags & RF_SHELL_RED) && (currententity->flags & RF_SHELL_BLUE) && (currententity->flags & RF_SHELL_GREEN) ) { for (i=0 ; i<3 ; i++) shadelight[i] = 1.0; } else if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE ) ) { VectorClear (shadelight); if ( currententity->flags & RF_SHELL_RED ) { shadelight[0] = 1.0; if (currententity->flags & (RF_SHELL_BLUE|RF_SHELL_DOUBLE) ) shadelight[2] = 1.0; } else if ( currententity->flags & RF_SHELL_BLUE ) { if ( currententity->flags & RF_SHELL_DOUBLE ) { shadelight[1] = 1.0; shadelight[2] = 1.0; } else { shadelight[2] = 1.0; } } else if ( currententity->flags & RF_SHELL_DOUBLE ) { shadelight[0] = 0.9; shadelight[1] = 0.7; } } else if ( currententity->flags & ( RF_SHELL_HALF_DAM | RF_SHELL_GREEN ) ) { VectorClear (shadelight); // PMM - new colors if ( currententity->flags & RF_SHELL_HALF_DAM ) { shadelight[0] = 0.56; shadelight[1] = 0.59; shadelight[2] = 0.45; } if ( currententity->flags & RF_SHELL_GREEN ) { shadelight[1] = 1.0; } } } //PMM - ok, now flatten these down to range from 0 to 1.0. // max_shell_val = max(shadelight[0], max(shadelight[1], shadelight[2])); // if (max_shell_val > 0) // { // for (i=0; i<3; i++) // { // shadelight[i] = shadelight[i] / max_shell_val; // } // } // pmm */ else if ( currententity->flags & RF_FULLBRIGHT ) { for (i=0 ; i<3 ; i++) shadelight[i] = 1.0; } else { R_LightPoint (currententity->origin, shadelight); // player lighting hack for communication back to server // big hack! if ( currententity->flags & RF_WEAPONMODEL ) { // pick the greatest component, which should be the same // as the mono value returned by software if (shadelight[0] > shadelight[1]) { if (shadelight[0] > shadelight[2]) r_lightlevel->value = 150*shadelight[0]; else r_lightlevel->value = 150*shadelight[2]; } else { if (shadelight[1] > shadelight[2]) r_lightlevel->value = 150*shadelight[1]; else r_lightlevel->value = 150*shadelight[2]; } } if ( gl_monolightmap->string[0] != '0' ) { float s = shadelight[0]; if ( s < shadelight[1] ) s = shadelight[1]; if ( s < shadelight[2] ) s = shadelight[2]; shadelight[0] = s; shadelight[1] = s; shadelight[2] = s; } } if ( currententity->flags & RF_MINLIGHT ) { for (i=0 ; i<3 ; i++) if (shadelight[i] > 0.1) break; if (i == 3) { shadelight[0] = 0.1; shadelight[1] = 0.1; shadelight[2] = 0.1; } } if ( currententity->flags & RF_GLOW ) { // bonus items will pulse with time float scale; float min; scale = 0.1 * sin(r_newrefdef.time*7); for (i=0 ; i<3 ; i++) { min = shadelight[i] * 0.8; shadelight[i] += scale; if (shadelight[i] < min) shadelight[i] = min; } } // ================= // PGM ir goggles color override if ( r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE) { shadelight[0] = 1.0; shadelight[1] = 0.0; shadelight[2] = 0.0; } // PGM // ================= shadedots = r_avertexnormal_dots[((int)(currententity->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; an = currententity->angles[1]/180*M_PI; shadevector[0] = cos(-an); shadevector[1] = sin(-an); shadevector[2] = 1; VectorNormalize (shadevector); // // locate the proper data // c_alias_polys += paliashdr->num_tris; // // draw all the triangles // if (currententity->flags & RF_DEPTHHACK) // hack the depth range to prevent view model from poking into walls qglDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin)); if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) ) { extern void MYgluPerspective( GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar ); qglMatrixMode( GL_PROJECTION ); qglPushMatrix(); qglLoadIdentity(); qglScalef( -1, 1, 1 ); MYgluPerspective( r_newrefdef.fov_y, ( float ) r_newrefdef.width / r_newrefdef.height, 4, 4096); qglMatrixMode( GL_MODELVIEW ); qglCullFace( GL_BACK ); } qglPushMatrix (); e->angles[PITCH] = -e->angles[PITCH]; // sigh. e->angles[ROLL] = e->angles[ROLL] * R_RollMult(); // Knightmare- roll is backwards R_RotateForEntity (e, true); e->angles[PITCH] = -e->angles[PITCH]; // sigh. e->angles[ROLL] = e->angles[ROLL] * R_RollMult(); // Knightmare- roll is backwards // select skin if (currententity->skin) skin = currententity->skin; // custom player skin else { if (currententity->skinnum >= MAX_MD2SKINS) skin = currentmodel->skins[0]; else { skin = currentmodel->skins[currententity->skinnum]; if (!skin) skin = currentmodel->skins[0]; } } if (!skin) skin = r_notexture; // fallback... GL_Bind(skin->texnum); // draw it qglShadeModel (GL_SMOOTH); GL_TexEnv( GL_MODULATE ); if ( currententity->flags & RF_TRANSLUCENT ) { qglEnable (GL_BLEND); } if ( (currententity->frame >= paliashdr->num_frames) || (currententity->frame < 0) ) { ri.Con_Printf (PRINT_ALL, "R_DrawAliasModel %s: no such frame %d\n", currentmodel->name, currententity->frame); currententity->frame = 0; currententity->oldframe = 0; } if ( (currententity->oldframe >= paliashdr->num_frames) || (currententity->oldframe < 0)) { ri.Con_Printf (PRINT_ALL, "R_DrawAliasModel %s: no such oldframe %d\n", currentmodel->name, currententity->oldframe); currententity->frame = 0; currententity->oldframe = 0; } if ( !r_lerpmodels->value ) currententity->backlerp = 0; GL_DrawAliasFrameLerp (paliashdr, currententity->backlerp); GL_TexEnv( GL_REPLACE ); qglShadeModel (GL_FLAT); qglPopMatrix (); //#if 1 if (gl_showbbox->value) // Knightmare- show bbox option { qglColor4f (1.0f, 1.0f, 1.0f, 1.0f); qglDisable( GL_CULL_FACE ); qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); qglDisable( GL_TEXTURE_2D ); /* qglBegin( GL_TRIANGLE_STRIP ); for ( i = 0; i < 8; i++ ) { qglVertex3fv( bbox[i] ); } qglEnd();*/ qglBegin( GL_QUADS ); qglVertex3fv( bbox[0] ); qglVertex3fv( bbox[1] ); qglVertex3fv( bbox[3] ); qglVertex3fv( bbox[2] ); qglVertex3fv( bbox[4] ); qglVertex3fv( bbox[5] ); qglVertex3fv( bbox[7] ); qglVertex3fv( bbox[6] ); qglVertex3fv( bbox[0] ); qglVertex3fv( bbox[1] ); qglVertex3fv( bbox[5] ); qglVertex3fv( bbox[4] ); qglVertex3fv( bbox[2] ); qglVertex3fv( bbox[3] ); qglVertex3fv( bbox[7] ); qglVertex3fv( bbox[6] ); qglEnd(); qglEnable( GL_TEXTURE_2D ); qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); qglEnable( GL_CULL_FACE ); } //#endif if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) ) { qglMatrixMode( GL_PROJECTION ); qglPopMatrix(); qglMatrixMode( GL_MODELVIEW ); qglCullFace( GL_FRONT ); } if ( currententity->flags & RF_TRANSLUCENT ) { qglDisable (GL_BLEND); } if (currententity->flags & RF_DEPTHHACK) qglDepthRange (gldepthmin, gldepthmax); if (gl_shadows->value && !(currententity->flags & (RF_TRANSLUCENT | RF_WEAPONMODEL))) { // qglPushMatrix (); // R_RotateForEntity (e, false); // qglDisable (GL_TEXTURE_2D); // qglEnable (GL_BLEND); // qglColor4f (0, 0, 0, gl_shadowalpha->value); // was 0.5 GL_DrawAliasShadow (e, paliashdr, currententity->frame ); // qglEnable (GL_TEXTURE_2D); // qglDisable (GL_BLEND); // qglPopMatrix (); } qglColor4f (1,1,1,1); }
/* * RB_RenderDrawSurfList */ void RB_RenderDrawSurfList(drawSurf_t *drawSurfs, int numDrawSurfs) { material_t *shader, *oldShader; int fogNum, oldFogNum; int entityNum, oldEntityNum; int dlighted, oldDlighted; int pshadowed, oldPshadowed; qbool depthRange, oldDepthRange, isCrosshair, wasCrosshair; int i; drawSurf_t *drawSurf; int oldSort; float originalTime; float depth[2]; FBO_t * fbo = NULL; qbool inQuery = qfalse; /* save original time for entity shader offsets */ originalTime = backEnd.refdef.floatTime; /* clear the z buffer, set the modelview, etc */ RB_BeginDrawingView (); fbo = glState.currentFBO; /* draw everything */ oldEntityNum = -1; backEnd.currentEntity = &tr.worldEntity; oldShader = NULL; oldFogNum = -1; oldDepthRange = qfalse; wasCrosshair = qfalse; oldDlighted = qfalse; oldPshadowed = qfalse; oldSort = -1; depthRange = qfalse; depth[0] = 0.f; depth[1] = 1.f; backEnd.pc.c_surfaces += numDrawSurfs; for(i = 0, drawSurf = drawSurfs; i < numDrawSurfs; i++, drawSurf++){ if(drawSurf->sort == oldSort){ /* fast path, same as previous sort */ rb_surfaceTable[ *drawSurf->surface ](drawSurf->surface); continue; } oldSort = drawSurf->sort; R_DecomposeSort(drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed); /* * change the tess parameters if needed * a "entityMergable" shader is a shader that can have surfaces from seperate * entities merged into a single batch, like smoke and blood puff sprites */ if(shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || pshadowed != oldPshadowed || (entityNum != oldEntityNum && !shader->entityMergable)){ if(oldShader != NULL){ RB_EndSurface(); } RB_BeginSurface(shader, fogNum); backEnd.pc.c_surfBatches++; oldShader = shader; oldFogNum = fogNum; oldDlighted = dlighted; oldPshadowed = pshadowed; } /* * change the modelview matrix if needed * */ if(entityNum != oldEntityNum){ qbool sunflare = qfalse; depthRange = isCrosshair = qfalse; #ifdef REACTION /* if we were rendering to a FBO and the previous entity was a sunflare * and the current one isn't, switch back to the main fbo */ if(oldEntityNum != -1 && fbo && RF_SUNFLARE == (backEnd.refdef.entities[oldEntityNum].e.renderfx & RF_SUNFLARE) && 0 == (backEnd.refdef.entities[entityNum].e.renderfx & RF_SUNFLARE)){ if(inQuery){ inQuery = qfalse; qglEndQueryARB(GL_SAMPLES_PASSED_ARB); } FBO_Bind(fbo); qglDepthRange(depth[0], depth[1]); } #endif if(entityNum != ENTITYNUM_WORLD){ backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; /* we have to reset the shaderTime as well otherwise image animations start * from the wrong frame */ tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; /* set up the transformation matrix */ R_RotateForEntity(backEnd.currentEntity, &backEnd.viewParms, &backEnd.or); /* set up the dynamic lighting if needed */ if(backEnd.currentEntity->needDlights){ R_TransformDlights(backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or); } #ifdef REACTION /* if the current entity is a sunflare */ if(backEnd.currentEntity->e.renderfx & RF_SUNFLARE){ /* if we're rendering to a fbo */ if(fbo){ copyv3(backEnd.currentEntity->e.origin, backEnd.sunFlarePos); /* switch FBO */ FBO_Bind(tr.godRaysFbo); qglClearColor(0.0f, 0.0f, 0.0f, 1.0f); qglClear(GL_COLOR_BUFFER_BIT); qglDepthRange(1.f, 1.f); if(glRefConfig.occlusionQuery && !inQuery && !backEnd.hasSunFlare){ inQuery = qtrue; tr.sunFlareQueryActive[tr.sunFlareQueryIndex] = qtrue; qglBeginQueryARB( GL_SAMPLES_PASSED_ARB, tr.sunFlareQuery[tr.sunFlareQueryIndex]); } /* backEnd.hasSunFlare = qtrue; */ sunflare = qtrue; }else{ depthRange = qtrue; } } #endif if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK){ /* hack the depth range to prevent view model from poking into walls */ depthRange = qtrue; if(backEnd.currentEntity->e.renderfx & RF_CROSSHAIR) isCrosshair = qtrue; } }else{ backEnd.currentEntity = &tr.worldEntity; backEnd.refdef.floatTime = originalTime; backEnd.or = backEnd.viewParms.world; /* we have to reset the shaderTime as well otherwise image animations on * the world (like water) continue with the wrong frame */ tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; R_TransformDlights(backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or); } GL_SetModelviewMatrix(backEnd.or.modelMatrix); /* * change depthrange. Also change projection matrix so first person weapon does not look like coming * out of the screen. * */ if(oldDepthRange != depthRange || wasCrosshair != isCrosshair){ if(depthRange){ if(backEnd.viewParms.stereoFrame != STEREO_CENTER){ if(isCrosshair){ if(oldDepthRange){ /* was not a crosshair but now is, change back proj matrix */ GL_SetProjectionMatrix( backEnd.viewParms.projectionMatrix); } }else{ viewParms_t temp = backEnd.viewParms; R_SetupProjection(&temp, r_znear->value, 0, qfalse); GL_SetProjectionMatrix(temp.projectionMatrix); } } #ifdef REACTION if(!oldDepthRange){ depth[0] = 0; depth[1] = 0.3f; qglDepthRange (0, 0.3); } #endif }else{ if(!wasCrosshair && backEnd.viewParms.stereoFrame != STEREO_CENTER){ GL_SetProjectionMatrix(backEnd.viewParms.projectionMatrix); } if(!sunflare) qglDepthRange (0, 1); depth[0] = 0; depth[1] = 1; } oldDepthRange = depthRange; wasCrosshair = isCrosshair; } oldEntityNum = entityNum; } /* add the triangles for this surface */ rb_surfaceTable[ *drawSurf->surface ](drawSurf->surface); } backEnd.refdef.floatTime = originalTime; /* draw the contents of the last shader batch */ if(oldShader != NULL){ RB_EndSurface(); } if(inQuery){ inQuery = qfalse; qglEndQueryARB(GL_SAMPLES_PASSED_ARB); } FBO_Bind(fbo); /* go back to the world modelview matrix */ GL_SetModelviewMatrix(backEnd.viewParms.world.modelMatrix); /* if ( depthRange ) { */ qglDepthRange (0, 1); /* } */ #if 0 RB_DrawSun(); #endif /* darken down any stencil shadows */ RB_ShadowFinish(); /* add light flares on lights that aren't obscured */ RB_RenderFlares(); if(glRefConfig.framebufferObject) FBO_Bind(NULL); }
/* ================== RB_RenderDrawSurfList ================== */ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { shader_t *shader, *oldShader; int fogNum, oldFogNum; int entityNum, oldEntityNum; int dlighted, oldDlighted; qboolean depthRange, oldDepthRange; int i; drawSurf_t *drawSurf; unsigned int oldSort; float originalTime; // save original time for entity shader offsets originalTime = backEnd.refdef.floatTime; // clear the z buffer, set the modelview, etc RB_BeginDrawingView (); // draw everything oldEntityNum = -1; backEnd.currentEntity = &tr.worldEntity; oldShader = NULL; oldFogNum = -1; oldDepthRange = qfalse; oldDlighted = qfalse; oldSort = (unsigned int)~0; depthRange = qfalse; backEnd.pc.c_surfaces += numDrawSurfs; for( i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++ ) { if ( drawSurf->sort == (unsigned int)oldSort ) { // fast path, same as previous sort rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); continue; } oldSort = drawSurf->sort; R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted ); // // change the tess parameters if needed // a "entityMergable" shader is a shader that can have surfaces from seperate // entities merged into a single batch, like smoke and blood puff sprites if (shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || ( entityNum != oldEntityNum && !shader->entityMergable ) ) { if (oldShader != NULL) { RB_EndSurface(); } RB_BeginSurface( shader, fogNum, GL_TRIANGLES ); oldShader = shader; oldFogNum = fogNum; oldDlighted = dlighted; } // // change the modelview matrix if needed // if ( entityNum != oldEntityNum ) { depthRange = qfalse; if ( entityNum != ENTITYNUM_WORLD ) { backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; // we have to reset the shaderTime as well otherwise image animations start // from the wrong frame tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; // set up the transformation matrix R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.or ); // set up the dynamic lighting if needed if ( backEnd.currentEntity->needDlights ) { R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); } if ( backEnd.currentEntity->e.renderfx & RF_DEPTHHACK ) { // hack the depth range to prevent view model from poking into walls depthRange = qtrue; } } else { backEnd.currentEntity = &tr.worldEntity; backEnd.refdef.floatTime = originalTime; backEnd.or = backEnd.viewParms.world; // we have to reset the shaderTime as well otherwise image animations on // the world (like water) continue with the wrong frame tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); } R_StateSetModelViewMatrixCountedRaw( backEnd.or.modelMatrix ); // // change depthrange if needed // if( oldDepthRange != depthRange ) { R_StateSetDefaultDepthRange( 0, depthRange ? 0.3F : 1.0F ); oldDepthRange = depthRange; } oldEntityNum = entityNum; } // add the triangles for this surface rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); } backEnd.refdef.floatTime = originalTime; // draw the contents of the last shader batch if( oldShader ) RB_EndSurface(); // go back to the world modelview matrix R_StateSetModelViewMatrixCountedRaw( backEnd.viewParms.world.modelMatrix ); if( depthRange ) R_StateSetDefaultDepthRange( 0, 1 ); #if 0 RB_DrawSun(); #endif // darken down any stencil shadows RB_ShadowFinish(); // add light flares on lights that aren't obscured RB_RenderFlares(); }