/* * CG_ThirdPersonOffsetView */ static void CG_ThirdPersonOffsetView( cg_viewdef_t *view ) { float dist, f, r; vec3_t dest, stop; vec3_t chase_dest; trace_t trace; vec3_t mins = { -4, -4, -4 }; vec3_t maxs = { 4, 4, 4 }; if( !cg_thirdPersonAngle || !cg_thirdPersonRange ) { cg_thirdPersonAngle = trap_Cvar_Get( "cg_thirdPersonAngle", "0", CVAR_ARCHIVE ); cg_thirdPersonRange = trap_Cvar_Get( "cg_thirdPersonRange", "70", CVAR_ARCHIVE ); } // calc exact destination VectorCopy( view->origin, chase_dest ); r = DEG2RAD( cg_thirdPersonAngle->value ); f = -cos( r ); r = -sin( r ); VectorMA( chase_dest, cg_thirdPersonRange->value * f, &view->axis[AXIS_FORWARD], chase_dest ); VectorMA( chase_dest, cg_thirdPersonRange->value * r, &view->axis[AXIS_RIGHT], chase_dest ); chase_dest[2] += 8; // find the spot the player is looking at VectorMA( view->origin, 512, &view->axis[AXIS_FORWARD], dest ); CG_Trace( &trace, view->origin, mins, maxs, dest, view->POVent, MASK_SOLID ); // calculate pitch to look at the same spot from camera VectorSubtract( trace.endpos, view->origin, stop ); dist = sqrt( stop[0] * stop[0] + stop[1] * stop[1] ); if( dist < 1 ) dist = 1; view->angles[PITCH] = RAD2DEG( -atan2( stop[2], dist ) ); view->angles[YAW] -= cg_thirdPersonAngle->value; Matrix3_FromAngles( view->angles, view->axis ); // move towards destination CG_Trace( &trace, view->origin, mins, maxs, chase_dest, view->POVent, MASK_SOLID ); if( trace.fraction != 1.0 ) { VectorCopy( trace.endpos, stop ); stop[2] += ( 1.0 - trace.fraction ) * 32; CG_Trace( &trace, view->origin, mins, maxs, stop, view->POVent, MASK_SOLID ); VectorCopy( trace.endpos, chase_dest ); } VectorCopy( chase_dest, view->origin ); }
/* * CG_CalcViewWeapon */ void CG_CalcViewWeapon( cg_viewweapon_t *viewweapon ) { orientation_t tag; weaponinfo_t *weaponInfo; vec3_t gunAngles; vec3_t gunOffset; float fallfrac, fallkick; CG_ViewWeapon_RefreshAnimation( viewweapon ); //if( cg.view.thirdperson ) // return; weaponInfo = CG_GetWeaponInfo( viewweapon->weapon ); viewweapon->ent.model = weaponInfo->model[HAND]; viewweapon->ent.renderfx = RF_MINLIGHT|RF_WEAPONMODEL|RF_FORCENOLOD|(cg_shadows->integer < 2 ? RF_NOSHADOW : 0); viewweapon->ent.scale = 1.0f; viewweapon->ent.customShader = NULL; viewweapon->ent.customSkin = NULL; viewweapon->ent.rtype = RT_MODEL; Vector4Set( viewweapon->ent.shaderRGBA, 255, 255, 255, 255 ); // calculate the entity position #if 1 VectorCopy( cg.view.origin, viewweapon->ent.origin ); #else VectorCopy( cg.predictedPlayerState.pmove.origin, viewweapon->ent.origin ); viewweapon->ent.origin[2] += cg.predictedPlayerState.viewheight; #endif // weapon config offsets VectorAdd( weaponInfo->handpositionAngles, cg.predictedPlayerState.viewangles, gunAngles ); gunOffset[FORWARD] = cg_gunz->value + weaponInfo->handpositionOrigin[FORWARD]; gunOffset[RIGHT] = cg_gunx->value + weaponInfo->handpositionOrigin[RIGHT]; gunOffset[UP] = cg_guny->value + weaponInfo->handpositionOrigin[UP]; // hand cvar offset if( cgs.demoPlaying ) { if( hand->integer == 0 ) gunOffset[RIGHT] += cg_handOffset->value; else if( hand->integer == 1 ) gunOffset[RIGHT] -= cg_handOffset->value; } else { if( cgs.clientInfo[cg.view.POVent-1].hand == 0 ) gunOffset[RIGHT] += cg_handOffset->value; else if( cgs.clientInfo[cg.view.POVent-1].hand == 1 ) gunOffset[RIGHT] -= cg_handOffset->value; } // fallkick offset if( cg.weapon.fallEff_Time > cg.time ) { fallfrac = (float)( cg.time - cg.weapon.fallEff_rebTime ) / (float)( cg.weapon.fallEff_Time - cg.weapon.fallEff_rebTime ); fallkick = sin( DEG2RAD( fallfrac*180 ) ) * ( ( cg.weapon.fallEff_Time - cg.weapon.fallEff_rebTime ) * 0.01f ); } else { cg.weapon.fallEff_Time = cg.weapon.fallEff_rebTime = 0; fallkick = fallfrac = 0; } gunOffset[UP] -= fallkick; // apply the offsets #if 1 VectorMA( viewweapon->ent.origin, gunOffset[FORWARD], &cg.view.axis[AXIS_FORWARD], viewweapon->ent.origin ); VectorMA( viewweapon->ent.origin, gunOffset[RIGHT], &cg.view.axis[AXIS_RIGHT], viewweapon->ent.origin ); VectorMA( viewweapon->ent.origin, gunOffset[UP], &cg.view.axis[AXIS_UP], viewweapon->ent.origin ); #else Matrix3_FromAngles( cg.predictedPlayerState.viewangles, offsetAxis ); VectorMA( viewweapon->ent.origin, gunOffset[FORWARD], &offsetAxis[AXIS_FORWARD], viewweapon->ent.origin ); VectorMA( viewweapon->ent.origin, gunOffset[RIGHT], &offsetAxis[AXIS_RIGHT], viewweapon->ent.origin ); VectorMA( viewweapon->ent.origin, gunOffset[UP], &offsetAxis[AXIS_UP], viewweapon->ent.origin ); #endif // add angles effects CG_ViewWeapon_AddAngleEffects( gunAngles ); // finish AnglesToAxis( gunAngles, viewweapon->ent.axis ); if( cg_gun_fov->integer && !cg.predictedPlayerState.pmove.stats[PM_STAT_ZOOMTIME] ) { float gun_fov = bound( 20, cg_gun_fov->value, 160 ); float fracWeapFOV = ( 1.0f / cg.view.fracDistFOV ) * tan( gun_fov * ( M_PI/180 ) * 0.5f ); VectorScale( &viewweapon->ent.axis[AXIS_FORWARD], fracWeapFOV, &viewweapon->ent.axis[AXIS_FORWARD] ); } // if the player doesn't want to view the weapon we still have to build the projection source if( CG_GrabTag( &tag, &viewweapon->ent, "tag_weapon" ) ) CG_ViewWeapon_UpdateProjectionSource( viewweapon->ent.origin, viewweapon->ent.axis, tag.origin, tag.axis ); else CG_ViewWeapon_UpdateProjectionSource( viewweapon->ent.origin, viewweapon->ent.axis, vec3_origin, axis_identity ); }
/* * CG_DamageIndicatorAdd */ void CG_DamageIndicatorAdd( int damage, const vec3_t dir ) { int i; unsigned int damageTime; vec3_t playerAngles; mat3_t playerAxis; // epsilons are 30 degrees #define INDICATOR_EPSILON 0.5f #define INDICATOR_EPSILON_UP 0.85f #define TOP_BLEND 0 #define RIGHT_BLEND 1 #define BOTTOM_BLEND 2 #define LEFT_BLEND 3 float blends[4]; float forward, side; if( !cg_damage_indicator->integer ) return; playerAngles[PITCH] = 0; playerAngles[YAW] = cg.predictedPlayerState.viewangles[YAW]; playerAngles[ROLL] = 0; Matrix3_FromAngles( playerAngles, playerAxis ); if( cg_damage_indicator_time->value < 0 ) trap_Cvar_SetValue( "cg_damage_indicator_time", 0 ); Vector4Set( blends, 0, 0, 0, 0 ); damageTime = damage * cg_damage_indicator_time->value; // up and down go distributed equally to all blends and assumed when no dir is given if( !dir || VectorCompare( dir, vec3_origin ) || cg_damage_indicator->integer == 2 || GS_Instagib() || ( fabs( DotProduct( dir, &playerAxis[AXIS_UP] ) ) > INDICATOR_EPSILON_UP ) ) { blends[RIGHT_BLEND] += damageTime; blends[LEFT_BLEND] += damageTime; blends[TOP_BLEND] += damageTime; blends[BOTTOM_BLEND] += damageTime; } else { side = DotProduct( dir, &playerAxis[AXIS_RIGHT] ); if( side > INDICATOR_EPSILON ) blends[LEFT_BLEND] += damageTime; else if( side < -INDICATOR_EPSILON ) blends[RIGHT_BLEND] += damageTime; forward = DotProduct( dir, &playerAxis[AXIS_FORWARD] ); if( forward > INDICATOR_EPSILON ) blends[BOTTOM_BLEND] += damageTime; else if( forward < -INDICATOR_EPSILON ) blends[TOP_BLEND] += damageTime; } for( i = 0; i < 4; i++ ) { if( cg.damageBlends[i] < cg.time + blends[i] ) cg.damageBlends[i] = cg.time + blends[i]; } #undef TOP_BLEND #undef RIGHT_BLEND #undef BOTTOM_BLEND #undef LEFT_BLEND #undef INDICATOR_EPSILON #undef INDICATOR_EPSILON_UP }
/* * CG_SetupViewDef */ static void CG_SetupViewDef( cg_viewdef_t *view, int type, bool flipped ) { memset( view, 0, sizeof( cg_viewdef_t ) ); // // VIEW SETTINGS // view->type = type; view->flipped = flipped; if( view->type == VIEWDEF_PLAYERVIEW ) { view->POVent = cg.frame.playerState.POVnum; view->draw2D = true; // set up third-person if( cgs.demoPlaying ) view->thirdperson = CG_DemoCam_GetThirdPerson(); else if( chaseCam.mode == CAM_THIRDPERSON ) view->thirdperson = true; else view->thirdperson = ( cg_thirdPerson->integer != 0 ); if( cg_entities[view->POVent].serverFrame != cg.frame.serverFrame ) view->thirdperson = false; // check for drawing gun if( !view->thirdperson && view->POVent > 0 && view->POVent <= gs.maxclients ) { if( ( cg_entities[view->POVent].serverFrame == cg.frame.serverFrame ) && ( cg_entities[view->POVent].current.weapon != 0 ) ) view->drawWeapon = ( cg_gun->integer != 0 ) && ( cg_gun_alpha->value > 0 ); } // check for chase cams if( !( cg.frame.playerState.pmove.pm_flags & PMF_NO_PREDICTION ) ) { if( (unsigned)view->POVent == cgs.playerNum + 1 ) { if( cg_predict->integer && !cgs.demoPlaying ) { view->playerPrediction = true; } } } } else if( view->type == VIEWDEF_CAMERA ) { CG_DemoCam_GetViewDef( view ); } else { module_Error( "CG_SetupView: Invalid view type %i\n", view->type ); } // // SETUP REFDEF FOR THE VIEW SETTINGS // if( view->type == VIEWDEF_PLAYERVIEW ) { int i; vec3_t viewoffset; if( view->playerPrediction ) { CG_PredictMovement(); // fixme: crouching is predicted now, but it looks very ugly VectorSet( viewoffset, 0.0f, 0.0f, cg.predictedPlayerState.viewheight ); for( i = 0; i < 3; i++ ) { view->origin[i] = cg.predictedPlayerState.pmove.origin[i] + viewoffset[i] - ( 1.0f - cg.lerpfrac ) * cg.predictionError[i]; view->angles[i] = cg.predictedPlayerState.viewangles[i]; } CG_ViewSmoothPredictedSteps( view->origin ); // smooth out stair climbing if( cg_viewBob->integer && !cg_thirdPerson->integer ) { view->origin[2] += CG_ViewSmoothFallKick() * 6.5f; } } else { cg.predictingTimeStamp = cg.time; cg.predictFrom = 0; // we don't run prediction, but we still set cg.predictedPlayerState with the interpolation CG_InterpolatePlayerState( &cg.predictedPlayerState ); VectorSet( viewoffset, 0.0f, 0.0f, cg.predictedPlayerState.viewheight ); VectorAdd( cg.predictedPlayerState.pmove.origin, viewoffset, view->origin ); VectorCopy( cg.predictedPlayerState.viewangles, view->angles ); } view->refdef.fov_x = cg.predictedPlayerState.fov; CG_CalcViewBob(); VectorCopy( cg.predictedPlayerState.pmove.velocity, view->velocity ); } else if( view->type == VIEWDEF_CAMERA ) { view->refdef.fov_x = CG_DemoCam_GetOrientation( view->origin, view->angles, view->velocity ); } Matrix3_FromAngles( view->angles, view->axis ); if( view->flipped ) VectorInverse( &view->axis[AXIS_RIGHT] ); // view rectangle size view->refdef.x = scr_vrect.x; view->refdef.y = scr_vrect.y; view->refdef.width = scr_vrect.width; view->refdef.height = scr_vrect.height; view->refdef.time = cg.time; view->refdef.areabits = cg.frame.areabits; view->refdef.scissor_x = scr_vrect.x; view->refdef.scissor_y = scr_vrect.y; view->refdef.scissor_width = scr_vrect.width; view->refdef.scissor_height = scr_vrect.height; view->refdef.fov_y = CalcFov( view->refdef.fov_x, view->refdef.width, view->refdef.height ); AdjustFov( &view->refdef.fov_x, &view->refdef.fov_y, view->refdef.width, view->refdef.height, false ); view->fracDistFOV = tan( view->refdef.fov_x * ( M_PI/180 ) * 0.5f ); view->refdef.minLight = 0.3f; if( view->thirdperson ) CG_ThirdPersonOffsetView( view ); if( !view->playerPrediction ) cg.predictedWeaponSwitch = 0; VectorCopy( cg.view.origin, view->refdef.vieworg ); Matrix3_Copy( cg.view.axis, view->refdef.viewaxis ); VectorInverse( &view->refdef.viewaxis[AXIS_RIGHT] ); view->refdef.colorCorrection = NULL; if( cg_colorCorrection->integer ) { int colorCorrection = GS_ColorCorrection(); if( ( colorCorrection > 0 ) && ( colorCorrection < MAX_IMAGES ) ) view->refdef.colorCorrection = cgs.imagePrecache[colorCorrection]; } }