//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #ifndef CONSTRAINTS_H #define CONSTRAINTS_H #ifdef _WIN32 #pragma once #endif #include "mathlib/mathlib.h" #include "vphysics_interface.h" // constraint groups struct constraint_groupparams_t { int additionalIterations; // additional solver iterations make the // constraint system more stable int minErrorTicks; // minimum number of ticks with an error before it's // reported float errorTolerance; // error tolerance in HL units inline void Defaults() { additionalIterations = 0; minErrorTicks = 15; errorTolerance = 3.0f; } }; // Breakable constraints; // // forceLimit - kg * in / s limit (N * conversion(in/m)) // torqueLimit - kg * in^2 / s (Nm * conversion(in^2/m^2)) // // strength 0 - 1 struct constraint_breakableparams_t { float strength; // strength of the constraint 0.0 - 1.0 float forceLimit; // constraint force limit to break (0 means never break) float torqueLimit; // constraint torque limit to break (0 means never break) float bodyMassScale[2]; // scale applied to mass of reference/attached // object before solving constriant bool isActive; inline void Defaults() { forceLimit = 0.0f; torqueLimit = 0.0f; strength = 1.0f; bodyMassScale[0] = 1.0f; bodyMassScale[1] = 1.0f; isActive = true; } }; //----------------------------------------------------------------------------- // Purpose: constraint limit on a single rotation axis //----------------------------------------------------------------------------- struct constraint_axislimit_t { float minRotation; float maxRotation; float angularVelocity; // desired angular velocity around hinge float torque; // torque to achieve angular velocity (use 0, torque for // "friction") inline void SetAxisFriction(float rmin, float rmax, float friction) { minRotation = rmin; maxRotation = rmax; angularVelocity = 0; torque = friction; } inline void Defaults() { SetAxisFriction(0, 0, 0); } }; // Builds a transform which maps points in the input object's local space // to the output object's local space inline void BuildObjectRelativeXform(IPhysicsObject *pOutputSpace, IPhysicsObject *pInputSpace, matrix3x4_t &xformInToOut) { matrix3x4_t outInv, tmp, input; pOutputSpace->GetPositionMatrix(&tmp); MatrixInvert(tmp, outInv); pInputSpace->GetPositionMatrix(&input); ConcatTransforms(outInv, input, xformInToOut); } //----------------------------------------------------------------------------- // Purpose: special limited ballsocket constraint for ragdolls. // Has axis limits for all 3 axes. //----------------------------------------------------------------------------- struct constraint_ragdollparams_t { constraint_breakableparams_t constraint; matrix3x4_t constraintToReference; // xform constraint space to refobject space matrix3x4_t constraintToAttached; // xform constraint space to attached // object space int parentIndex; // NOTE: only used for parsing. NEED NOT BE SET for // create int childIndex; // NOTE: only used for parsing. NEED NOT BE SET for create constraint_axislimit_t axes[3]; bool onlyAngularLimits; // only angular limits (not translation as well?) bool isActive; bool useClockwiseRotations; // HACKHACK: Did this wrong in version one. Fix // in the future. inline void Defaults() { constraint.Defaults(); isActive = true; SetIdentityMatrix(constraintToReference); SetIdentityMatrix(constraintToAttached); parentIndex = -1; childIndex = -1; axes[0].Defaults(); axes[1].Defaults(); axes[2].Defaults(); onlyAngularLimits = false; useClockwiseRotations = false; } }; //----------------------------------------------------------------------------- // Purpose: Used to init a hinge restricting the relative position and // orientation // of two objects to rotation around a single axis //----------------------------------------------------------------------------- struct constraint_hingeparams_t { Vector worldPosition; // position in world space on the hinge axis Vector worldAxisDirection; // unit direction vector of the hinge axis in // world space constraint_axislimit_t hingeAxis; constraint_breakableparams_t constraint; inline void Defaults() { worldPosition.Init(); worldAxisDirection.Init(); hingeAxis.Defaults(); constraint.Defaults(); } }; struct constraint_limitedhingeparams_t : public constraint_hingeparams_t { Vector referencePerpAxisDirection; // unit direction vector vector // perpendicular to the hinge axis in // world space Vector attachedPerpAxisDirection; // unit direction vector vector // perpendicular to the hinge axis in // world space constraint_limitedhingeparams_t() {} constraint_limitedhingeparams_t(const constraint_hingeparams_t &hinge) { static_cast(*this) = hinge; referencePerpAxisDirection.Init(); attachedPerpAxisDirection.Init(); } inline void Defaults() { this->constraint_hingeparams_t::Defaults(); referencePerpAxisDirection.Init(); attachedPerpAxisDirection.Init(); } }; //----------------------------------------------------------------------------- // Purpose: Used to init a constraint that fixes the position and orientation // of two objects relative to each other (like glue) //----------------------------------------------------------------------------- struct constraint_fixedparams_t { matrix3x4_t attachedRefXform; // xform attached object space to ref object space constraint_breakableparams_t constraint; inline void InitWithCurrentObjectState(IPhysicsObject *pRef, IPhysicsObject *pAttached) { BuildObjectRelativeXform(pRef, pAttached, attachedRefXform); } inline void Defaults() { SetIdentityMatrix(attachedRefXform); constraint.Defaults(); } }; //----------------------------------------------------------------------------- // Purpose: Same parameters as fixed constraint, but torqueLimit has no effect //----------------------------------------------------------------------------- struct constraint_ballsocketparams_t { Vector constraintPosition[2]; // position of the constraint in each // object's space constraint_breakableparams_t constraint; inline void Defaults() { constraint.Defaults(); constraintPosition[0].Init(); constraintPosition[1].Init(); } void InitWithCurrentObjectState(IPhysicsObject *pRef, IPhysicsObject *pAttached, const Vector &ballsocketOrigin) { pRef->WorldToLocal(&constraintPosition[0], ballsocketOrigin); pAttached->WorldToLocal(&constraintPosition[1], ballsocketOrigin); } }; struct constraint_slidingparams_t { matrix3x4_t attachedRefXform; // xform attached object space to ref object space Vector slideAxisRef; // unit direction vector of the slide axis in ref // object space constraint_breakableparams_t constraint; // NOTE: if limitMin == limitMax there is NO limit set! float limitMin; // minimum limit coordinate refAxisDirection space float limitMax; // maximum limit coordinate refAxisDirection space float friction; // friction on sliding float velocity; // desired velocity inline void Defaults() { SetIdentityMatrix(attachedRefXform); slideAxisRef.Init(); limitMin = limitMax = 0; friction = 0; velocity = 0; constraint.Defaults(); } inline void SetFriction(float inputFriction) { friction = inputFriction; velocity = 0; } inline void SetLinearMotor(float inputVelocity, float maxForce) { friction = maxForce; velocity = inputVelocity; } inline void InitWithCurrentObjectState(IPhysicsObject *pRef, IPhysicsObject *pAttached, const Vector &slideDirWorldspace) { BuildObjectRelativeXform(pRef, pAttached, attachedRefXform); matrix3x4_t tmp; pRef->GetPositionMatrix(&tmp); VectorIRotate(slideDirWorldspace, tmp, slideAxisRef); } }; struct constraint_pulleyparams_t { constraint_breakableparams_t constraint; Vector pulleyPosition[2]; // These are the pulley positions for the // reference and attached objects in world space Vector objectPosition[2]; // local positions of attachments to the ref,att // objects float totalLength; // total rope length (include gearing!) float gearRatio; // gearing affects attached object ALWAYS bool isRigid; inline void Defaults() { constraint.Defaults(); totalLength = 1.0; gearRatio = 1.0; pulleyPosition[0].Init(); pulleyPosition[1].Init(); objectPosition[0].Init(); objectPosition[1].Init(); isRigid = false; } }; struct constraint_lengthparams_t { constraint_breakableparams_t constraint; Vector objectPosition[2]; // These are the positions for the reference and // attached objects in local space float totalLength; // Length of rope/spring/constraint. Distance to maintain float minLength; // if rigid, objects are not allowed to move closer than // totalLength either void InitWorldspace(IPhysicsObject *pRef, IPhysicsObject *pAttached, const Vector &refPosition, const Vector &attachedPosition, bool rigid = false) { pRef->WorldToLocal(&objectPosition[0], refPosition); pAttached->WorldToLocal(&objectPosition[1], attachedPosition); totalLength = (refPosition - attachedPosition).Length(); minLength = rigid ? totalLength : 0; } inline void Defaults() { constraint.Defaults(); objectPosition[0].Init(); objectPosition[1].Init(); totalLength = 1; minLength = 0; } }; class IPhysicsConstraint { public: virtual ~IPhysicsConstraint(void) {} // NOTE: Constraints are active when created. You can temporarily // enable/disable them with these functions virtual void Activate(void) = 0; virtual void Deactivate(void) = 0; // set a pointer to the game object virtual void SetGameData(void *gameData) = 0; // get a pointer to the game object virtual void *GetGameData(void) const = 0; // Get the parent/referenced object virtual IPhysicsObject *GetReferenceObject(void) const = 0; // Get the attached object virtual IPhysicsObject *GetAttachedObject(void) const = 0; virtual void SetLinearMotor(float speed, float maxLinearImpulse) = 0; virtual void SetAngularMotor(float rotSpeed, float maxAngularImpulse) = 0; virtual void UpdateRagdollTransforms( const matrix3x4_t &constraintToReference, const matrix3x4_t &constraintToAttached) = 0; virtual bool GetConstraintTransform( matrix3x4_t *pConstraintToReference, matrix3x4_t *pConstraintToAttached) const = 0; virtual bool GetConstraintParams( constraint_breakableparams_t *pParams) const = 0; virtual void OutputDebugInfo() = 0; }; class IPhysicsConstraintGroup { public: virtual ~IPhysicsConstraintGroup(void) {} virtual void Activate() = 0; virtual bool IsInErrorState() = 0; virtual void ClearErrorState() = 0; virtual void GetErrorParams(constraint_groupparams_t *pParams) = 0; virtual void SetErrorParams(const constraint_groupparams_t ¶ms) = 0; virtual void SolvePenetration(IPhysicsObject *pObj0, IPhysicsObject *pObj1) = 0; }; #endif // CONSTRAINTS_H