/* ================ sdClientScriptEntity::Event_SetAngles ================ */ void sdClientScriptEntity::Event_SetAngles( const idAngles& ang ) { idMat3 axis = ang.ToMat3(); SetAxis( axis ); if ( GetPhysics() != NULL ) { GetPhysics()->SetAxis( axis ); } }
/* ================ sdDeliveryVehicle::Magog_DoMove ================ */ void sdDeliveryVehicle::Magog_DoMove( const idVec3& aheadPointIdeal, const idVec3& aheadPointDir, const idVec3& endPoint, float itemRotation, float maxYawScale, bool orientToEnd, bool clampRoll, bool slowNearEnd, float pathSpeed ) { float frameTime = MS2SEC( gameLocal.msec ); idVec3 aheadPoint = aheadPointIdeal; const idVec3& origin = GetPhysics()->GetOrigin(); const idVec3& velocity = GetPhysics()->GetLinearVelocity(); const idMat3& axis = GetPhysics()->GetAxis(); const idAngles angles = axis.ToAngles(); const idVec3& angVel = GetPhysics()->GetAngularVelocity(); const idVec3& currentFwd = axis[ 0 ]; const idVec3& currentRight = axis[ 1 ]; const idVec3& currentUp = axis[ 2 ]; float rollVel = angVel * currentFwd; float pitchVel = angVel * currentRight; float yawVel = angVel * currentUp; // find the current height of the vehicle idVec3 futureContribution = velocity * 1.0f; futureContribution.z = 0.0f; float futureContributionLength = futureContribution.Length(); if ( futureContributionLength > 2000.0f ) { futureContribution = futureContribution * ( 2000.0f / futureContributionLength ); } idVec3 futureSpot = origin + futureContribution; futureSpot.z -= HOVER_DOWNCAST_LENGTH; trace_t trace; gameLocal.clip.TraceBounds( CLIP_DEBUG_PARMS trace, origin, futureSpot, GetPhysics()->GetBounds(), axis, MASK_SOLID | MASK_OPAQUE, this ); futureSpot = trace.endpos; // shift the ahead point based on the trace float currentHeight = origin.z - futureSpot.z; if ( currentHeight < HOVER_DOWNCAST_LENGTH ) { aheadPoint.z = origin.z - currentHeight + HOVER_HEIGHT_AIM; } else { aheadPoint.z = origin.z - HOVER_DOWNCAST_LENGTH + HOVER_HEIGHT_AIM; } // sys.debugCircle( g_colorRed, origin, '0 0 1', 16, 8, 0 ); // sys.debugArrow( g_colorRed, origin, futureSpot, 256, 0 ); // sys.debugCircle( g_colorRed, futureSpot, '0 0 1', 16, 8, 0 ); // sys.debugCircle( '0 1 0', aheadPoint, '0 0 1', 256.0f, 16, 0 ); idVec3 point; float lookaheadFactor; { // generate a cubic spline between the two points idVec3 x0 = origin; idVec3 x1 = aheadPoint; idVec3 dx0 = velocity * 3.0f; // maintaining our current velocity is more important idVec3 dx1 = aheadPointDir * pathSpeed * 1.0f; // than matching the destination vector // calculate coefficients idVec3 D = x0; idVec3 C = dx0; idVec3 B = 3*x1 - dx1 - 2*C - 3*D; idVec3 A = x1 - B - C - D; float distanceLeft = ( endPoint - origin ).Length(); lookaheadFactor = ( distanceLeft / 6096.0f ) * 0.5f; lookaheadFactor = idMath::ClampFloat( 0.2f, 0.5f, lookaheadFactor ); if ( !slowNearEnd ) { lookaheadFactor = 0.5f; } point = ( A * lookaheadFactor + B )*lookaheadFactor*lookaheadFactor + C*lookaheadFactor + D; } // // Follower logic // idVec3 delta = point - origin; idVec3 aheadDelta = aheadPoint - origin; idVec3 newVelocity = vec3_origin; // // Z axis // // figure out what Z velocity is needed to get where we want to go within a frame float Zvel = aheadDelta.z / frameTime; Zvel = idMath::ClampFloat( -maxZVel, maxZVel, Zvel ); // figure out what Z acceleration is neccessary float ZAccel = ( Zvel - velocity.z ) / frameTime; ZAccel = idMath::ClampFloat( -maxZAccel, maxZAccel, ZAccel ); // chop the Z acceleration when its nearing the end - helps to avoid settling issues if ( lookaheadFactor < 0.5f ) { ZAccel *= idMath::Sqrt( lookaheadFactor * 2.0f ); } Zvel = velocity.z + ZAccel * frameTime; // rapidly prevent acceleration downwards when its below the target if ( aheadDelta.z > 0.0f && Zvel < 0.0f ) { Zvel *= 0.9f; } // // X & Y // // ignore Z delta.z = 0.0f; aheadDelta.z = 0.0f; idVec3 flatVelocity = velocity; flatVelocity.z = 0.0f; float distance = delta.Length(); idVec3 direction; if ( distance > idMath::FLT_EPSILON ) { direction = delta / distance; } else { direction = vec3_origin; } // figure out how fast it needs to go to get there in time float vel = distance / 0.5f; vel = idMath::ClampFloat( -pathSpeed, pathSpeed, vel ); idVec3 vecVel = vel * direction; // figure out what acceleration is neccessary idVec3 velDelta = vecVel - flatVelocity; idVec3 velDeltaDir = velDelta; float velDeltaLength = velDeltaDir.Normalize(); float accel = velDeltaLength / frameTime; accel = idMath::ClampFloat( -600.0f, 600.0f, accel ); idVec3 vecAccel = accel * frameTime * velDeltaDir; newVelocity = flatVelocity + vecAccel; newVelocity.z = Zvel; // // Angles // idVec3 velDir = velocity; float velLength = velDir.Normalize(); // calculate what acceleration we are undergoing idVec3 velAccel = ( newVelocity - velocity ) / frameTime; // calculate a component due to air resistance float speed = InchesToMetres( velLength ); float rho = 1.2f; float sideArea = InchesToMetres( 650.0f ) * InchesToMetres( 650.0f ); float Cd = 0.6f; float dragForceMagnitude = MetresToInches( 0.5 * Cd * sideArea * rho * speed * speed ); // assume mass is 10,000 -> I know this works nicely idVec3 dragAccel = ( dragForceMagnitude / 10000.f ) * velDir; idVec3 desiredAccel = velAccel + dragAccel; desiredAccel *= 0.4f; desiredAccel.z += MetresToInches( 9.8f ); // ok, so we desire to be looking at the target idVec3 forwards = endPoint - origin; forwards.z = 0.0f; forwards.Normalize(); if ( orientToEnd ) { idAngles targetAngles = ang_zero; targetAngles.yaw = idMath::AngleNormalize180( itemRotation ); forwards = targetAngles.ToForward(); } // figure out the axes corresponding to this orientation idVec3 up = desiredAccel; up.Normalize(); idVec3 right = up.Cross( forwards ); right.Normalize(); forwards = right.Cross( up ); forwards.Normalize(); // convert that to an angles idAngles desiredAngles = ( idMat3( forwards, right, up ) ).ToAngles(); if ( clampRoll ) { desiredAngles.roll = idMath::ClampFloat( -9.0f, 9.0f, desiredAngles.roll ); } else { desiredAngles.roll = idMath::ClampFloat( -30.0f, 30.0f, desiredAngles.roll ); } desiredAngles.pitch = idMath::ClampFloat( -30.0f, 30.0f, desiredAngles.pitch ); // find the diff between that and what we currently have idAngles diffAngles = ( desiredAngles - angles ).Normalize180(); diffAngles = diffAngles * 0.1f; diffAngles = diffAngles / frameTime; diffAngles *= 0.1f; // translate the old angular velocity back to an angle diff style value idAngles oldDiffAngles; oldDiffAngles.pitch = angVel * currentRight; oldDiffAngles.yaw = angVel * currentUp; oldDiffAngles.roll = angVel * currentFwd; // blend the old and the new to soften the quick changes diffAngles = oldDiffAngles * 0.9f + diffAngles * 0.1f; // figure out how much we're trying to change by in a single frame idAngles angleAccel = diffAngles - oldDiffAngles; float maxAngleAccel = 45.0f * frameTime; float maxYawAccel = maxAngleAccel * maxYawScale; angleAccel.pitch = idMath::ClampFloat( -maxAngleAccel, maxAngleAccel, angleAccel.pitch ); angleAccel.yaw = idMath::ClampFloat( -maxYawAccel, maxYawAccel, angleAccel.yaw ); angleAccel.roll = idMath::ClampFloat( -maxAngleAccel, maxAngleAccel, angleAccel.roll ); diffAngles = oldDiffAngles + angleAccel; idVec3 newAngVel = diffAngles.pitch * currentRight + diffAngles.yaw * currentUp + diffAngles.roll * currentFwd; // HACK: ensure it never gets below the minimum height if ( currentHeight < HOVER_HEIGHT_MIN ) { idVec3 newOrigin = origin; newOrigin.z = origin.z - currentHeight + HOVER_HEIGHT_MIN; GetPhysics()->SetOrigin( newOrigin ); } else if ( currentHeight < HOVER_HEIGHT_RESCUE ) { float oldNewVelLength = newVelocity.Length(); float scale = ( HOVER_HEIGHT_RESCUE - currentHeight ) / ( HOVER_HEIGHT_RESCUE - HOVER_HEIGHT_MIN ); scale = idMath::Sqrt( scale ); float rescueVelocity = scale * ( HOVER_HEIGHT_RESCUE - HOVER_HEIGHT_MIN ) / 0.5f; float rescueAcceleration = ( rescueVelocity - velocity.z ) / frameTime; rescueAcceleration = idMath::ClampFloat( 0.0f, 1800.0f, rescueAcceleration ); rescueVelocity = velocity.z + rescueAcceleration * frameTime; if ( rescueVelocity > newVelocity.z ) { newVelocity.z = rescueVelocity; } newVelocity.Normalize(); newVelocity *= oldNewVelLength; } GetPhysics()->SetLinearVelocity( newVelocity ); GetPhysics()->SetAxis( angles.ToMat3() ); GetPhysics()->SetAngularVelocity( newAngVel ); }
/* ================ sdClientAnimated::Event_SetJointAngle ================ */ void sdClientAnimated::Event_SetJointAngle( jointHandle_t joint, jointModTransform_t transformType, const idAngles& angles ) { animator.SetJointAxis( joint, transformType, angles.ToMat3() ); }
/* ================ hhCameraInterpolator::UpdateViewAngles ================ */ idAngles hhCameraInterpolator::UpdateViewAngles( const idAngles& viewAngles ) { return (viewAngles.ToMat3() * GetCurrentAxis()).ToAngles(); }