/* ================ HUD_UpdateFlashlight update client flashlight ================ */ void HUD_UpdateFlashlight( cl_entity_t *pEnt ) { Vector v_angles, forward, right, up; Vector v_origin; if( UTIL_IsLocal( pEnt->index )) { ref_params_t tmpRefDef = RI.refdef; // player seen through camera. Restore firstperson view here if( RI.refdef.viewentity > RI.refdef.maxclients ) V_CalcFirstPersonRefdef( &tmpRefDef ); v_angles = tmpRefDef.viewangles; v_origin = tmpRefDef.vieworg; } else { // restore viewangles from angles v_angles[PITCH] = -pEnt->angles[PITCH] * 3; v_angles[YAW] = pEnt->angles[YAW]; v_angles[ROLL] = 0; // no roll v_origin = pEnt->origin; } AngleVectors( v_angles, forward, NULL, NULL ); Vector vecEnd = v_origin + forward * FLASHLIGHT_DISTANCE; pmtrace_t trace; int traceFlags = PM_STUDIO_BOX; if( r_lighting_extended->value < 2 ) traceFlags |= PM_GLASS_IGNORE; gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); gEngfuncs.pEventAPI->EV_PlayerTrace( v_origin, vecEnd, traceFlags, -1, &trace ); float falloff = trace.fraction * FLASHLIGHT_DISTANCE; if( falloff < 250.0f ) falloff = 1.0f; else falloff = 250.0f / falloff; falloff *= falloff; // update flashlight endpos dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight( pEnt->curstate.number ); dl->origin = trace.endpos; dl->die = GET_CLIENT_TIME() + 0.01f; // die on next frame dl->color.r = bound( 0, 255 * falloff, 255 ); dl->color.g = bound( 0, 255 * falloff, 255 ); dl->color.b = bound( 0, 255 * falloff, 255 ); dl->radius = 72; }
//========================== // V_StartPitchDrift //========================== void V_StartPitchDrift( void ) { if( pd.laststop == GET_CLIENT_TIME( )) { // something else is keeping it from drifting return; } if( pd.nodrift || !pd.pitchvel ) { pd.pitchvel = v_centerspeed->value; pd.driftmove = 0; pd.nodrift = 0; } }
void R_RenderShadowmaps( void ) { ref_instance_t oldRI; if( r_fullbright->value || !r_shadows->value || RI.refdef.paused || RI.drawOrtho ) return; // check for dynamic lights if( !R_CountPlights( true )) return; oldRI = RI; // make refinst backup int oldframecount = tr.framecount; for( int i = 0; i < MAX_PLIGHTS; i++ ) { plight_t *pl = &cl_plights[i]; if( pl->die < GET_CLIENT_TIME() || !pl->radius ) continue; // TODO: allow shadows for pointlights if( pl->pointlight || FBitSet( pl->flags, CF_NOSHADOWS )) { pl->shadowTexture = 0; continue; } // don't cull by PVS, because we may cull visible shadow here if( R_CullSphereExt( RI.frustum, pl->origin, pl->radius, RI.clipFlags )) continue; RI.params = RP_SHADOWVIEW|RP_MERGEVISIBILITY; // allow screen size RI.viewport[2] = RI.viewport[3] = 512; R_RenderShadowScene( &RI.refdef, pl ); r_stats.c_shadow_passes++; pl->shadowTexture = R_AllocateShadowTexture(); RI = oldRI; // restore ref instance } tr.framecount = oldframecount; // restore real framecount }
//========================== // V_CalcCameraRefdef //========================== void V_CalcCameraRefdef( struct ref_params_s *pparams ) { static float lasttime, oldz = 0; // get viewentity and monster eyeposition cl_entity_t *view = GET_ENTITY( pparams->viewentity ); if( view ) { pparams->vieworg = view->origin; pparams->viewangles = view->angles; // interpolate position for monsters if( view->curstate.movetype == MOVETYPE_STEP ) { float f; // don't do it if the goalstarttime hasn't updated in a while. // NOTE: Because we need to interpolate multiplayer characters, the interpolation time limit // was increased to 1.0 s., which is 2x the max lag we are accounting for. if(( GET_CLIENT_TIME() < view->curstate.animtime + 1.0f ) && ( view->curstate.animtime != view->latched.prevanimtime )) { f = (GET_CLIENT_TIME() - view->curstate.animtime) / (view->curstate.animtime - view->latched.prevanimtime); } if( !( view->curstate.effects & EF_NOINTERP )) { // ugly hack to interpolate angle, position. // current is reached 0.1 seconds after being set f = f - 1.0f; } else { f = 0.0f; } InterpolateOrigin( view->latched.prevorigin, view->origin, pparams->vieworg, f, true ); InterpolateAngles( view->latched.prevangles, view->angles, pparams->viewangles, f, true ); } studiohdr_t *viewmonster = (studiohdr_t *)IEngineStudio.Mod_Extradata( view->model ); if( viewmonster && view->curstate.eflags & EFLAG_SLERP ) { Vector forward; AngleVectors( pparams->viewangles, forward, NULL, NULL ); Vector viewpos = viewmonster->eyeposition; if( viewpos == g_vecZero ) viewpos = Vector( 0, 0, 8 ); // monster_cockroach pparams->vieworg += viewpos + forward * 8; // best value for humans pparams->fov_x = 100; // adjust fov for monster view pparams->fov_y = V_CalcFov( pparams->fov_x, pparams->viewport[2], pparams->viewport[3] ); } // this is smooth stair climbing in thirdperson mode but not affected for client model :( if( !pparams->smoothing && pparams->onground && view->origin[2] - oldz > 0.0f ) { float steptime; steptime = pparams->time - lasttime; if( steptime < 0 ) steptime = 0; oldz += steptime * 150.0f; if( oldz > view->origin[2] ) oldz = view->origin[2]; if( view->origin[2] - oldz > pparams->movevars->stepsize ) oldz = view->origin[2] - pparams->movevars->stepsize; pparams->vieworg[2] += oldz - view->origin[2]; } else { oldz = view->origin[2]; } lasttime = pparams->time; if( view->curstate.effects & EF_NUKE_ROCKET ) pparams->viewangles.x = -pparams->viewangles.x; // stupid quake bug! // g-cont. apply shake to camera gEngfuncs.V_CalcShake(); gEngfuncs.V_ApplyShake( pparams->vieworg, pparams->viewangles, 1.0f ); } }
//========================== // V_StopPitchDrift //========================== void V_StopPitchDrift( void ) { pd.laststop = GET_CLIENT_TIME(); pd.nodrift = 1; pd.pitchvel = 0; }
void CParticleSystem :: DrawParticle( CParticle *part, Vector &right, Vector &up ) { float fSize = part->m_fSize; // nothing to draw? if( fSize <= 0 ) return; // frustrum visible check if( !ParticleIsVisible( part )) return; Vector point1, point2, point3, point4; Vector origin = part->origin; float fCosSize = CosLookup( part->m_fAngle ) * fSize; float fSinSize = SinLookup( part->m_fAngle ) * fSize; // calculate the four corners of the sprite point1 = origin + up * fSinSize + right * -fCosSize; point2 = origin + up * fCosSize + right * fSinSize; point3 = origin + up * -fSinSize + right * fCosSize; point4 = origin + up * -fCosSize + right * -fSinSize; int iContents = CONTENTS_NONE; model_t *pModel; for( CParticle *pDraw = part; pDraw; pDraw = pDraw->m_pOverlay ) { if( !pDraw->pType->m_hSprite ) continue; if( pDraw->pType->m_iDrawCond ) { if( pDraw->pType->m_iDrawCond == CONTENT_SPOTLIGHT ) { if( !R_CountPlights( )) continue; // fast reject for( int i = 0; i < MAX_PLIGHTS; i++ ) { plight_t *pl = &cl_plights[i]; if( pl->die < GET_CLIENT_TIME() || !pl->radius ) continue; if( !R_CullSphereExt( pl->frustum, part->origin, part->m_fSize + 1, pl->clipflags )) break; // cone intersected with particle } if( i == MAX_PLIGHTS ) continue; // no intersection } else { if( iContents == CONTENTS_NONE ) iContents = POINT_CONTENTS( origin ); if( iContents != pDraw->pType->m_iDrawCond ) continue; } } pModel = (model_t *)gEngfuncs.GetSpritePointer( pDraw->pType->m_hSprite ); // if we've reached the end of the sprite's frames, loop back while (pDraw->frame > pModel->numframes) pDraw->frame -= pModel->numframes; while (pDraw->frame < 0) pDraw->frame += pModel->numframes; if( !TriSpriteTexture( pModel, (int)pDraw->frame )) continue; gEngfuncs.pTriAPI->RenderMode( pDraw->pType->m_iRenderMode ); if( m_iLightingModel >= 1 ) { color24 lightColor; Vector lightingColor; if( m_iLightingModel == 1 ) R_LightForPoint( part->origin, &lightColor, false, true, fSize + 1 ); else R_LightForPoint( part->origin, &lightColor, false, true, 0.0f ); // FIXME: this code is totally wrong. // We need a fake lightmap here like in sprite implementation lightingColor.x = pDraw->m_fRed * lightColor.r * (1.0f / 255.0f); lightingColor.y = pDraw->m_fGreen * lightColor.g * (1.0f / 255.0f); lightingColor.z = pDraw->m_fBlue * lightColor.b * (1.0f / 255.0f); pglColor4f( lightingColor.x, lightingColor.y, lightingColor.z, pDraw->m_fAlpha ); } else pglColor4f( pDraw->m_fRed, pDraw->m_fGreen, pDraw->m_fBlue, pDraw->m_fAlpha ); pglBegin( GL_QUADS ); pglTexCoord2f( 0.0f, 0.0f ); pglVertex3fv( point1 ); pglTexCoord2f( 1.0f, 0.0f ); pglVertex3fv( point2 ); pglTexCoord2f( 1.0f, 1.0f ); pglVertex3fv( point3 ); pglTexCoord2f( 0.0f, 1.0f ); pglVertex3fv( point4 ); pglEnd(); if( m_iLightingModel >=2 && R_CountPlights( )) { for( int i = 0; i < MAX_PLIGHTS; i++ ) { plight_t *pl = &cl_plights[i]; if( pl->die < GET_CLIENT_TIME() || !pl->radius ) continue; if( R_CullSphereExt( pl->frustum, part->origin, part->m_fSize + 1, pl->clipflags )) continue; R_BeginDrawProjection( pl ); pglBegin( GL_QUADS ); pglVertex3fv( point1 ); pglVertex3fv( point2 ); pglVertex3fv( point3 ); pglVertex3fv( point4 ); pglEnd(); R_EndDrawProjection(); } } } }
/* ======================== HUD_AddEntity Return 0 to filter entity from visible list for rendering ======================== */ int HUD_AddEntity( int type, struct cl_entity_s *ent, const char *modelname ) { if( g_fRenderInitialized ) { // use engine renderer if( gl_renderer->value == 0 ) return 1; if( ent->curstate.effects & EF_SKYCAMERA ) { // found env_sky tr.sky_camera = ent; return 0; } if( type == ET_BEAM ) { R_AddServerBeam( ent ); return 0; } if( !R_AddEntity( ent, type )) return 0; // apply effects if( ent->curstate.effects & EF_BRIGHTFIELD ) gEngfuncs.pEfxAPI->R_EntityParticles( ent ); // add in muzzleflash effect if( ent->curstate.effects & EF_MUZZLEFLASH ) { if( ent == gEngfuncs.GetViewModel( )) ent->curstate.effects &= ~EF_MUZZLEFLASH; // make sure what attachment is valid if( ent->origin != ent->attachment[0] ) { dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocElight( 0 ); dl->origin = ent->attachment[0]; dl->die = gEngfuncs.GetClientTime() + 0.05f; dl->color.r = 255; dl->color.g = 180; dl->color.b = 64; dl->radius = 100; } } // add light effect if( ent->curstate.effects & EF_LIGHT ) { dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight( ent->curstate.number ); dl->origin = ent->origin; dl->die = gEngfuncs.GetClientTime(); // die at next frame dl->color.r = 100; dl->color.g = 100; dl->color.b = 100; dl->radius = 200; gEngfuncs.pEfxAPI->R_RocketFlare( ent->origin ); } // add dimlight if( ent->curstate.effects & EF_DIMLIGHT ) { if( type == ET_PLAYER ) { HUD_UpdateFlashlight( ent ); } else { dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight( ent->curstate.number ); dl->origin = ent->origin; dl->die = gEngfuncs.GetClientTime(); // die at next frame dl->color.r = 255; dl->color.g = 255; dl->color.b = 255; dl->radius = gEngfuncs.pfnRandomLong( 200, 230 ); } } if( ent->curstate.effects & EF_BRIGHTLIGHT ) { dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight( 0 ); dl->origin = ent->origin; dl->origin.z += 16; dl->die = GET_CLIENT_TIME() + 0.001f; // die at next frame dl->color.r = 255; dl->color.g = 255; dl->color.b = 255; if( type == ET_PLAYER ) dl->radius = 430; else dl->radius = gEngfuncs.pfnRandomLong( 400, 430 ); } // projected light can be attached like as normal dlight if( ent->curstate.effects & EF_PROJECTED_LIGHT ) { plight_t *pl = CL_AllocPlight( ent->curstate.number ); float factor = 1.0f; if( ent->curstate.renderfx ) { factor = RI.lightstylevalue[ent->curstate.renderfx] * (1.0f/255.0f); } if( ent->curstate.rendercolor.r == 0 && ent->curstate.rendercolor.g == 0 && ent->curstate.rendercolor.b == 0 ) { pl->color.r = pl->color.g = pl->color.b = 255; } else { pl->color.r = ent->curstate.rendercolor.r; pl->color.g = ent->curstate.rendercolor.g; pl->color.b = ent->curstate.rendercolor.b; } pl->color.r *= factor; pl->color.g *= factor; pl->color.b *= factor; float radius = ent->curstate.scale ? (ent->curstate.scale * 8.0f) : 500; // default light radius float fov = ent->curstate.iuser2 ? ent->curstate.iuser2 : 50; pl->die = GET_CLIENT_TIME() + 0.05f; // die at next frame pl->flags = ent->curstate.iuser1; Vector origin, angles; R_GetLightVectors( ent, origin, angles ); R_SetupLightProjectionTexture( pl, ent ); R_SetupLightProjection( pl, origin, angles, radius, fov ); R_SetupLightAttenuationTexture( pl, ent->curstate.renderamt ); } // dynamic light can be attached like as normal dlight if( ent->curstate.effects & EF_DYNAMIC_LIGHT ) { if( tr.attenuationTexture3D && tr.dlightCubeTexture ) { plight_t *pl = CL_AllocPlight( ent->curstate.number ); float factor = 1.0f; if( ent->curstate.renderfx ) { factor = RI.lightstylevalue[ent->curstate.renderfx] * (1.0f/255.0f); factor = bound( 0.0f, factor, 1.0f ); } if( ent->curstate.rendercolor.r == 0 && ent->curstate.rendercolor.g == 0 && ent->curstate.rendercolor.b == 0 ) { pl->color.r = pl->color.g = pl->color.b = 255; } else { pl->color.r = ent->curstate.rendercolor.r; pl->color.g = ent->curstate.rendercolor.g; pl->color.b = ent->curstate.rendercolor.b; } pl->color.r *= factor; pl->color.g *= factor; pl->color.b *= factor; float radius = ent->curstate.scale ? (ent->curstate.scale * 8.0f) : 300; // default light radius pl->die = GET_CLIENT_TIME() + 0.05f; // die at next frame pl->flags = ent->curstate.iuser1; pl->projectionTexture = tr.dlightCubeTexture; pl->pointlight = true; Vector origin, angles; R_GetLightVectors( ent, origin, angles ); if( pl->flags & CF_NOLIGHT_IN_SOLID ) { pmtrace_t tr; // test the lights who stuck in the solid geometry gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); gEngfuncs.pEventAPI->EV_PlayerTrace( origin, origin, PM_STUDIO_IGNORE, -1, &tr ); // an experimental feature for point lights if( tr.allsolid ) radius = 0.0f; } if( radius != 0.0f ) { R_SetupLightProjection( pl, origin, angles, radius, 90.0f ); R_SetupLightAttenuationTexture( pl ); } else { // light in solid pl->radius = 0.0f; } } else { // cubemaps or 3d textures isn't supported: use old-style dlights dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight( 0 ); if( ent->curstate.rendercolor.r == 0 && ent->curstate.rendercolor.g == 0 && ent->curstate.rendercolor.b == 0 ) { dl->color.r = dl->color.g = dl->color.b = 255; } else { dl->color.r = ent->curstate.rendercolor.r; dl->color.g = ent->curstate.rendercolor.g; dl->color.b = ent->curstate.rendercolor.b; } dl->radius = ent->curstate.scale ? (ent->curstate.scale * 8.0f) : 300; // default light radius dl->die = GET_CLIENT_TIME() + 0.001f; // die at next frame dl->origin = ent->origin; } } if( ent->model->type == mod_studio ) { if (ent->model->flags & STUDIO_ROTATE) ent->angles[1] = anglemod(100 * GET_CLIENT_TIME()); if( ent->model->flags & STUDIO_GIB ) gEngfuncs.pEfxAPI->R_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 2 ); else if( ent->model->flags & STUDIO_ZOMGIB ) gEngfuncs.pEfxAPI->R_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 4 ); else if( ent->model->flags & STUDIO_TRACER ) gEngfuncs.pEfxAPI->R_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 3 ); else if( ent->model->flags & STUDIO_TRACER2 ) gEngfuncs.pEfxAPI->R_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 5 ); else if( ent->model->flags & STUDIO_ROCKET ) { dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight( ent->curstate.number ); dl->origin = ent->origin; dl->color.r = 255; dl->color.g = 255; dl->color.b = 255; // HACKHACK: get radius from head entity if( ent->curstate.rendermode != kRenderNormal ) dl->radius = max( 0, ent->curstate.renderamt - 55 ); else dl->radius = 200; dl->die = GET_CLIENT_TIME() + 0.01; gEngfuncs.pEfxAPI->R_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 0 ); } else if( ent->model->flags & STUDIO_GRENADE ) gEngfuncs.pEfxAPI->R_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 1 ); else if( ent->model->flags & STUDIO_TRACER3 ) gEngfuncs.pEfxAPI->R_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 6 ); } return 0; } return 1; }