void UpdateAvatarEffect(void) { if(!haptics->HasDevice()) return; Vector vel; Vector vvel; Vector evel; QAngle eye; C_BasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer(); if(!pPlayer) return; eye = pPlayer->GetAbsAngles(); if(pPlayer->IsInAVehicle() && pPlayer->GetVehicle()) { pPlayer->GetVehicle()->GetVehicleEnt()->EstimateAbsVelocity(vvel); eye = pPlayer->GetVehicle()->GetVehicleEnt()->EyeAngles(); if(!Q_stristr(pPlayer->GetVehicle()->GetVehicleEnt()->GetClassname(),"choreo")) { eye[YAW] += 90; } } else { vel = pPlayer->GetAbsVelocity(); } Vector PlayerVel = pPlayer->GetAbsVelocity(); //Choreo vehicles use player avatar and don't produce their own velocity if(!pPlayer->GetVehicle() || abs(vvel.Length()) == 0 ) { vel = PlayerVel; } else vel = vvel; VectorYawRotate(vel, -90 -eye[YAW], vel ); vel.y = -vel.y; vel.z = -vel.z; switch(pPlayer->GetMoveType()) { case MOVETYPE_NOCLIP: vel *= hap_noclip_avatar_scale.GetFloat(); break; default: break; } haptics->UpdateAvatarVelocity(vel); }
static void GetPos( const CCommand &args, Vector &vecOrigin, QAngle &angles ) { vecOrigin = MainViewOrigin(); angles = MainViewAngles(); if ( args.ArgC() == 2 && atoi( args[1] ) == 2 ) { C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if ( pPlayer ) { vecOrigin = pPlayer->GetAbsOrigin(); angles = pPlayer->GetAbsAngles(); } } }
void CreateHairballCallback() { for ( int i=0; i < 20; i++ ) { C_Hairball *pHairball = new C_Hairball; pHairball->Init(); // Put it a short distance in front of the player. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if ( !pPlayer ) return; Vector vForward; AngleVectors( pPlayer->GetAbsAngles(), &vForward ); pHairball->SetLocalOrigin( pPlayer->GetAbsOrigin() + vForward * 300 + RandomVector( 0, 100 ) ); } }
static void GetPos( const CCommand &args, Vector &vecOrigin, QAngle &angles ) { int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT(); vecOrigin = MainViewOrigin(nSlot); angles = MainViewAngles(nSlot); #ifdef INFESTED_DLL C_ASW_Marine *pMarine = C_ASW_Marine::GetLocalMarine(); if ( pMarine ) { vecOrigin = pMarine->GetAbsOrigin(); angles = pMarine->GetAbsAngles(); } #endif if ( ( args.ArgC() == 2 && atoi( args[1] ) == 2 ) || FStrEq( args[0], "getpos_exact" ) ) { C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if ( pPlayer ) { vecOrigin = pPlayer->GetAbsOrigin(); angles = pPlayer->GetAbsAngles(); } } }
//----------------------------------------------------------------------------- // Purpose: Moves the client pitch angle towards cl.idealpitch sent by the server. // If the user is adjusting pitch manually, either with lookup/lookdown, // mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped. //----------------------------------------------------------------------------- void CViewRender::DriftPitch (void) { float delta, move; C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); if ( !player ) return; #if defined( REPLAY_ENABLED ) if ( engine->IsHLTV() || g_pEngineClientReplay->IsPlayingReplayDemo() || ( player->GetGroundEntity() == NULL ) || engine->IsPlayingDemo() ) #else if ( engine->IsHLTV() || ( player->GetGroundEntity() == NULL ) || engine->IsPlayingDemo() ) #endif { m_PitchDrift.driftmove = 0; m_PitchDrift.pitchvel = 0; return; } // Don't count small mouse motion if ( m_PitchDrift.nodrift ) { if ( fabs( input->GetLastForwardMove() ) < cl_forwardspeed.GetFloat() ) { m_PitchDrift.driftmove = 0; } else { m_PitchDrift.driftmove += gpGlobals->frametime; } if ( m_PitchDrift.driftmove > v_centermove.GetFloat() ) { StartPitchDrift (); } return; } // How far off are we delta = prediction->GetIdealPitch() - player->GetAbsAngles()[ PITCH ]; if ( !delta ) { m_PitchDrift.pitchvel = 0; return; } // Determine movement amount move = gpGlobals->frametime * m_PitchDrift.pitchvel; // Accelerate m_PitchDrift.pitchvel += gpGlobals->frametime * v_centerspeed.GetFloat(); // Move predicted pitch appropriately if (delta > 0) { if ( move > delta ) { m_PitchDrift.pitchvel = 0; move = delta; } player->SetLocalAngles( player->GetLocalAngles() + QAngle( move, 0, 0 ) ); } else if ( delta < 0 ) { if ( move > -delta ) { m_PitchDrift.pitchvel = 0; move = -delta; } player->SetLocalAngles( player->GetLocalAngles() - QAngle( move, 0, 0 ) ); } }
void C_EnvProjectedTexture::UpdateLight( void ) { VPROF("C_EnvProjectedTexture::UpdateLight"); bool bVisible = true; Vector vLinearFloatLightColor( m_LightColor.r, m_LightColor.g, m_LightColor.b ); float flLinearFloatLightAlpha = m_LightColor.a; if ( m_bAlwaysUpdate ) { m_bForceUpdate = true; } if ( m_CurrentLinearFloatLightColor != vLinearFloatLightColor || m_flCurrentLinearFloatLightAlpha != flLinearFloatLightAlpha ) { float flColorTransitionSpeed = gpGlobals->frametime * m_flColorTransitionTime * 255.0f; m_CurrentLinearFloatLightColor.x = Approach( vLinearFloatLightColor.x, m_CurrentLinearFloatLightColor.x, flColorTransitionSpeed ); m_CurrentLinearFloatLightColor.y = Approach( vLinearFloatLightColor.y, m_CurrentLinearFloatLightColor.y, flColorTransitionSpeed ); m_CurrentLinearFloatLightColor.z = Approach( vLinearFloatLightColor.z, m_CurrentLinearFloatLightColor.z, flColorTransitionSpeed ); m_flCurrentLinearFloatLightAlpha = Approach( flLinearFloatLightAlpha, m_flCurrentLinearFloatLightAlpha, flColorTransitionSpeed ); m_bForceUpdate = true; } if ( !m_bForceUpdate ) { bVisible = IsBBoxVisible(); } if ( m_bState == false || !bVisible ) { // Spotlight's extents aren't in view ShutDownLightHandle(); return; } if ( m_LightHandle == CLIENTSHADOW_INVALID_HANDLE || m_hTargetEntity != NULL || m_bForceUpdate ) { Vector vForward, vRight, vUp, vPos = GetAbsOrigin(); FlashlightState_t state; if ( m_hTargetEntity != NULL ) { if ( m_bCameraSpace ) { const QAngle &angles = GetLocalAngles(); C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if( pPlayer ) { const QAngle playerAngles = pPlayer->GetAbsAngles(); Vector vPlayerForward, vPlayerRight, vPlayerUp; AngleVectors( playerAngles, &vPlayerForward, &vPlayerRight, &vPlayerUp ); matrix3x4_t mRotMatrix; AngleMatrix( angles, mRotMatrix ); VectorITransform( vPlayerForward, mRotMatrix, vForward ); VectorITransform( vPlayerRight, mRotMatrix, vRight ); VectorITransform( vPlayerUp, mRotMatrix, vUp ); float dist = (m_hTargetEntity->GetAbsOrigin() - GetAbsOrigin()).Length(); vPos = m_hTargetEntity->GetAbsOrigin() - vForward*dist; VectorNormalize( vForward ); VectorNormalize( vRight ); VectorNormalize( vUp ); } } else { vForward = m_hTargetEntity->GetAbsOrigin() - GetAbsOrigin(); VectorNormalize( vForward ); // JasonM - unimplemented Assert (0); //Quaternion q = DirectionToOrientation( dir ); // // JasonM - set up vRight, vUp // // VectorNormalize( vRight ); // VectorNormalize( vUp ); } } else { AngleVectors( GetAbsAngles(), &vForward, &vRight, &vUp ); } state.m_fHorizontalFOVDegrees = m_flLightFOV; state.m_fVerticalFOVDegrees = m_flLightFOV; state.m_vecLightOrigin = vPos; BasisToQuaternion( vForward, vRight, vUp, state.m_quatOrientation ); state.m_NearZ = m_flNearZ; state.m_FarZ = m_flFarZ; // quickly check the proposed light's bbox against the view frustum to determine whether we // should bother to create it, if it doesn't exist, or cull it, if it does. if ( m_bSimpleProjection == false ) { #pragma message("OPTIMIZATION: this should be made SIMD") // get the half-widths of the near and far planes, // based on the FOV which is in degrees. Remember that // on planet Valve, x is forward, y left, and z up. const float tanHalfAngle = tan( m_flLightFOV * ( M_PI/180.0f ) * 0.5f ); const float halfWidthNear = tanHalfAngle * m_flNearZ; const float halfWidthFar = tanHalfAngle * m_flFarZ; // now we can build coordinates in local space: the near rectangle is eg // (0, -halfWidthNear, -halfWidthNear), (0, halfWidthNear, -halfWidthNear), // (0, halfWidthNear, halfWidthNear), (0, -halfWidthNear, halfWidthNear) VectorAligned vNearRect[4] = { VectorAligned( m_flNearZ, -halfWidthNear, -halfWidthNear), VectorAligned( m_flNearZ, halfWidthNear, -halfWidthNear), VectorAligned( m_flNearZ, halfWidthNear, halfWidthNear), VectorAligned( m_flNearZ, -halfWidthNear, halfWidthNear) }; VectorAligned vFarRect[4] = { VectorAligned( m_flFarZ, -halfWidthFar, -halfWidthFar), VectorAligned( m_flFarZ, halfWidthFar, -halfWidthFar), VectorAligned( m_flFarZ, halfWidthFar, halfWidthFar), VectorAligned( m_flFarZ, -halfWidthFar, halfWidthFar) }; matrix3x4_t matOrientation( vForward, -vRight, vUp, vPos ); enum { kNEAR = 0, kFAR = 1, }; VectorAligned vOutRects[2][4]; for ( int i = 0 ; i < 4 ; ++i ) { VectorTransform( vNearRect[i].Base(), matOrientation, vOutRects[0][i].Base() ); } for ( int i = 0 ; i < 4 ; ++i ) { VectorTransform( vFarRect[i].Base(), matOrientation, vOutRects[1][i].Base() ); } // now take the MIN and MAX extents for the bbox, and see if it is visible. Vector mins = **vOutRects; Vector maxs = **vOutRects; for ( int i = 1; i < 8 ; ++i ) { VectorMin( mins, *(*vOutRects+i), mins ); VectorMax( maxs, *(*vOutRects+i), maxs ); } #if 0 //for debugging the visibility frustum we just calculated NDebugOverlay::Triangle( vOutRects[0][0], vOutRects[0][1], vOutRects[0][2], 255, 0, 0, 100, true, 0.0f ); //first tri NDebugOverlay::Triangle( vOutRects[0][2], vOutRects[0][1], vOutRects[0][0], 255, 0, 0, 100, true, 0.0f ); //make it double sided NDebugOverlay::Triangle( vOutRects[0][2], vOutRects[0][3], vOutRects[0][0], 255, 0, 0, 100, true, 0.0f ); //second tri NDebugOverlay::Triangle( vOutRects[0][0], vOutRects[0][3], vOutRects[0][2], 255, 0, 0, 100, true, 0.0f ); //make it double sided NDebugOverlay::Triangle( vOutRects[1][0], vOutRects[1][1], vOutRects[1][2], 0, 0, 255, 100, true, 0.0f ); //first tri NDebugOverlay::Triangle( vOutRects[1][2], vOutRects[1][1], vOutRects[1][0], 0, 0, 255, 100, true, 0.0f ); //make it double sided NDebugOverlay::Triangle( vOutRects[1][2], vOutRects[1][3], vOutRects[1][0], 0, 0, 255, 100, true, 0.0f ); //second tri NDebugOverlay::Triangle( vOutRects[1][0], vOutRects[1][3], vOutRects[1][2], 0, 0, 255, 100, true, 0.0f ); //make it double sided NDebugOverlay::Box( vec3_origin, mins, maxs, 0, 255, 0, 100, 0.0f ); #endif bool bVisible = IsBBoxVisible( mins, maxs ); if (!bVisible) { // Spotlight's extents aren't in view if ( m_LightHandle != CLIENTSHADOW_INVALID_HANDLE ) { ShutDownLightHandle(); } return; } } float flAlpha = m_flCurrentLinearFloatLightAlpha * ( 1.0f / 255.0f ); state.m_fQuadraticAtten = 0.0; state.m_fLinearAtten = 100; state.m_fConstantAtten = 0.0f; state.m_FarZAtten = m_flFarZ; state.m_fBrightnessScale = m_flBrightnessScale; state.m_Color[0] = m_CurrentLinearFloatLightColor.x * ( 1.0f / 255.0f ) * flAlpha; state.m_Color[1] = m_CurrentLinearFloatLightColor.y * ( 1.0f / 255.0f ) * flAlpha; state.m_Color[2] = m_CurrentLinearFloatLightColor.z * ( 1.0f / 255.0f ) * flAlpha; state.m_Color[3] = 0.0f; // fixme: need to make ambient work m_flAmbient; state.m_flShadowSlopeScaleDepthBias = g_pMaterialSystemHardwareConfig->GetShadowSlopeScaleDepthBias(); state.m_flShadowDepthBias = g_pMaterialSystemHardwareConfig->GetShadowDepthBias(); state.m_bEnableShadows = m_bEnableShadows; state.m_pSpotlightTexture = m_SpotlightTexture; state.m_pProjectedMaterial = NULL; // only complain if we're using material projection state.m_nSpotlightTextureFrame = m_nSpotlightTextureFrame; state.m_flProjectionSize = m_flProjectionSize; state.m_flProjectionRotation = m_flRotation; state.m_nShadowQuality = m_nShadowQuality; // Allow entity to affect shadow quality if ( m_bSimpleProjection == true ) { state.m_bSimpleProjection = true; state.m_bOrtho = true; state.m_fOrthoLeft = -m_flProjectionSize; state.m_fOrthoTop = -m_flProjectionSize; state.m_fOrthoRight = m_flProjectionSize; state.m_fOrthoBottom = m_flProjectionSize; } if( m_LightHandle == CLIENTSHADOW_INVALID_HANDLE ) { // Hack: env projected textures don't work like normal flashlights; they're not assigned to a given splitscreen slot, // but the flashlight code requires this HACK_GETLOCALPLAYER_GUARD( "Env projected texture" ); if ( m_bSimpleProjection == true ) { m_LightHandle = g_pClientShadowMgr->CreateProjection( state ); } else { m_LightHandle = g_pClientShadowMgr->CreateFlashlight( state ); } if ( m_LightHandle != CLIENTSHADOW_INVALID_HANDLE ) { m_bForceUpdate = false; } } else { if ( m_bSimpleProjection == true ) { g_pClientShadowMgr->UpdateProjectionState( m_LightHandle, state ); } else { g_pClientShadowMgr->UpdateFlashlightState( m_LightHandle, state ); } m_bForceUpdate = false; } g_pClientShadowMgr->GetFrustumExtents( m_LightHandle, m_vecExtentsMin, m_vecExtentsMax ); m_vecExtentsMin = m_vecExtentsMin - GetAbsOrigin(); m_vecExtentsMax = m_vecExtentsMax - GetAbsOrigin(); } if( m_bLightOnlyTarget ) { g_pClientShadowMgr->SetFlashlightTarget( m_LightHandle, m_hTargetEntity ); } else { g_pClientShadowMgr->SetFlashlightTarget( m_LightHandle, NULL ); } g_pClientShadowMgr->SetFlashlightLightWorld( m_LightHandle, m_bLightWorld ); if ( !asw_perf_wtf.GetBool() && !m_bForceUpdate ) { g_pClientShadowMgr->UpdateProjectedTexture( m_LightHandle, true ); } }
void C_EnvProjectedTexture::UpdateLight( bool bForceUpdate ) { if ( m_bState == false ) { if ( m_LightHandle != CLIENTSHADOW_INVALID_HANDLE ) { ShutDownLightHandle(); } return; } Vector vForward, vRight, vUp, vPos = GetAbsOrigin(); FlashlightState_t state; if ( m_hTargetEntity != NULL ) { if ( m_bCameraSpace ) { const QAngle &angles = GetLocalAngles(); C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if( pPlayer ) { const QAngle playerAngles = pPlayer->GetAbsAngles(); Vector vPlayerForward, vPlayerRight, vPlayerUp; AngleVectors( playerAngles, &vPlayerForward, &vPlayerRight, &vPlayerUp ); matrix3x4_t mRotMatrix; AngleMatrix( angles, mRotMatrix ); VectorITransform( vPlayerForward, mRotMatrix, vForward ); VectorITransform( vPlayerRight, mRotMatrix, vRight ); VectorITransform( vPlayerUp, mRotMatrix, vUp ); float dist = (m_hTargetEntity->GetAbsOrigin() - GetAbsOrigin()).Length(); vPos = m_hTargetEntity->GetAbsOrigin() - vForward*dist; VectorNormalize( vForward ); VectorNormalize( vRight ); VectorNormalize( vUp ); } } else { // VXP: Fixing targeting Vector vecToTarget; QAngle vecAngles; if ( m_hTargetEntity == NULL ) { vecAngles = GetAbsAngles(); } else { vecToTarget = m_hTargetEntity->GetAbsOrigin() - GetAbsOrigin(); VectorAngles( vecToTarget, vecAngles ); } AngleVectors( vecAngles, &vForward, &vRight, &vUp ); } } else { AngleVectors( GetAbsAngles(), &vForward, &vRight, &vUp ); } state.m_fHorizontalFOVDegrees = m_flLightFOV; state.m_fVerticalFOVDegrees = m_flLightFOV; state.m_vecLightOrigin = vPos; BasisToQuaternion( vForward, vRight, vUp, state.m_quatOrientation ); state.m_fQuadraticAtten = 0.0; state.m_fLinearAtten = 100; state.m_fConstantAtten = 0.0f; state.m_Color[0] = m_LinearFloatLightColor.x; state.m_Color[1] = m_LinearFloatLightColor.y; state.m_Color[2] = m_LinearFloatLightColor.z; state.m_Color[3] = 0.0f; // fixme: need to make ambient work m_flAmbient; state.m_NearZ = m_flNearZ; state.m_FarZ = m_flFarZ; state.m_flShadowSlopeScaleDepthBias = mat_slopescaledepthbias_shadowmap.GetFloat(); state.m_flShadowDepthBias = mat_depthbias_shadowmap.GetFloat(); state.m_bEnableShadows = m_bEnableShadows; state.m_pSpotlightTexture = materials->FindTexture( m_SpotlightTextureName, TEXTURE_GROUP_OTHER, false ); state.m_nSpotlightTextureFrame = m_nSpotlightTextureFrame; state.m_nShadowQuality = m_nShadowQuality; // Allow entity to affect shadow quality if( m_LightHandle == CLIENTSHADOW_INVALID_HANDLE ) { m_LightHandle = g_pClientShadowMgr->CreateFlashlight( state ); } else { if ( m_hTargetEntity != NULL || bForceUpdate == true ) { g_pClientShadowMgr->UpdateFlashlightState( m_LightHandle, state ); } } if( m_bLightOnlyTarget ) { g_pClientShadowMgr->SetFlashlightTarget( m_LightHandle, m_hTargetEntity ); } else { g_pClientShadowMgr->SetFlashlightTarget( m_LightHandle, NULL ); } g_pClientShadowMgr->SetFlashlightLightWorld( m_LightHandle, m_bLightWorld ); //if ( bForceUpdate == false ) //{ g_pClientShadowMgr->UpdateProjectedTexture( m_LightHandle, true ); //} }
void CMumbleSystem::PostRender() { #ifndef NO_STEAM if ( !g_pMumbleMemory || !sv_mumble_positionalaudio.GetBool() ) return; if ( g_pMumbleMemory->uiVersion != 2 ) { V_wcscpy_safe( g_pMumbleMemory->name, L"Source engine: " ); wchar_t wcsGameDir[MAX_PATH]; Q_UTF8ToUnicode( COM_GetModDirectory(), wcsGameDir, sizeof(wcsGameDir) ); V_wcscat_safe( g_pMumbleMemory->name, wcsGameDir ); V_wcscpy_safe( g_pMumbleMemory->description, L"Links Source engine games to Mumble." ); g_pMumbleMemory->uiVersion = 2; } g_pMumbleMemory->uiTick++; Vector vecOriginPlayer, vecOriginCamera = MainViewOrigin(); QAngle anglesPlayer, anglesCamera = MainViewAngles(); C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if ( pPlayer ) { vecOriginPlayer = pPlayer->EyePosition(); anglesPlayer = pPlayer->GetAbsAngles(); } else { vecOriginPlayer = vecOriginCamera; anglesPlayer = anglesCamera; } anglesPlayer.x = 0; Vector vecPlayerForward, vecPlayerUp, vecCameraForward, vecCameraUp; AngleVectors( anglesPlayer, &vecPlayerForward, NULL, &vecPlayerUp ); AngleVectors( anglesCamera, &vecCameraForward, NULL, &vecCameraUp ); // 1 Source unit is about one inch // 1 mumble unit = 1 meter vecOriginPlayer *= METERS_PER_INCH; vecOriginCamera *= METERS_PER_INCH; VectorToMumbleFloatArray( vecPlayerForward, g_pMumbleMemory->fAvatarFront ); VectorToMumbleFloatArray( vecPlayerUp, g_pMumbleMemory->fAvatarTop ); VectorToMumbleFloatArray( vecOriginPlayer, g_pMumbleMemory->fAvatarPosition ); VectorToMumbleFloatArray( vecCameraForward, g_pMumbleMemory->fCameraFront ); VectorToMumbleFloatArray( vecCameraUp, g_pMumbleMemory->fCameraTop ); VectorToMumbleFloatArray( vecOriginCamera, g_pMumbleMemory->fCameraPosition ); if ( pPlayer && m_bHasSetPlayerUniqueId && m_nTeamSetInUniqueId != pPlayer->GetTeamNumber() ) { // Player changed team since we set the unique ID. Set it again. m_bHasSetPlayerUniqueId = false; } if ( !m_bHasSetPlayerUniqueId && steamapicontext && steamapicontext->SteamUser() ) { CSteamID steamid = steamapicontext->SteamUser()->GetSteamID(); if ( steamid.IsValid() ) { int unTeam = pPlayer ? pPlayer->GetTeamNumber() : 0; char szSteamId[256]; V_sprintf_safe( szSteamId, "universe:%u;account_type:%u;id:%u;instance:%u;team:%d", steamid.GetEUniverse(), steamid.GetEAccountType(), steamid.GetAccountID(), steamid.GetUnAccountInstance(), unTeam ); wchar_t wcsSteamId[256]; Q_UTF8ToUnicode( szSteamId, wcsSteamId, sizeof(wcsSteamId) ); // Identifier which uniquely identifies a certain player in a context. V_wcscpy_safe( g_pMumbleMemory->identity, wcsSteamId ); m_bHasSetPlayerUniqueId = true; m_nTeamSetInUniqueId = unTeam; } } // Context should be equal for players which should be able to hear each other positional and // differ for those who shouldn't (e.g. it could contain the server+port and team) memcpy( g_pMumbleMemory->context, &m_szSteamIDCurrentServer, m_cubSteamIDCurrentServer ); g_pMumbleMemory->context_len = m_cubSteamIDCurrentServer; #endif // NO_STEAM }
void C_EnvProjectedTexture::UpdateLight(void) { VPROF_BUDGET("C_EnvProjectedTexture::UpdateLight", "Projected Textures"); if (CurrentViewID() == VIEW_SHADOW_DEPTH_TEXTURE /*|| CurrentViewID() == VIEW_SUN_SHAFTS*/) return; bool bVisible = true; if (m_bAlwaysUpdate) { m_bForceUpdate = true; } float fHighFOV; if (m_flLightFOV > m_flLightHorFOV) fHighFOV = m_flLightFOV; else fHighFOV = m_flLightHorFOV; if (m_bState == false || !IsWithinFarZ(fHighFOV) || !IsBBoxVisible()) { // Spotlight's extents aren't in view ShutDownLightHandle(); return; } else { bVisible = true; } Vector vLinearFloatLightColor(m_LightColor.r, m_LightColor.g, m_LightColor.b); float flLinearFloatLightAlpha = m_LightColor.a; if (m_CurrentLinearFloatLightColor != vLinearFloatLightColor || m_flCurrentLinearFloatLightAlpha != flLinearFloatLightAlpha) { float flColorTransitionSpeed = gpGlobals->frametime * m_flColorTransitionTime * 255.0f; m_CurrentLinearFloatLightColor.x = Approach(vLinearFloatLightColor.x, m_CurrentLinearFloatLightColor.x, flColorTransitionSpeed); m_CurrentLinearFloatLightColor.y = Approach(vLinearFloatLightColor.y, m_CurrentLinearFloatLightColor.y, flColorTransitionSpeed); m_CurrentLinearFloatLightColor.z = Approach(vLinearFloatLightColor.z, m_CurrentLinearFloatLightColor.z, flColorTransitionSpeed); m_flCurrentLinearFloatLightAlpha = Approach(flLinearFloatLightAlpha, m_flCurrentLinearFloatLightAlpha, flColorTransitionSpeed); m_bForceUpdate = true; } if (m_LightHandle == CLIENTSHADOW_INVALID_HANDLE || m_hTargetEntity != NULL || GetRootMoveParent() != NULL || m_bForceUpdate) { Vector vForward, vRight, vUp, vPos = GetAbsOrigin(); FlashlightState_t state; if (m_hTargetEntity != NULL) { if (m_bCameraSpace) { const QAngle &angles = GetLocalAngles(); C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if (pPlayer) { const QAngle playerAngles = pPlayer->GetAbsAngles(); Vector vPlayerForward, vPlayerRight, vPlayerUp; AngleVectors(playerAngles, &vPlayerForward, &vPlayerRight, &vPlayerUp); matrix3x4_t mRotMatrix; AngleMatrix(angles, mRotMatrix); VectorITransform(vPlayerForward, mRotMatrix, vForward); VectorITransform(vPlayerRight, mRotMatrix, vRight); VectorITransform(vPlayerUp, mRotMatrix, vUp); float dist = (m_hTargetEntity->GetAbsOrigin() - GetAbsOrigin()).Length(); vPos = m_hTargetEntity->GetAbsOrigin() - vForward*dist; VectorNormalize(vForward); VectorNormalize(vRight); VectorNormalize(vUp); } } else { Vector vecToTarget = m_hTargetEntity->GetAbsOrigin() - GetAbsOrigin(); QAngle vecAngles; VectorAngles(vecToTarget, vecAngles); AngleVectors(vecAngles, &vForward, &vRight, &vUp); } } else { AngleVectors(GetAbsAngles(), &vForward, &vRight, &vUp); } state.m_fHorizontalFOVDegrees = abs(m_flLightHorFOV); state.m_fVerticalFOVDegrees = abs(m_flLightFOV); state.m_vecLightOrigin = vPos; BasisToQuaternion(vForward, vRight, vUp, state.m_quatOrientation); state.m_NearZ = m_flNearZ; state.m_FarZ = m_flFarZ; // quickly check the proposed light's bbox against the view frustum to determine whether we // should bother to create it, if it doesn't exist, or cull it, if it does. // get the half-widths of the near and far planes, // based on the FOV which is in degrees. Remember that // on planet Valve, x is forward, y left, and z up. const float tanHalfAngle = tan(fHighFOV * (M_PI / 180.0f) * 0.5f); const float halfWidthNear = tanHalfAngle * m_flNearZ; const float halfWidthFar = tanHalfAngle * m_flFarZ; // now we can build coordinates in local space: the near rectangle is eg // (0, -halfWidthNear, -halfWidthNear), (0, halfWidthNear, -halfWidthNear), // (0, halfWidthNear, halfWidthNear), (0, -halfWidthNear, halfWidthNear) VectorAligned vNearRect[4] = { VectorAligned(m_flNearZ, -halfWidthNear, -halfWidthNear), VectorAligned(m_flNearZ, halfWidthNear, -halfWidthNear), VectorAligned(m_flNearZ, halfWidthNear, halfWidthNear), VectorAligned(m_flNearZ, -halfWidthNear, halfWidthNear) }; VectorAligned vFarRect[4] = { VectorAligned(m_flFarZ, -halfWidthFar, -halfWidthFar), VectorAligned(m_flFarZ, halfWidthFar, -halfWidthFar), VectorAligned(m_flFarZ, halfWidthFar, halfWidthFar), VectorAligned(m_flFarZ, -halfWidthFar, halfWidthFar) }; matrix3x4_t matOrientation(vForward, -vRight, vUp, vPos); enum { kNEAR = 0, kFAR = 1, }; VectorAligned vOutRects[2][4]; for (int i = 0; i < 4; ++i) { VectorTransform(vNearRect[i].Base(), matOrientation, vOutRects[0][i].Base()); } for (int i = 0; i < 4; ++i) { VectorTransform(vFarRect[i].Base(), matOrientation, vOutRects[1][i].Base()); } // now take the min and max extents for the bbox, and see if it is visible. Vector mins = **vOutRects; Vector maxs = **vOutRects; for (int i = 1; i < 8; ++i) { VectorMin(mins, *(*vOutRects + i), mins); VectorMax(maxs, *(*vOutRects + i), maxs); } #if 0 //for debugging the visibility frustum we just calculated NDebugOverlay::Triangle(vOutRects[0][0], vOutRects[0][1], vOutRects[0][2], 255, 0, 0, 100, true, 0.0f); //first tri NDebugOverlay::Triangle(vOutRects[0][2], vOutRects[0][1], vOutRects[0][0], 255, 0, 0, 100, true, 0.0f); //make it double sided NDebugOverlay::Triangle(vOutRects[0][2], vOutRects[0][3], vOutRects[0][0], 255, 0, 0, 100, true, 0.0f); //second tri NDebugOverlay::Triangle(vOutRects[0][0], vOutRects[0][3], vOutRects[0][2], 255, 0, 0, 100, true, 0.0f); //make it double sided NDebugOverlay::Triangle(vOutRects[1][0], vOutRects[1][1], vOutRects[1][2], 0, 0, 255, 100, true, 0.0f); //first tri NDebugOverlay::Triangle(vOutRects[1][2], vOutRects[1][1], vOutRects[1][0], 0, 0, 255, 100, true, 0.0f); //make it double sided NDebugOverlay::Triangle(vOutRects[1][2], vOutRects[1][3], vOutRects[1][0], 0, 0, 255, 100, true, 0.0f); //second tri NDebugOverlay::Triangle(vOutRects[1][0], vOutRects[1][3], vOutRects[1][2], 0, 0, 255, 100, true, 0.0f); //make it double sided NDebugOverlay::Box(vec3_origin, mins, maxs, 0, 255, 0, 100, 0.0f); #endif bool bVisible = IsBBoxVisible(mins, maxs); if (!bVisible) { // Spotlight's extents aren't in view if (m_LightHandle != CLIENTSHADOW_INVALID_HANDLE) { ShutDownLightHandle(); } return; } float flAlpha = m_flCurrentLinearFloatLightAlpha * (1.0f / 255.0f); state.m_fQuadraticAtten = m_flQuadratic; state.m_fLinearAtten = 100; if (m_bAtten) { state.m_fConstantAtten = 0.0f; } else { state.m_fConstantAtten = 1.0f; } state.m_Color[0] = (m_CurrentLinearFloatLightColor.x * (1.0f / 255.0f) * flAlpha) * m_fBrightness; state.m_Color[1] = (m_CurrentLinearFloatLightColor.y * (1.0f / 255.0f) * flAlpha) * m_fBrightness; state.m_Color[2] = (m_CurrentLinearFloatLightColor.z * (1.0f / 255.0f) * flAlpha) * m_fBrightness; state.m_Color[3] = m_flAmbient; state.m_flShadowSlopeScaleDepthBias = mat_slopescaledepthbias_shadowmap.GetFloat(); state.m_flShadowDepthBias = mat_depthbias_shadowmap.GetFloat(); if (m_bEnableShadows && r_flashlightdepthtexture.GetBool() && m_bClientWantsShadows) { state.m_bEnableShadows = true; } else { state.m_bEnableShadows = false; } state.m_pSpotlightTexture = m_SpotlightTexture; state.m_nSpotlightTextureFrame = m_nSpotlightTextureFrame; if (r_dynamicshadows_use_c17_improvements.GetBool()) { //state.m_flShadowFilterSize = m_flBlur; if (r_flashlightdepthres.GetInt() == 512) { state.m_flShadowFilterSize = 0.8f; } else if (r_flashlightdepthres.GetInt() == 1024) { state.m_flShadowFilterSize = 0.3f; } else if (r_flashlightdepthres.GetInt() == 2048) { state.m_flShadowFilterSize = 0.2f; } else if (r_flashlightdepthres.GetInt() == 4096) { state.m_flShadowFilterSize = 0.08f; } else { state.m_flShadowFilterSize = 1.0f; } state.m_flShadowAtten = m_flAtten; } else { state.m_flShadowFilterSize = 3.0f; state.m_flShadowAtten = 0.35f; } state.m_nShadowQuality = m_nShadowQuality; // Allow entity to affect shadow quality if (m_LightHandle == CLIENTSHADOW_INVALID_HANDLE) { // Hack: env projected textures don't work like normal flashlights; they're not assigned to a given splitscreen slot, // but the flashlight code requires this m_LightHandle = g_pClientShadowMgr->CreateFlashlight(state); if (m_LightHandle != CLIENTSHADOW_INVALID_HANDLE) { m_bForceUpdate = false; } } else { g_pClientShadowMgr->UpdateFlashlightState(m_LightHandle, state); m_bForceUpdate = false; } g_pClientShadowMgr->GetFrustumExtents(m_LightHandle, m_vecExtentsMin, m_vecExtentsMax); m_vecExtentsMin = m_vecExtentsMin - GetAbsOrigin(); m_vecExtentsMax = m_vecExtentsMax - GetAbsOrigin(); } if (m_bLightOnlyTarget) { g_pClientShadowMgr->SetFlashlightTarget(m_LightHandle, m_hTargetEntity); } else { g_pClientShadowMgr->SetFlashlightTarget(m_LightHandle, NULL); } g_pClientShadowMgr->SetFlashlightLightWorld(m_LightHandle, m_bLightWorld); if (!m_bForceUpdate) { g_pClientShadowMgr->UpdateProjectedTexture(m_LightHandle, true); } }