//----------------------------------------------------------------------------- // Computes the surrounding collision bounds from the current sequence box //----------------------------------------------------------------------------- void CCollisionProperty::ComputeRotationExpandedSequenceBounds( Vector *pVecWorldMins, Vector *pVecWorldMaxs ) { CBaseAnimating *pAnim = GetOuter()->GetBaseAnimating(); if ( !pAnim ) { ComputeOBBBounds( pVecWorldMins, pVecWorldMaxs ); return; } Vector mins, maxs; pAnim->ExtractBbox( pAnim->GetSequence(), mins, maxs ); float flRadius = MAX( MAX( FloatMakePositive( mins.x ), FloatMakePositive( maxs.x ) ), MAX( FloatMakePositive( mins.y ), FloatMakePositive( maxs.y ) ) ); mins.x = mins.y = -flRadius; maxs.x = maxs.y = flRadius; // Add bloat to account for gesture sequences Vector vecBloat( 6, 6, 0 ); mins -= vecBloat; maxs += vecBloat; // NOTE: This is necessary because the server doesn't know how to blend // animations together. Therefore, we have to just pick a box that can // surround all of our potential sequences. This should be something we // should be able to compute @ tool time instead, however. VectorMin( mins, m_vecSurroundingMins, mins ); VectorMax( maxs, m_vecSurroundingMaxs, maxs ); VectorAdd( mins, GetCollisionOrigin(), *pVecWorldMins ); VectorAdd( maxs, GetCollisionOrigin(), *pVecWorldMaxs ); }
//----------------------------------------------------------------------------- // Builds a rotation matrix that rotates one direction vector into another //----------------------------------------------------------------------------- void MatrixBuildRotation( VMatrix &dst, const Vector& initialDirection, const Vector& finalDirection ) { float angle = DotProduct( initialDirection, finalDirection ); assert( IsFinite(angle) ); Vector axis; // No rotation required if (angle - 1.0 > -1e-3) { // parallel case MatrixSetIdentity(dst); return; } else if (angle + 1.0 < 1e-3) { // antiparallel case, pick any axis in the plane // perpendicular to the final direction. Choose the direction (x,y,z) // which has the minimum component of the final direction, use that // as an initial guess, then subtract out the component which is // parallel to the final direction int idx = 0; if (FloatMakePositive(finalDirection[1]) < FloatMakePositive(finalDirection[idx])) idx = 1; if (FloatMakePositive(finalDirection[2]) < FloatMakePositive(finalDirection[idx])) idx = 2; axis.Init( 0, 0, 0 ); axis[idx] = 1.0f; VectorMA( axis, -DotProduct( axis, finalDirection ), finalDirection, axis ); VectorNormalize(axis); angle = 180.0f; } else { CrossProduct( initialDirection, finalDirection, axis ); VectorNormalize( axis ); angle = acos(angle) * 180 / M_PI; } MatrixBuildRotationAboutAxis( dst, axis, angle ); #ifdef _DEBUG Vector test; Vector3DMultiply( dst, initialDirection, test ); test -= finalDirection; assert( test.LengthSqr() < 1e-3 ); #endif }
bool VMatrix::IsRotationMatrix() const { Vector &v1 = (Vector&)m[0][0]; Vector &v2 = (Vector&)m[1][0]; Vector &v3 = (Vector&)m[2][0]; return FloatMakePositive( 1 - v1.Length() ) < 0.01f && FloatMakePositive( 1 - v2.Length() ) < 0.01f && FloatMakePositive( 1 - v3.Length() ) < 0.01f && FloatMakePositive( v1.Dot(v2) ) < 0.01f && FloatMakePositive( v1.Dot(v3) ) < 0.01f && FloatMakePositive( v2.Dot(v3) ) < 0.01f; }
//----------------------------------------------------------------------------- // Purpose: Find the minor projection axes based on the given normal. //----------------------------------------------------------------------------- void CVRADDispColl::GetMinorAxes( Vector const &vecNormal, int &nAxis0, int &nAxis1 ) { nAxis0 = 0; nAxis1 = 1; if( FloatMakePositive( vecNormal.x ) > FloatMakePositive( vecNormal.y ) ) { if( FloatMakePositive( vecNormal.x ) > FloatMakePositive( vecNormal.z ) ) { nAxis0 = 1; nAxis1 = 2; } } else { if( FloatMakePositive( vecNormal.y ) > FloatMakePositive( vecNormal.z ) ) { nAxis0 = 0; nAxis1 = 2; } } }
//----------------------------------------------------------------------------- // Computes the surrounding collision bounds from the the OBB (not vphysics) //----------------------------------------------------------------------------- void CCollisionProperty::ComputeRotationExpandedBounds( Vector *pVecWorldMins, Vector *pVecWorldMaxs ) { if ( !IsBoundsDefinedInEntitySpace() ) { *pVecWorldMins = m_vecMins; *pVecWorldMaxs = m_vecMaxs; } else { float flMaxVal; flMaxVal = max( FloatMakePositive(m_vecMins.Get().x), FloatMakePositive(m_vecMaxs.Get().x) ); pVecWorldMins->x = -flMaxVal; pVecWorldMaxs->x = flMaxVal; flMaxVal = max( FloatMakePositive(m_vecMins.Get().y), FloatMakePositive(m_vecMaxs.Get().y) ); pVecWorldMins->y = -flMaxVal; pVecWorldMaxs->y = flMaxVal; flMaxVal = max( FloatMakePositive(m_vecMins.Get().z), FloatMakePositive(m_vecMaxs.Get().z) ); pVecWorldMins->z = -flMaxVal; pVecWorldMaxs->z = flMaxVal; } }
bool MatrixInverseGeneral(const VMatrix& src, VMatrix& dst) { int iRow, i, j, iTemp, iTest; vec_t mul, fTest, fLargest; vec_t mat[4][8]; int rowMap[4], iLargest; vec_t *pOut, *pRow, *pScaleRow; // How it's done. // AX = I // A = this // X = the matrix we're looking for // I = identity // Setup AI for(i=0; i < 4; i++) { const vec_t *pIn = src[i]; pOut = mat[i]; for(j=0; j < 4; j++) { pOut[j] = pIn[j]; } pOut[4] = 0.0f; pOut[5] = 0.0f; pOut[6] = 0.0f; pOut[7] = 0.0f; pOut[i+4] = 1.0f; rowMap[i] = i; } // Use row operations to get to reduced row-echelon form using these rules: // 1. Multiply or divide a row by a nonzero number. // 2. Add a multiple of one row to another. // 3. Interchange two rows. for(iRow=0; iRow < 4; iRow++) { // Find the row with the largest element in this column. fLargest = 0.001f; iLargest = -1; for(iTest=iRow; iTest < 4; iTest++) { fTest = (vec_t)FloatMakePositive(mat[rowMap[iTest]][iRow]); if(fTest > fLargest) { iLargest = iTest; fLargest = fTest; } } // They're all too small.. sorry. if(iLargest == -1) { return false; } // Swap the rows. iTemp = rowMap[iLargest]; rowMap[iLargest] = rowMap[iRow]; rowMap[iRow] = iTemp; pRow = mat[rowMap[iRow]]; // Divide this row by the element. mul = 1.0f / pRow[iRow]; for(j=0; j < 8; j++) pRow[j] *= mul; pRow[iRow] = 1.0f; // Preserve accuracy... // Eliminate this element from the other rows using operation 2. for(i=0; i < 4; i++) { if(i == iRow) continue; pScaleRow = mat[rowMap[i]]; // Multiply this row by -(iRow*the element). mul = -pScaleRow[iRow]; for(j=0; j < 8; j++) { pScaleRow[j] += pRow[j] * mul; } pScaleRow[iRow] = 0.0f; // Preserve accuracy... } } // The inverse is on the right side of AX now (the identity is on the left). for(i=0; i < 4; i++) { const vec_t *pIn = mat[rowMap[i]] + 4; pOut = dst.m[i]; for(j=0; j < 4; j++) { pOut[j] = pIn[j]; } } return true; }
char *V_pretifymem( float value, int digitsafterdecimal /*= 2*/, bool usebinaryonek /*= false*/ ) { static char output[ NUM_PRETIFYMEM_BUFFERS ][ 32 ]; static int current; float onekb = usebinaryonek ? 1024.0f : 1000.0f; float onemb = onekb * onekb; char *out = output[ current ]; current = ( current + 1 ) & ( NUM_PRETIFYMEM_BUFFERS -1 ); char suffix[ 8 ]; // First figure out which bin to use if ( value > onemb ) { value /= onemb; V_snprintf( suffix, sizeof( suffix ), " MB" ); } else if ( value > onekb ) { value /= onekb; V_snprintf( suffix, sizeof( suffix ), " KB" ); } else { V_snprintf( suffix, sizeof( suffix ), " bytes" ); } char val[ 32 ]; // Clamp to >= 0 digitsafterdecimal = max( digitsafterdecimal, 0 ); // If it's basically integral, don't do any decimals if ( FloatMakePositive( value - (int)value ) < 0.00001 ) { V_snprintf( val, sizeof( val ), "%i%s", (int)value, suffix ); } else { char fmt[ 32 ]; // Otherwise, create a format string for the decimals V_snprintf( fmt, sizeof( fmt ), "%%.%if%s", digitsafterdecimal, suffix ); V_snprintf( val, sizeof( val ), fmt, value ); } // Copy from in to out char *i = val; char *o = out; // Search for decimal or if it was integral, find the space after the raw number char *dot = strstr( i, "." ); if ( !dot ) { dot = strstr( i, " " ); } // Compute position of dot int pos = dot - i; // Don't put a comma if it's <= 3 long pos -= 3; while ( *i ) { // If pos is still valid then insert a comma every third digit, except if we would be // putting one in the first spot if ( pos >= 0 && !( pos % 3 ) ) { // Never in first spot if ( o != out ) { *o++ = ','; } } // Count down comma position pos--; // Copy rest of data as normal *o++ = *i++; } // Terminate *o = 0; return out; }
//----------------------------------------------------------------------------- // Purpose: Apply joystick to CUserCmd creation // Input : frametime - // *cmd - //----------------------------------------------------------------------------- void CInput::JoyStickMove( float frametime, CUserCmd *cmd ) { // complete initialization if first time in ( needed as cvars are not available at initialization time ) if ( !m_fJoystickAdvancedInit ) { Joystick_Advanced(); m_fJoystickAdvancedInit = true; } // verify joystick is available and that the user wants to use it if ( !in_joystick.GetInt() || 0 == inputsystem->GetJoystickCount() ) return; // Skip out if vgui is active if ( vgui::surface()->IsCursorVisible() ) return; if ( m_flRemainingJoystickSampleTime <= 0 ) return; frametime = MIN(m_flRemainingJoystickSampleTime, frametime); m_flRemainingJoystickSampleTime -= frametime; QAngle viewangles; // Get starting angles engine->GetViewAngles( viewangles ); struct axis_t { float value; int controlType; }; axis_t gameAxes[ MAX_GAME_AXES ]; memset( &gameAxes, 0, sizeof(gameAxes) ); // Get each joystick axis value, and normalize the range for ( int i = 0; i < MAX_JOYSTICK_AXES; ++i ) { if ( GAME_AXIS_NONE == m_rgAxes[i].AxisMap ) continue; float fAxisValue = inputsystem->GetAnalogValue( (AnalogCode_t)JOYSTICK_AXIS( 0, i ) ); if (joy_wwhack2.GetInt() != 0 ) { // this is a special formula for the Logitech WingMan Warrior // y=ax^b; where a = 300 and b = 1.3 // also x values are in increments of 800 (so this is factored out) // then bounds check result to level out excessively high spin rates float fTemp = 300.0 * pow(abs(fAxisValue) / 800.0, 1.3); if (fTemp > 14000.0) fTemp = 14000.0; // restore direction information fAxisValue = (fAxisValue > 0.0) ? fTemp : -fTemp; } unsigned int idx = m_rgAxes[i].AxisMap; gameAxes[idx].value = fAxisValue; gameAxes[idx].controlType = m_rgAxes[i].ControlMap; } // Re-map the axis values if necessary, based on the joystick configuration if ( (joy_advanced.GetInt() == 0) && (in_jlook.state & 1) ) { // user wants forward control to become pitch control gameAxes[GAME_AXIS_PITCH] = gameAxes[GAME_AXIS_FORWARD]; gameAxes[GAME_AXIS_FORWARD].value = 0; // if mouse invert is on, invert the joystick pitch value // Note: only absolute control support here - joy_advanced = 0 if ( m_pitch->GetFloat() < 0.0 ) { gameAxes[GAME_AXIS_PITCH].value *= -1; } } if ( (in_strafe.state & 1) || lookstrafe.GetFloat() && (in_jlook.state & 1) ) { // user wants yaw control to become side control gameAxes[GAME_AXIS_SIDE] = gameAxes[GAME_AXIS_YAW]; gameAxes[GAME_AXIS_YAW].value = 0; } float forward = ScaleAxisValue( gameAxes[GAME_AXIS_FORWARD].value, MAX_BUTTONSAMPLE * joy_forwardthreshold.GetFloat() ); float side = ScaleAxisValue( gameAxes[GAME_AXIS_SIDE].value, MAX_BUTTONSAMPLE * joy_sidethreshold.GetFloat() ); float pitch = ScaleAxisValue( gameAxes[GAME_AXIS_PITCH].value, MAX_BUTTONSAMPLE * joy_pitchthreshold.GetFloat() ); float yaw = ScaleAxisValue( gameAxes[GAME_AXIS_YAW].value, MAX_BUTTONSAMPLE * joy_yawthreshold.GetFloat() ); // If we're inverting our joystick, do so if ( joy_inverty.GetBool() ) { pitch *= -1.0f; } // drive yaw, pitch and move like a screen relative platformer game if ( CAM_IsThirdPerson() && thirdperson_platformer.GetInt() ) { if ( forward || side ) { // apply turn control [ YAW ] // factor in the camera offset, so that the move direction is relative to the thirdperson camera viewangles[ YAW ] = RAD2DEG(atan2(-side, -forward)) + m_vecCameraOffset[ YAW ]; engine->SetViewAngles( viewangles ); // apply movement Vector2D moveDir( forward, side ); cmd->forwardmove += moveDir.Length() * cl_forwardspeed.GetFloat(); } if ( pitch || yaw ) { // look around with the camera m_vecCameraOffset[ PITCH ] += pitch * joy_pitchsensitivity.GetFloat(); m_vecCameraOffset[ YAW ] += yaw * joy_yawsensitivity.GetFloat(); } if ( forward || side || pitch || yaw ) { // update the ideal pitch and yaw cam_idealpitch.SetValue( m_vecCameraOffset[ PITCH ] - viewangles[ PITCH ] ); cam_idealyaw.SetValue( m_vecCameraOffset[ YAW ] - viewangles[ YAW ] ); } return; } float joySideMove = 0.f; float joyForwardMove = 0.f; float aspeed = frametime * gHUD.GetFOVSensitivityAdjust(); // apply forward and side control C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); int iResponseCurve = 0; if ( pLocalPlayer && pLocalPlayer->IsInAVehicle() ) { iResponseCurve = pLocalPlayer->GetVehicle() ? pLocalPlayer->GetVehicle()->GetJoystickResponseCurve() : joy_response_move_vehicle.GetInt(); } else { iResponseCurve = joy_response_move.GetInt(); } float val = ResponseCurve( iResponseCurve, forward, PITCH, joy_forwardsensitivity.GetFloat() ); joyForwardMove += val * cl_forwardspeed.GetFloat(); val = ResponseCurve( iResponseCurve, side, YAW, joy_sidesensitivity.GetFloat() ); joySideMove += val * cl_sidespeed.GetFloat(); Vector2D move( yaw, pitch ); float dist = move.Length(); // apply turn control float angle = 0.f; if ( JOY_ABSOLUTE_AXIS == gameAxes[GAME_AXIS_YAW].controlType ) { float fAxisValue = ResponseCurveLook( joy_response_look.GetInt(), yaw, YAW, pitch, dist, frametime ); angle = fAxisValue * joy_yawsensitivity.GetFloat() * aspeed * cl_yawspeed.GetFloat(); } else { angle = yaw * joy_yawsensitivity.GetFloat() * aspeed * 180.0; } viewangles[YAW] += angle; cmd->mousedx = angle; // apply look control if ( IsX360() || in_jlook.state & 1 ) { float angle = 0; if ( JOY_ABSOLUTE_AXIS == gameAxes[GAME_AXIS_PITCH].controlType ) { float fAxisValue = ResponseCurveLook( joy_response_look.GetInt(), pitch, PITCH, yaw, dist, frametime ); angle = fAxisValue * joy_pitchsensitivity.GetFloat() * aspeed * cl_pitchspeed.GetFloat(); } else { angle = pitch * joy_pitchsensitivity.GetFloat() * aspeed * 180.0; } viewangles[PITCH] += angle; cmd->mousedy = angle; view->StopPitchDrift(); if( pitch == 0.f && lookspring.GetFloat() == 0.f ) { // no pitch movement // disable pitch return-to-center unless requested by user // *** this code can be removed when the lookspring bug is fixed // *** the bug always has the lookspring feature on view->StopPitchDrift(); } } // apply player motion relative to screen space if ( CAM_IsThirdPerson() && thirdperson_screenspace.GetInt() ) { float ideal_yaw = cam_idealyaw.GetFloat(); float ideal_sin = sin(DEG2RAD(ideal_yaw)); float ideal_cos = cos(DEG2RAD(ideal_yaw)); float side_movement = ideal_cos*joySideMove - ideal_sin*joyForwardMove; float forward_movement = ideal_cos*joyForwardMove + ideal_sin*joySideMove; cmd->forwardmove += forward_movement; cmd->sidemove += side_movement; } else { cmd->forwardmove += joyForwardMove; cmd->sidemove += joySideMove; } if ( IsPC() ) { CCommand tmp; if ( FloatMakePositive(joyForwardMove) >= joy_autosprint.GetFloat() || FloatMakePositive(joySideMove) >= joy_autosprint.GetFloat() ) { KeyDown( &in_joyspeed, NULL ); } else { KeyUp( &in_joyspeed, NULL ); } } // Bound pitch viewangles[PITCH] = clamp( viewangles[ PITCH ], -cl_pitchup.GetFloat(), cl_pitchdown.GetFloat() ); engine->SetViewAngles( viewangles ); }
//----------------------------------------------------------------------------- // Purpose: Apply joystick to CUserCmd creation // Input : frametime - // *cmd - //----------------------------------------------------------------------------- void CInput::JoyStickMove( float frametime, CUserCmd *cmd ) { // complete initialization if first time in ( needed as cvars are not available at initialization time ) if ( !m_fJoystickAdvancedInit ) { Joystick_Advanced(); m_fJoystickAdvancedInit = true; } // verify joystick is available and that the user wants to use it if ( !in_joystick.GetInt() || 0 == inputsystem->GetJoystickCount() ) { return; } QAngle viewangles; // Get starting angles engine->GetViewAngles( viewangles ); struct axis_t { float value; int controlType; }; axis_t gameAxes[ MAX_GAME_AXES ]; memset( &gameAxes, 0, sizeof(gameAxes) ); // Get each joystick axis value, and normalize the range for ( int i = 0; i < MAX_JOYSTICK_AXES; ++i ) { if ( GAME_AXIS_NONE == m_rgAxes[i].AxisMap ) continue; float fAxisValue = inputsystem->GetAnalogValue( (AnalogCode_t)JOYSTICK_AXIS( 0, i ) ); if (joy_wwhack2.GetInt() != 0 ) { // this is a special formula for the Logitech WingMan Warrior // y=ax^b; where a = 300 and b = 1.3 // also x values are in increments of 800 (so this is factored out) // then bounds check result to level out excessively high spin rates float fTemp = 300.0 * pow(abs(fAxisValue) / 800.0, 1.3); if (fTemp > 14000.0) fTemp = 14000.0; // restore direction information fAxisValue = (fAxisValue > 0.0) ? fTemp : -fTemp; } unsigned int idx = m_rgAxes[i].AxisMap; gameAxes[idx].value = fAxisValue; gameAxes[idx].controlType = m_rgAxes[i].ControlMap; } // Re-map the axis values if necessary, based on the joystick configuration if ( (joy_advanced.GetInt() == 0) && (in_jlook.state & 1) ) { // user wants forward control to become pitch control gameAxes[GAME_AXIS_PITCH] = gameAxes[GAME_AXIS_FORWARD]; gameAxes[GAME_AXIS_FORWARD].value = 0; // if mouse invert is on, invert the joystick pitch value // Note: only absolute control support here - joy_advanced = 0 if ( m_pitch.GetFloat() < 0.0 ) { gameAxes[GAME_AXIS_PITCH].value *= -1; } } if ( (in_strafe.state & 1) || lookstrafe.GetFloat() && (in_jlook.state & 1) ) { // user wants yaw control to become side control gameAxes[GAME_AXIS_SIDE] = gameAxes[GAME_AXIS_YAW]; gameAxes[GAME_AXIS_YAW].value = 0; } float forward = ScaleAxisValue( gameAxes[GAME_AXIS_FORWARD].value, MAX_BUTTONSAMPLE * joy_forwardthreshold.GetFloat() ); float side = ScaleAxisValue( gameAxes[GAME_AXIS_SIDE].value, MAX_BUTTONSAMPLE * joy_sidethreshold.GetFloat() ); float pitch = ScaleAxisValue( gameAxes[GAME_AXIS_PITCH].value, MAX_BUTTONSAMPLE * joy_pitchthreshold.GetFloat() ); float yaw = ScaleAxisValue( gameAxes[GAME_AXIS_YAW].value, MAX_BUTTONSAMPLE * joy_yawthreshold.GetFloat() ); float joySideMove = 0.f; float joyForwardMove = 0.f; float aspeed = frametime * gHUD.GetFOVSensitivityAdjust(); // apply forward and side control joyForwardMove += ResponseCurve( joy_response_move.GetInt(), forward ) * joy_forwardsensitivity.GetFloat() * cl_forwardspeed.GetFloat(); joySideMove += ResponseCurve( joy_response_move.GetInt(), side ) * joy_sidesensitivity.GetFloat() * cl_sidespeed.GetFloat(); Vector2D move( yaw, pitch ); float dist = move.Length(); // apply turn control float angle = 0.f; if ( JOY_ABSOLUTE_AXIS == gameAxes[GAME_AXIS_YAW].controlType ) { float fAxisValue = ResponseCurveLook( joy_response_look.GetInt(), yaw, YAW, pitch, dist ); angle = fAxisValue * joy_yawsensitivity.GetFloat() * aspeed * cl_yawspeed.GetFloat(); } else { angle = yaw * joy_yawsensitivity.GetFloat() * aspeed * 180.0; } viewangles[YAW] += angle; cmd->mousedx = angle; // apply look control if ( IsXbox() || in_jlook.state & 1 ) { float angle = 0; if ( JOY_ABSOLUTE_AXIS == gameAxes[GAME_AXIS_PITCH].controlType ) { float fAxisValue = ResponseCurveLook( joy_response_look.GetInt(), pitch, PITCH, yaw, dist ); angle = fAxisValue * joy_pitchsensitivity.GetFloat() * aspeed * cl_pitchspeed.GetFloat(); } else { angle = pitch * joy_pitchsensitivity.GetFloat() * aspeed * 180.0; } viewangles[PITCH] += angle; cmd->mousedy = angle; view->StopPitchDrift(); if( pitch == 0.f && lookspring.GetFloat() == 0.f ) { // no pitch movement // disable pitch return-to-center unless requested by user // *** this code can be removed when the lookspring bug is fixed // *** the bug always has the lookspring feature on view->StopPitchDrift(); } } cmd->forwardmove += joyForwardMove; cmd->sidemove += joySideMove; if ( IsPC() ) { if ( FloatMakePositive(joyForwardMove) >= joy_autosprint.GetFloat() || FloatMakePositive(joySideMove) >= joy_autosprint.GetFloat() ) { KeyDown( &in_joyspeed, true ); } else { KeyUp( &in_joyspeed, true ); } } // Bound pitch viewangles[PITCH] = clamp( viewangles[ PITCH ], -cl_pitchup.GetFloat(), cl_pitchdown.GetFloat() ); engine->SetViewAngles( viewangles ); }