├── .github └── FUNDING.yml ├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── include ├── vphysics │ ├── constraintsV32.h │ ├── softbodyV32.h │ └── vehiclesV32.h └── vphysics_interfaceV32.h ├── src ├── DebugDrawer.cpp ├── DebugDrawer.h ├── IController.h ├── Physics.cpp ├── Physics.h ├── Physics_Collision.cpp ├── Physics_Collision.h ├── Physics_CollisionSet.cpp ├── Physics_CollisionSet.h ├── Physics_Constraint.cpp ├── Physics_Constraint.h ├── Physics_DragController.cpp ├── Physics_DragController.h ├── Physics_Environment.cpp ├── Physics_Environment.h ├── Physics_FluidController.cpp ├── Physics_FluidController.h ├── Physics_FrictionSnapshot.cpp ├── Physics_FrictionSnapshot.h ├── Physics_KeyParser.cpp ├── Physics_KeyParser.h ├── Physics_MotionController.cpp ├── Physics_MotionController.h ├── Physics_Object.cpp ├── Physics_Object.h ├── Physics_ObjectPairHash.cpp ├── Physics_ObjectPairHash.h ├── Physics_PlayerController.cpp ├── Physics_PlayerController.h ├── Physics_ShadowController.cpp ├── Physics_ShadowController.h ├── Physics_SoftBody.cpp ├── Physics_SoftBody.h ├── Physics_SurfaceProps.cpp ├── Physics_SurfaceProps.h ├── Physics_VehicleAirboat.cpp ├── Physics_VehicleAirboat.h ├── Physics_VehicleController.cpp ├── Physics_VehicleController.h ├── Physics_VehicleControllerCustom.cpp ├── Physics_VehicleControllerCustom.h ├── StdAfx.cpp ├── StdAfx.h ├── convert.h ├── miscmath.cpp ├── miscmath.h ├── phydata.h ├── premake4.lua ├── resource.h └── vphysics.rc ├── vphysics.sln ├── vphysics.vcxproj └── vphysics.vcxproj.filters /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: dyanikoglu 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.ipch 2 | *.ncb 3 | *.sdf 4 | *.opensdf 5 | *.suo 6 | *.user 7 | *.exe 8 | *.dll 9 | *.exp 10 | *.ilk 11 | *.lib 12 | *.pdb 13 | *.aps 14 | *.o 15 | *.d 16 | 17 | *.cproject 18 | *.project 19 | 20 | /build 21 | /ipch 22 | proj/gmake 23 | proj/vs2010 24 | .vs/* -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "qhull"] 2 | path = thirdparty/qhull 3 | url = https://github.com/manctl/qhull.git 4 | [submodule "sourcesdk"] 5 | path = thirdparty/sourcesdk 6 | url = https://github.com/ValveSoftware/source-sdk-2013.git 7 | [submodule "thirdparty/bullet3"] 8 | path = thirdparty/bullet3 9 | url = https://github.com/dyanikoglu/bullet3.git 10 | [submodule "thirdparty/tbb"] 11 | path = thirdparty/tbb 12 | url = https://github.com/dyanikoglu/tbb-prebuilt.git 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Doğa Can Yanıkoğlu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # source-sdk-bullet-physics 2 | Experimental Bullet Physics Injection for Source SDK 2013. 3 | 4 | ![image](https://i.ibb.co/nkcRSLg/download.gif) 5 | 6 | ## About 7 | The repository is based on https://github.com/DrChat/Gmod-vphysics. It's not forked because of that one having whole Bullet SDK pushed into same repository, to keep my repository crisp & clear. Major changes on this implementation are: 8 | 9 | - Updated version of Bullet SDK. The base repository had an ancient version of Bullet with lots of deprecated stuff being used. 10 | - Utilization of new multithreaded modules of Bullet SDK 11 | - Lots of performance improvements 12 | 13 | Demonstration recordings can be found on: 14 | - https://www.youtube.com/watch?v=6CH1BSyM92A 15 | - https://www.youtube.com/watch?v=kMz_1qonMqs 16 | 17 | ## Building Vphysics.dll for Source SDK 2013 18 | - Checkout submodules inside thirdparty folder 19 | - Follow the instructions on bullet3 repository to build Bullet libs & binaries 20 | - Open vphysics solution and build the project 21 | - Place generated vphysics.dll binary into desired Source SDK 2013 based game (Half-Life 2, GMod etc.), or into your custom built Source SDK 2013 game. 22 | 23 | ## Known Issues 24 | - Save/Load functionality doesn't work, and mostly crashes the game. You should disable physics restore functionality on save/load module of Source SDK 2013 to fix this issue. 25 | - Small objects with very high speed (Thrown grenades for example) may pass through landscape mesh. Also, big objects with very high speed may have a tunnelling effect while colliding with landscape meshes. That's mostly an issue with Bullet's messed up convex mesh collision algorithm, and it's not likely to be solved because of core part of the physics engine being abandoned on development. 26 | - Impact damage is not implemented. Because of Bullet's lack of a proper callback system for hit/impact/collision events, it requires huge amount of effort while using multithreaded modules of Bullet. 27 | - Physics impact sounds are broken, again, it will probably require huge amount of effort to be fixed. 28 | - The implementation is highly experimental, it's not recommended to use it with production purposes. 29 | 30 | ## License 31 | ``` 32 | MIT License 33 | 34 | Copyright (c) 2020 Doğa Can Yanıkoğlu 35 | 36 | Permission is hereby granted, free of charge, to any person obtaining a copy 37 | of this software and associated documentation files (the "Software"), to deal 38 | in the Software without restriction, including without limitation the rights 39 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 40 | copies of the Software, and to permit persons to whom the Software is 41 | furnished to do so, subject to the following conditions: 42 | 43 | The above copyright notice and this permission notice shall be included in all 44 | copies or substantial portions of the Software. 45 | 46 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 47 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 48 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 49 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 50 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 51 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 52 | SOFTWARE. 53 | ``` 54 | ## Contribution 55 | Source code is licensed under MIT license, and other developers are encouraged to fork the repository, open issues & pull requests to help the development. 56 | -------------------------------------------------------------------------------- /include/vphysics/constraintsV32.h: -------------------------------------------------------------------------------- 1 | #ifndef CONSTRAINTSV32_H 2 | #define CONSTRAINTSV32_h 3 | #ifdef _MSC_VER 4 | #pragma once 5 | #endif 6 | 7 | #include "vphysics/constraints.h" 8 | 9 | struct physconstraintinfo_t { 10 | int numConstraintRows; // Amount of constraint rows 11 | int nub; // Unknown. Usually 6 - numConstraintRows. Appears unused in bullet. 12 | }; 13 | 14 | struct physconstraintsolveinfo_t { 15 | Vector J1linearAxis, J1angularAxis; // Linear axis to solve on (normalized), Angular axis is rel pos cross normal. 16 | Vector J2linearAxis, J2angularAxis; // Same as above for 2nd rigid body, may be NULL if there is no 2nd rigid body. 17 | 18 | // Right hand sides of the equation (J*v = c + cfm * lambda) 19 | // FIXME: Not converted to/from HL units! 20 | float constraintError, cfm; 21 | 22 | // TODO: Description 23 | // FIXME: Not converted to/from HL units! 24 | float lowerLimit, upperLimit; 25 | 26 | inline void Defaults() { 27 | J1linearAxis.Zero(); 28 | J1angularAxis.Zero(); 29 | J2linearAxis.Zero(); 30 | J2angularAxis.Zero(); 31 | 32 | constraintError = 0; 33 | cfm = 0; 34 | 35 | lowerLimit = -FLT_MAX; 36 | upperLimit = FLT_MAX; 37 | } 38 | }; 39 | 40 | class IPhysicsUserConstraint { 41 | public: 42 | virtual ~IPhysicsUserConstraint() {} 43 | 44 | // Optional function. Called when a constraint is destroyed that was attached to this constraint. 45 | // No other functions on this user constraint will be called afterwards from that constraint. 46 | virtual void ConstraintDestroyed(IPhysicsConstraint *pConstraint) {} 47 | 48 | // WARNING: The following functions may not be called on the main thread! Do not do any non-threadsafe operations here! 49 | 50 | // Basic constraint info for internal setup 51 | virtual void GetConstraintInfo(IPhysicsObject32 *pObjA, IPhysicsObject32 *pObjB, physconstraintinfo_t &info) = 0; 52 | 53 | // Info for constraint solve (an array of size numRows) 54 | // FPS - frames per second (1/stepsize), erp - default error reduction parameter (0..1) 55 | virtual void GetConstraintSolveInfo(IPhysicsObject32 *pObjA, IPhysicsObject32 *pObjB, physconstraintsolveinfo_t *info, int numRows, float fps, float erp) = 0; 56 | }; 57 | 58 | struct constraint_gearparams_t { 59 | constraint_breakableparams_t constraint; // TODO: Will be supported in the future 60 | Vector objectLocalAxes[2]; // Local axis in objects 61 | float ratio; // Gear ratio 62 | 63 | inline void Defaults() { 64 | constraint.Defaults(); 65 | objectLocalAxes[0].Init(); 66 | objectLocalAxes[1].Init(); 67 | ratio = 1; 68 | } 69 | }; 70 | 71 | #endif // CONSTRAINTSV32_h -------------------------------------------------------------------------------- /include/vphysics/softbodyV32.h: -------------------------------------------------------------------------------- 1 | #ifndef SOFTBODYV32_H 2 | #define SOFTBODYV32_H 3 | #ifdef _MSC_VER 4 | #pragma once 5 | #endif 6 | 7 | struct softbodynode_t { 8 | Vector pos, vel; 9 | float invMass; 10 | }; 11 | 12 | struct softbodyface_t { 13 | int nodeIndexes[3]; // Node indexes that can be passed into the node functions 14 | softbodynode_t nodes[3]; 15 | Vector normal; 16 | }; 17 | 18 | struct softbodylink_t { 19 | int nodeIndexes[2]; // Node indexes that can be passed into the node functions 20 | softbodynode_t nodes[2]; 21 | }; 22 | 23 | struct softbodyparams_t { 24 | float totalMass; 25 | }; 26 | 27 | class IPhysicsSoftBody { 28 | public: 29 | virtual ~IPhysicsSoftBody() {} 30 | 31 | virtual void SetTotalMass(float fMass, bool bFromFaces = false) = 0; 32 | virtual void Anchor(int node, IPhysicsObject *pObj) = 0; 33 | 34 | virtual int GetNodeCount() const = 0; 35 | virtual int GetFaceCount() const = 0; 36 | virtual int GetLinkCount() const = 0; 37 | 38 | virtual softbodynode_t GetNode(int i) const = 0; 39 | virtual softbodyface_t GetFace(int i) const = 0; 40 | virtual softbodylink_t GetLink(int i) const = 0; 41 | 42 | // Get soft body AABB (cannot be implemented in collision interface because soft bodies change shape) 43 | virtual void GetAABB(Vector *mins, Vector *maxs) const = 0; 44 | virtual void RayTest(Ray_t &ray, trace_t *pTrace) const = 0; 45 | 46 | virtual void Transform(const matrix3x4_t &mat) = 0; 47 | virtual void Transform(const Vector *vec, const QAngle *ang) = 0; 48 | virtual void Scale(const Vector &scale) = 0; // Scales a softbody. Do this before it's moved from the origin, or bad things will happen! 49 | 50 | virtual IPhysicsEnvironment32 *GetPhysicsEnvironment() const = 0; 51 | }; 52 | 53 | #endif // SOFTBODYV32_H -------------------------------------------------------------------------------- /include/vphysics/vehiclesV32.h: -------------------------------------------------------------------------------- 1 | #ifndef VEHICLESV32_H 2 | #define VEHICLESV32_h 3 | #ifdef _MSC_VER 4 | #pragma once 5 | #endif 6 | 7 | #include "vphysics/vehicles.h" 8 | 9 | // THIS INTERFACE IS NOT FINALIZED! FUNCTIONS MAY CHANGE! 10 | 11 | class IPhysicsVehicleController32 : public IPhysicsVehicleController { 12 | public: 13 | // force in kg*in/s 14 | virtual void SetWheelForce(int wheelIndex, float force) = 0; 15 | virtual void SetWheelBrake(int wheelIndex, float brakeVal) = 0; 16 | // steerVal is in degrees! 17 | virtual void SetWheelSteering(int wheelIndex, float steerVal) = 0; 18 | }; 19 | 20 | #endif // VEHICLESV32_H -------------------------------------------------------------------------------- /include/vphysics_interfaceV32.h: -------------------------------------------------------------------------------- 1 | #ifndef VPHYSICS_INTERFACEV32_H 2 | #define VPHYSICS_INTERFACEV32_H 3 | 4 | #ifdef _MSC_VER 5 | #pragma once 6 | #endif 7 | 8 | #include "tier1/interface.h" 9 | #include "vphysics_interface.h" 10 | 11 | // Purpose: Updated interface to vphysics.dll 12 | // This interface MUST be ADDITIVE ONLY. DO NOT change old function signatures. 13 | // To use this new interface, typecast the old interfaces to the newer ones 14 | // ex. IPhysics32 *newPhysics = (IPhysics32 *)oldPhysics; 15 | 16 | // THIS INTERFACE IS NOT FINALIZED! FUNCTIONS MAY CHANGE! 17 | 18 | class IPhysicsSoftBody; 19 | class IPhysicsConstraint; 20 | class IPhysicsConstraintGroup; 21 | class IPhysicsUserConstraint; 22 | class IPhysicsVehicleController; 23 | 24 | struct softbodyparams_t; 25 | struct constraint_gearparams_t; 26 | 27 | abstract_class IPhysics32 : public IPhysics { 28 | public: 29 | virtual int GetActiveEnvironmentCount() = 0; 30 | }; 31 | 32 | abstract_class IPhysicsEnvironment32 : public IPhysicsEnvironment { 33 | public: 34 | #if 0 35 | // Create a convex soft body from vertices. Vertices are in world space! 36 | virtual IPhysicsSoftBody * CreateSoftBodyFromVertices(const Vector *vertices, int numVertices, const softbodyparams_t *pParams) = 0; 37 | // Resolution is the amount of nodes in the rope. Higher number means less passthrough and a finer rope. 38 | virtual IPhysicsSoftBody * CreateSoftBodyRope(const Vector &start, const Vector &end, int resolution, const softbodyparams_t *pParams) = 0; 39 | virtual IPhysicsSoftBody * CreateSoftBodyPatch(const Vector *corners, int resx, int resy, const softbodyparams_t *pParams) = 0; 40 | virtual void DestroySoftBody(IPhysicsSoftBody *pSoftBody) = 0; 41 | #endif 42 | // Constraint group is not required (can be NULL) 43 | virtual IPhysicsConstraint *CreateGearConstraint(IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_gearparams_t &gear) = 0; 44 | virtual IPhysicsConstraint *CreateUserConstraint(IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, IPhysicsUserConstraint *pConstraint) = 0; 45 | 46 | virtual void SweepConvex(const CPhysConvex *pConvex, const Vector &vecAbsStart, const Vector &vecAbsEnd, const QAngle &vecAngles, unsigned int fMask, IPhysicsTraceFilter *pTraceFilter, trace_t *pTrace) = 0; 47 | 48 | virtual int GetObjectCount() const = 0; 49 | }; 50 | 51 | abstract_class IPhysicsObject32 : public IPhysicsObject { 52 | public: 53 | // You need to call EnableGravity(false) first so we stop using the environment's gravity. 54 | // To use the environment's gravity again, call EnableGravity(true) 55 | // (Yes I know it's confusing, nothing I can do about it without breaking backwards compatability) 56 | // This will allow you to override the gravity force acted upon the object. 57 | virtual void SetLocalGravity(const Vector &gravityVector) = 0; 58 | virtual Vector GetLocalGravity() const = 0; 59 | 60 | // Purpose: Set/Get the speeds at which any object is travelling slower than will fall asleep. 61 | // linear velocity is in in/s and angular velocity is in degrees/s 62 | // Parameters are optional in both functions. 63 | virtual void SetSleepThresholds(const float *linVel, const float *angVel) = 0; 64 | virtual void GetSleepThresholds(float *linVel, float *angVel) const = 0; 65 | 66 | // Get a modifiable version of the collision mesh we're using. If you change it at all, remember to call UpdateCollide() 67 | virtual CPhysCollide * GetCollide() = 0; 68 | // Set the collision model of an object. You don't need to call UpdateCollide after this. 69 | virtual void SetCollide(CPhysCollide *pCollide) = 0; 70 | 71 | // Call this if you have recently changed the collision shape we're using. 72 | virtual void UpdateCollide() = 0; 73 | 74 | virtual IPhysicsEnvironment32 *GetEnvironment() const = 0; 75 | 76 | virtual IPhysicsVehicleController *GetVehicleController() const = 0; 77 | }; 78 | 79 | // Note: If you change anything about a collision shape that an IPhysicsObject is using, call UpdateCollide on that object. 80 | 81 | abstract_class IPhysicsCollision32 : public IPhysicsCollision { 82 | public: 83 | // Adds a convex to a collide, with an optional transform to offset the convex. 84 | virtual void AddConvexToCollide(CPhysCollide *pCollide, const CPhysConvex *pConvex, const matrix3x4_t *xform = NULL) = 0; 85 | virtual void RemoveConvexFromCollide(CPhysCollide *pCollide, const CPhysConvex *pConvex) = 0; 86 | 87 | // This will scale a collide 88 | virtual void CollideSetScale(CPhysCollide *pCollide, const Vector &scale) = 0; 89 | virtual void CollideGetScale(const CPhysCollide *pCollide, Vector &scale) = 0; 90 | 91 | // API to disable old vphysics behavior for bboxes 92 | // (holds all bboxes in a cache, and it'll either give you one already created or create a new one) 93 | // The bbox cache doesn't provide any speed boost like it does in the old vphysics 94 | virtual void EnableBBoxCache(bool enable) = 0; 95 | virtual bool IsBBoxCacheEnabled() = 0; 96 | 97 | // New collision shapes 98 | // NOTE: VPhysics DOES NOT keep track of these, unlike BBoxes! You must destroy them with DestroyCollide! 99 | 100 | virtual CPhysConvex * CylinderToConvex(const Vector &mins, const Vector &maxs) = 0; 101 | virtual CPhysConvex * ConeToConvex(const float radius, const float height) = 0; 102 | virtual CPhysConvex * SphereToConvex(const float radius) = 0; 103 | }; 104 | 105 | #endif // VPHYSICS_INTERFACEV32_H -------------------------------------------------------------------------------- /src/DebugDrawer.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include "Physics_Environment.h" 8 | #include "DebugDrawer.h" 9 | #include "convert.h" 10 | 11 | #ifdef DEBUGDRAW_RENDER_SDL 12 | #include 13 | #include 14 | #endif // DEBUGDRAW_RENDER_SDL 15 | 16 | // memdbgon must be the last include file in a .cpp file!!! 17 | #include "tier0/memdbgon.h" 18 | 19 | #if DEBUG_DRAW 20 | 21 | // BUG: Debug draw causes memory leak in the server 22 | 23 | static ConVar cvar_renderoverlay("vphysics_renderoverlay", "0", FCVAR_CHEAT | FCVAR_ARCHIVE, "Render debug overlay"); 24 | static ConVar cvar_overlaywireframe("vphysics_overlay_wireframe", "0", FCVAR_CHEAT, "Render wireframe on the overlay (lags on most maps!)"); 25 | static ConVar cvar_overlaydepthtest("vphysics_overlay_nodepthtest", "0", FCVAR_CHEAT | FCVAR_ARCHIVE, "No depth test when rendering the overlay"); 26 | 27 | CDebugDrawer::CDebugDrawer(btCollisionWorld *world) : m_debugMode(0), m_overlay(NULL) { 28 | setDebugMode(/*DBG_DrawAabb |*/ DBG_DrawConstraintLimits | DBG_DrawConstraints | DBG_DrawContactPoints | 29 | DBG_DrawNormals); 30 | 31 | #ifdef DEBUGDRAW_RENDER_SDL 32 | m_pDisplay = NULL; 33 | 34 | SDL_Init(SDL_INIT_VIDEO); 35 | SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); 36 | SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); 37 | SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); 38 | SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); 39 | SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 40 | m_pDisplay = SDL_SetVideoMode(640, 480, 32, SDL_OPENGL); 41 | 42 | glShadeModel(GL_SMOOTH); 43 | glEnable(GL_DEPTH_TEST); 44 | glDepthFunc(GL_LESS); 45 | 46 | glClearColor(0, 0, 0, 0); 47 | glViewport(0, 0, 640, 480); 48 | glMatrixMode(GL_PROJECTION); 49 | glLoadIdentity(); 50 | glFrustum(-1, 1, -1, 1, 1, 10000); 51 | glMatrixMode(GL_MODELVIEW); 52 | glLoadIdentity(); 53 | gluLookAt(0, 17, -60, 0, 0, 0, 0, 1, 0); 54 | #endif 55 | 56 | m_world = world; 57 | m_world->setDebugDrawer(this); 58 | 59 | #ifndef BT_NO_PROFILE 60 | // m_pProfIterator = CProfileManager::Get_Iterator(); 61 | #endif 62 | } 63 | 64 | CDebugDrawer::~CDebugDrawer() { 65 | m_world->setDebugDrawer(NULL); 66 | #ifndef BT_NO_PROFILE 67 | // CProfileManager::Release_Iterator(m_pProfIterator); 68 | #endif 69 | 70 | #ifdef DEBUGDRAW_RENDER_SDL 71 | SDL_FreeSurface(m_pDisplay); 72 | SDL_Quit(); 73 | #endif 74 | } 75 | 76 | void CDebugDrawer::drawLine(const btVector3 &from, const btVector3 &to, const btVector3 &fromColor, const btVector3 &toColor) { 77 | #ifdef DEBUGDRAW_RENDER_SDL 78 | glBegin(GL_LINES); 79 | glColor3f(fromColor.getX(), fromColor.getY(), fromColor.getZ()); 80 | glVertex3d(from.getX(), from.getY(), from.getZ()); 81 | glColor3f(toColor.getX(), toColor.getY(), toColor.getZ()); 82 | glVertex3d(to.getX(), to.getY(), to.getZ()); 83 | glEnd(); 84 | #else 85 | Vector HLFrom; 86 | Vector HLTo; 87 | ConvertPosToHL(from, HLFrom); 88 | ConvertPosToHL(to, HLTo); 89 | 90 | m_overlay->AddLineOverlay(HLFrom, HLTo, fromColor.x() * 255, fromColor.y() * 255, fromColor.z() * 255, cvar_overlaydepthtest.GetBool(), 0); 91 | #endif 92 | } 93 | 94 | void CDebugDrawer::drawLine(const btVector3 &from, const btVector3 &to, const btVector3 &color) { 95 | drawLine(from, to, color, color); 96 | } 97 | 98 | #ifdef DEBUGDRAW_RENDER_SDL 99 | void CDebugDrawer::drawSphere(const btVector3 &p, btScalar radius, const btVector3 &color) { 100 | glColor4f (color.getX(), color.getY(), color.getZ(), btScalar(1.0f)); 101 | glPushMatrix (); 102 | glTranslatef (p.getX(), p.getY(), p.getZ()); 103 | 104 | int lats = 5; 105 | int longs = 5; 106 | 107 | int i, j; 108 | for(i = 0; i <= lats; i++) { 109 | btScalar lat0 = SIMD_PI * (-btScalar(0.5) + (btScalar) (i - 1) / lats); 110 | btScalar z0 = radius*sin(lat0); 111 | btScalar zr0 = radius*cos(lat0); 112 | 113 | btScalar lat1 = SIMD_PI * (-btScalar(0.5) + (btScalar) i / lats); 114 | btScalar z1 = radius*sin(lat1); 115 | btScalar zr1 = radius*cos(lat1); 116 | 117 | glBegin(GL_QUAD_STRIP); 118 | for(j = 0; j <= longs; j++) { 119 | btScalar lng = 2 * SIMD_PI * (btScalar) (j - 1) / longs; 120 | btScalar x = cos(lng); 121 | btScalar y = sin(lng); 122 | 123 | glNormal3f(x * zr0, y * zr0, z0); 124 | glVertex3f(x * zr0, y * zr0, z0); 125 | glNormal3f(x * zr1, y * zr1, z1); 126 | glVertex3f(x * zr1, y * zr1, z1); 127 | } 128 | glEnd(); 129 | } 130 | 131 | glPopMatrix(); 132 | } 133 | #endif 134 | 135 | void CDebugDrawer::drawBox(const btVector3 &boxMin, const btVector3 &boxMax, const btVector3 &color, btScalar alpha) { 136 | #ifdef DEBUGDRAW_RENDER_SDL 137 | btVector3 halfExtent = (boxMax - boxMin) * btScalar(0.5f); 138 | btVector3 center = (boxMax + boxMin) * btScalar(0.5f); 139 | //glEnable(GL_BLEND); // Turn blending On 140 | //glBlendFunc(GL_SRC_ALPHA, GL_ONE); 141 | glColor4f (color.getX(), color.getY(), color.getZ(), alpha); 142 | glPushMatrix (); 143 | glTranslatef (center.getX(), center.getY(), center.getZ()); 144 | glScaled(2*halfExtent[0], 2*halfExtent[1], 2*halfExtent[2]); 145 | glPopMatrix (); 146 | //glDisable(GL_BLEND); 147 | #else 148 | Vector HLBoxMin; 149 | Vector HLBoxMax; 150 | ConvertPosToHL(boxMin, HLBoxMin); 151 | ConvertPosToHL(boxMax, HLBoxMax); 152 | #endif 153 | } 154 | 155 | void CDebugDrawer::drawTriangle(const btVector3 &a, const btVector3 &b, const btVector3 &c, const btVector3 &color, btScalar alpha) { 156 | #ifdef DEBUGDRAW_RENDER_SDL 157 | const btVector3 n=btCross(b-a, c-a).normalized(); 158 | glBegin(GL_TRIANGLES); 159 | glColor4f(color.getX(), color.getY(), color.getZ(), alpha); 160 | glNormal3d(n.getX(), n.getY(), n.getZ()); 161 | glVertex3d(a.getX(), a.getY(), a.getZ()); 162 | glVertex3d(b.getX(), b.getY(), b.getZ()); 163 | glVertex3d(c.getX(), c.getY(), c.getZ()); 164 | glEnd(); 165 | #else 166 | Vector HLA; 167 | Vector HLB; 168 | Vector HLC; 169 | ConvertPosToHL(a, HLA); 170 | ConvertPosToHL(b, HLB); 171 | ConvertPosToHL(c, HLC); 172 | m_overlay->AddTriangleOverlay(HLA, HLB, HLC, color.x() * 255, color.y() * 255, color.z() * 255, alpha * 255, cvar_overlaydepthtest.GetBool(), 0); 173 | #endif 174 | } 175 | 176 | void CDebugDrawer::setDebugMode(int debugMode) { 177 | m_debugMode = debugMode; 178 | } 179 | 180 | void CDebugDrawer::draw3dText(const btVector3 &location, const char *textString) { 181 | #ifdef DEBUGDRAW_RENDER_SDL 182 | glRasterPos3f(location.x(), location.y(), location.z()); 183 | #else 184 | Vector HLLocation; 185 | ConvertPosToHL(location, HLLocation); 186 | 187 | m_overlay->AddTextOverlay(HLLocation, 0, textString); 188 | #endif 189 | } 190 | 191 | void CDebugDrawer::reportErrorWarning(const char *warningString) { 192 | Warning(warningString); 193 | } 194 | 195 | void CDebugDrawer::drawContactPoint(const btVector3 &pointOnB, const btVector3 &normalOnB, btScalar distance, int lifeTime, const btVector3 &color) { 196 | btVector3 to = pointOnB + normalOnB * (distance + 0.2); //pointOnB + normalOnB * 1; 197 | const btVector3 &from = pointOnB; 198 | #ifdef DEBUGDRAW_RENDER_SDL 199 | glColor4f(color.getX(), color.getY(), color.getZ(),1.f); 200 | glBegin(GL_LINES); 201 | glVertex3d(from.getX(), from.getY(), from.getZ()); 202 | glVertex3d(to.getX(), to.getY(), to.getZ()); 203 | glEnd(); 204 | #else 205 | drawLine(from, to, color); 206 | #endif 207 | } 208 | 209 | void CDebugDrawer::SetDebugOverlay(IVPhysicsDebugOverlay *pOverlay) { 210 | m_overlay = pOverlay; 211 | } 212 | 213 | IVPhysicsDebugOverlay *CDebugDrawer::GetDebugOverlay() { 214 | return m_overlay; 215 | } 216 | 217 | void CDebugDrawer::DrawWorld() { 218 | #ifdef DEBUGDRAW_RENDER_SDL 219 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 220 | setDebugMode(DBG_DrawWireframe); 221 | m_world->debugDrawWorld(); 222 | glFlush(); 223 | SDL_GL_SwapBuffers(); 224 | #else 225 | if (cvar_renderoverlay.GetBool()) { 226 | // Shit fuck I don't care, it works 227 | cvar_overlaywireframe.GetBool() ? setDebugMode(getDebugMode() | DBG_DrawWireframe) : setDebugMode(getDebugMode() & ~(DBG_DrawWireframe)); 228 | if (m_overlay) { 229 | m_world->debugDrawWorld(); 230 | } 231 | } 232 | #endif 233 | } 234 | 235 | #endif // DEBUG_DRAW 236 | -------------------------------------------------------------------------------- /src/DebugDrawer.h: -------------------------------------------------------------------------------- 1 | #ifndef GL_DEBUG_DRAWER_H 2 | #define GL_DEBUG_DRAWER_H 3 | 4 | #include 5 | 6 | //#define DEBUGDRAW_RENDER_SDL 7 | 8 | class CPhysicsEnvironment; 9 | struct SDL_Surface; 10 | 11 | class CProfileIterator; 12 | 13 | class CDebugDrawer : public btIDebugDraw { 14 | public: 15 | CDebugDrawer(btCollisionWorld *world); 16 | virtual ~CDebugDrawer(); 17 | 18 | virtual void drawLine(const btVector3 &from, const btVector3 &to, const btVector3 &fromColor, const btVector3 &toColor); 19 | virtual void drawLine(const btVector3 &from, const btVector3 &to, const btVector3 &color); 20 | 21 | #ifdef DEBUGDRAW_RENDER_SDL 22 | virtual void drawSphere(const btVector3 &p, btScalar radius, const btVector3 &color); 23 | #endif 24 | virtual void drawBox(const btVector3 &boxMin, const btVector3 &boxMax, const btVector3 &color, btScalar alpha); 25 | virtual void drawTriangle(const btVector3 &a, const btVector3 &b, const btVector3 &c, const btVector3 &color, btScalar alpha); 26 | virtual void drawContactPoint(const btVector3 &PointOnB, const btVector3 &normalOnB, btScalar distance, int lifeTime, const btVector3 &color); 27 | virtual void reportErrorWarning(const char *warningString); 28 | virtual void draw3dText(const btVector3 &location, const char *textString); 29 | virtual void setDebugMode(int debugMode); 30 | virtual int getDebugMode() const { return m_debugMode; } 31 | 32 | void SetDebugOverlay(IVPhysicsDebugOverlay *pOverlay); 33 | IVPhysicsDebugOverlay * GetDebugOverlay(); 34 | void DrawWorld(); 35 | 36 | private: 37 | int m_debugMode; 38 | btCollisionWorld * m_world; 39 | // CProfileIterator * m_pProfIterator; 40 | 41 | #ifdef DEBUGDRAW_RENDER_SDL 42 | SDL_Surface * m_pDisplay; 43 | #endif 44 | 45 | IVPhysicsDebugOverlay * m_overlay; 46 | }; 47 | 48 | #endif//GL_DEBUG_DRAWER_H 49 | -------------------------------------------------------------------------------- /src/IController.h: -------------------------------------------------------------------------------- 1 | #ifndef ICONTROLLER_H 2 | #define ICONTROLLER_H 3 | 4 | class CPhysicsObject; 5 | 6 | class IController { 7 | public: 8 | // Bullet tick, called post-simulation 9 | virtual void Tick(float deltaTime) = 0; 10 | }; 11 | 12 | #endif // ICONTROLLER_H 13 | -------------------------------------------------------------------------------- /src/Physics.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | 3 | #include 4 | 5 | #include "Physics.h" 6 | #include "Physics_Environment.h" 7 | #include "Physics_ObjectPairHash.h" 8 | #include "Physics_CollisionSet.h" 9 | 10 | // memdbgon must be the last include file in a .cpp file!!! 11 | #include "tier0/memdbgon.h" 12 | 13 | ConVar vphysics_bulletdebugoutput("vphysics_bulletdebugoutput", "0", FCVAR_ARCHIVE); 14 | 15 | void btDebugMessage(const char *str) { 16 | if (vphysics_bulletdebugoutput.GetBool()) { 17 | Msg("%s", str); 18 | } 19 | } 20 | 21 | void btDebugWarning(const char *str) { 22 | Warning("%s", str); 23 | } 24 | 25 | /****************** 26 | * CLASS CPhysics 27 | ******************/ 28 | CPhysics::~CPhysics() { 29 | #if defined(_DEBUG) && defined(_MSC_VER) 30 | // Probably not the place we should be doing this, but who cares. 31 | // This'll be called when vphysics is unloaded, and since we're (most likely) the only module with 32 | // memory debugging enabled, memory leaks should only correspond to our code. 33 | // Also convars "leak" 2 bytes of memory because this is being called before it should 34 | _CrtDumpMemoryLeaks(); 35 | #endif 36 | } 37 | 38 | InitReturnVal_t CPhysics::Init() { 39 | const InitReturnVal_t nRetVal = BaseClass::Init(); 40 | if (nRetVal != INIT_OK) return nRetVal; 41 | 42 | // Hook up our debug output functions 43 | btSetDbgMsgFn(btDebugMessage); 44 | btSetDbgWarnFn(btDebugWarning); 45 | 46 | return INIT_OK; 47 | } 48 | 49 | void CPhysics::Shutdown() { 50 | BaseClass::Shutdown(); 51 | } 52 | 53 | void *CPhysics::QueryInterface(const char *pInterfaceName) { 54 | const CreateInterfaceFn func = Sys_GetFactoryThis(); 55 | if (!func) 56 | return NULL; 57 | 58 | return func(pInterfaceName, NULL); 59 | } 60 | 61 | IPhysicsEnvironment *CPhysics::CreateEnvironment() { 62 | IPhysicsEnvironment *pEnvironment = new CPhysicsEnvironment; 63 | m_envList.AddToTail(pEnvironment); 64 | return pEnvironment; 65 | } 66 | 67 | void CPhysics::DestroyEnvironment(IPhysicsEnvironment *pEnvironment) { 68 | m_envList.FindAndRemove(pEnvironment); 69 | delete dynamic_cast(pEnvironment); 70 | } 71 | 72 | IPhysicsEnvironment *CPhysics::GetActiveEnvironmentByIndex(int index) { 73 | if (index < 0 || index >= m_envList.Count()) return NULL; 74 | return m_envList[index]; 75 | } 76 | 77 | int CPhysics::GetActiveEnvironmentCount() { 78 | return m_envList.Count(); 79 | } 80 | 81 | IPhysicsObjectPairHash *CPhysics::CreateObjectPairHash() { 82 | return new CPhysicsObjectPairHash(); 83 | } 84 | 85 | void CPhysics::DestroyObjectPairHash(IPhysicsObjectPairHash *pHash) { 86 | delete dynamic_cast(pHash); 87 | } 88 | 89 | IPhysicsCollisionSet *CPhysics::FindOrCreateCollisionSet(unsigned int id, int maxElementCount) { 90 | if (m_colSetTable.Find(id) != m_colSetTable.InvalidHandle()) 91 | return m_collisionSets[m_colSetTable.Element(m_colSetTable.Find(id))]; 92 | 93 | CPhysicsCollisionSet *set = NULL; 94 | if (maxElementCount < static_cast(sizeof(int)) * 8) { // Limit of 32 because of the way this works internally 95 | set = ::CreateCollisionSet(maxElementCount); 96 | const int vecId = m_collisionSets.AddToTail(set); 97 | 98 | m_colSetTable.Insert(id, vecId); 99 | } 100 | 101 | return set; 102 | } 103 | 104 | IPhysicsCollisionSet *CPhysics::FindCollisionSet(unsigned int id) { 105 | if (m_colSetTable.Find(id) != m_colSetTable.InvalidHandle()) 106 | return m_collisionSets[m_colSetTable.Element(m_colSetTable.Find(id))]; 107 | 108 | return NULL; 109 | } 110 | 111 | void CPhysics::DestroyAllCollisionSets() { 112 | for (int i = 0; i < m_collisionSets.Count(); i++) 113 | delete dynamic_cast(m_collisionSets[i]); 114 | 115 | m_collisionSets.RemoveAll(); 116 | m_colSetTable.RemoveAll(); 117 | } 118 | 119 | CPhysics g_Physics; 120 | EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CPhysics, IPhysics, VPHYSICS_INTERFACE_VERSION, g_Physics); 121 | EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CPhysics, IPhysics32, "VPhysics032", g_Physics); // "Undocumented" way to determine if this is the newer vphysics or not. 122 | -------------------------------------------------------------------------------- /src/Physics.h: -------------------------------------------------------------------------------- 1 | #ifndef PHYSICS_H 2 | #define PHYSICS_H 3 | #if defined(_MSC_VER) || (defined(__GNUC__) && __GNUC__ > 3) 4 | #pragma once 5 | #endif 6 | 7 | #include 8 | 9 | class IPhysicsEnvironment; 10 | class IPhysicsCollisionSet; 11 | 12 | class CPhysics : public CTier1AppSystem { 13 | typedef CTier1AppSystem BaseClass; 14 | public: 15 | ~CPhysics(); 16 | 17 | void * QueryInterface(const char *pInterfaceName); 18 | InitReturnVal_t Init(); 19 | void Shutdown(); 20 | 21 | IPhysicsEnvironment * CreateEnvironment(); 22 | void DestroyEnvironment(IPhysicsEnvironment *pEnv); 23 | IPhysicsEnvironment * GetActiveEnvironmentByIndex(int index); 24 | int GetActiveEnvironmentCount(); 25 | 26 | IPhysicsObjectPairHash * CreateObjectPairHash(); 27 | void DestroyObjectPairHash(IPhysicsObjectPairHash *pHash); 28 | 29 | IPhysicsCollisionSet * FindOrCreateCollisionSet(unsigned int id, int maxElementCount); 30 | IPhysicsCollisionSet * FindCollisionSet(unsigned int id); 31 | void DestroyAllCollisionSets(); 32 | private: 33 | CUtlVector m_envList; 34 | CUtlVector m_collisionSets; 35 | CUtlHashtable m_colSetTable; 36 | }; 37 | 38 | extern CPhysics g_Physics; 39 | 40 | #endif -------------------------------------------------------------------------------- /src/Physics_Collision.h: -------------------------------------------------------------------------------- 1 | #ifndef PHYSICS_COLLISION_H 2 | #define PHYSICS_COLLISION_H 3 | #if defined(_MSC_VER) || (defined(__GNUC__) && __GNUC__ > 3) 4 | #pragma once 5 | #endif 6 | 7 | // NOTE: There can only be up to 16 unique collision groups (data type of short)! 8 | enum ECollisionGroups { 9 | COLGROUP_NONE = 0, 10 | COLGROUP_WORLD = 1<<1, 11 | }; 12 | 13 | // Because the old vphysics had to do this. 14 | struct bboxcache_t { 15 | CPhysCollide * pCollide; 16 | Vector mins, maxs; 17 | }; 18 | 19 | class CPhysCollide { 20 | public: 21 | CPhysCollide(btCollisionShape *pShape); 22 | 23 | const btCollisionShape *GetCollisionShape() const { 24 | return m_pShape; 25 | } 26 | 27 | btCollisionShape *GetCollisionShape() { 28 | return m_pShape; 29 | } 30 | 31 | const btCompoundShape *GetCompoundShape() const { 32 | Assert(IsCompound()); 33 | if (!IsCompound()) 34 | return NULL; 35 | 36 | return (btCompoundShape *)m_pShape; 37 | } 38 | 39 | btCompoundShape *GetCompoundShape() { 40 | Assert(IsCompound()); 41 | if (!IsCompound()) 42 | return NULL; 43 | 44 | return (btCompoundShape *)m_pShape; 45 | } 46 | 47 | const btConvexShape *GetConvexShape() const { 48 | Assert(IsConvex()); 49 | if (!IsConvex()) 50 | return NULL; 51 | 52 | return (btConvexShape *)m_pShape; 53 | } 54 | 55 | btConvexShape *GetConvexShape() { 56 | Assert(IsConvex()); 57 | if (!IsConvex()) 58 | return NULL; 59 | 60 | return (btConvexShape *)m_pShape; 61 | } 62 | 63 | void SetRotationInertia(const btVector3 &inertia) { 64 | m_rotInertia = inertia; 65 | } 66 | 67 | btVector3 &GetRotationInertia() { 68 | return m_rotInertia; 69 | } 70 | 71 | const btVector3 &GetRotationInertia() const { 72 | return m_rotInertia; 73 | } 74 | 75 | void SetMassCenter(const btVector3 ¢er) { 76 | m_massCenter = center; 77 | } 78 | 79 | btVector3 &GetMassCenter() { 80 | return m_massCenter; 81 | } 82 | 83 | const btVector3 &GetMassCenter() const { 84 | return m_massCenter; 85 | } 86 | 87 | bool IsCompound() const { 88 | return m_pShape->isCompound(); 89 | } 90 | 91 | bool IsConvex() const { 92 | return m_pShape->isConvex(); 93 | } 94 | 95 | private: 96 | btCollisionShape *m_pShape; 97 | 98 | btVector3 m_rotInertia; 99 | btVector3 m_massCenter; 100 | }; 101 | 102 | class CPhysicsCollision : public IPhysicsCollision32 { 103 | public: 104 | CPhysicsCollision(); 105 | ~CPhysicsCollision(); 106 | 107 | CPhysConvex * ConvexFromVerts(Vector **ppVerts, int vertCount); 108 | CPhysConvex * ConvexFromVerts(const Vector *pVerts, int vertCount); // A more sensible version! 109 | CPhysConvex * ConvexFromPlanes(float *pPlanes, int planeCount, float mergeDistance); 110 | float ConvexVolume(CPhysConvex *pConvex); 111 | float ConvexSurfaceArea(CPhysConvex *pConvex); 112 | void SetConvexGameData(CPhysConvex *pConvex, unsigned int gameData); 113 | void ConvexFree(CPhysConvex *pConvex); 114 | CPhysConvex * ConvexFromConvexPolyhedron(const CPolyhedron &ConvexPolyhedron); 115 | CPolyhedron * PolyhedronFromConvex(CPhysConvex *const pConvex, bool bUseTempPolyhedron); 116 | void ConvexesFromConvexPolygon(const Vector &vPolyNormal, const Vector *pPoints, int iPointCount, CPhysConvex **pOutput); 117 | 118 | CPhysPolysoup * PolysoupCreate(); 119 | void PolysoupDestroy(CPhysPolysoup *pSoup); 120 | void PolysoupAddTriangle(CPhysPolysoup *pSoup, const Vector &a, const Vector &b, const Vector &c, int materialIndex7bits); 121 | 122 | CPhysCollide * ConvertPolysoupToCollide(CPhysPolysoup *pSoup, bool useMOPP); // Deprecated: useMOPP 123 | CPhysCollide * ConvertConvexToCollide(CPhysConvex **pConvex, int convexCount); 124 | CPhysCollide * ConvertConvexToCollideParams(CPhysConvex **pConvex, int convexCount, const convertconvexparams_t &convertParams); 125 | 126 | void AddConvexToCollide(CPhysCollide *pCollide, const CPhysConvex *pConvex, const matrix3x4_t *xform = NULL); 127 | void RemoveConvexFromCollide(CPhysCollide *pCollide, const CPhysConvex *pConvex); 128 | void RemoveConvexFromCollide(CPhysCollide *pCollide, int index); 129 | 130 | CPhysCollide * CreateCollide(); // Create an empty collision shape (to be used with AddConvexToCollide/RemoveConvexFromCollide) 131 | void DestroyCollide(CPhysCollide *pCollide); 132 | int CollideSize(CPhysCollide *pCollide); 133 | int CollideWrite(char *pDest, CPhysCollide *pCollide, bool swap = false); 134 | CPhysCollide * UnserializeCollide(char *pBuffer, int size, int index); 135 | float CollideVolume(CPhysCollide *pCollide); 136 | float CollideSurfaceArea(CPhysCollide *pCollide); 137 | Vector CollideGetExtent(const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, const Vector &direction); 138 | void CollideGetAABB(Vector *pMins, Vector *pMaxs, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles); 139 | void CollideGetMassCenter(CPhysCollide *pCollide, Vector *pOutMassCenter); 140 | void CollideSetMassCenter(CPhysCollide *pCollide, const Vector &massCenter); 141 | Vector CollideGetOrthographicAreas(const CPhysCollide *pCollide); 142 | void CollideSetOrthographicAreas(CPhysCollide *pCollide, const Vector &areas); 143 | void CollideSetScale(CPhysCollide *pCollide, const Vector &scale); 144 | void CollideGetScale(const CPhysCollide *pCollide, Vector &scale); 145 | int CollideIndex(const CPhysCollide *pCollide); 146 | int GetConvexesUsedInCollideable(const CPhysCollide *pCollideable, CPhysConvex **pOutputArray, int iOutputArrayLimit); 147 | 148 | // Some functions for old vphysics behavior. Do not use anything like these for newer collision shapes. 149 | 150 | CPhysCollide * GetCachedBBox(const Vector &mins, const Vector &maxs); 151 | void AddCachedBBox(CPhysCollide *pModel, const Vector &mins, const Vector &maxs); 152 | bool IsCachedBBox(CPhysCollide *pModel); 153 | void ClearBBoxCache(); 154 | bool GetBBoxCacheSize(int *pCachedSize, int *pCachedCount); 155 | 156 | // API for disabling old vphysics behavior. 157 | void EnableBBoxCache(bool enable); 158 | bool IsBBoxCacheEnabled(); 159 | 160 | CPhysConvex * BBoxToConvex(const Vector &mins, const Vector &maxs); 161 | CPhysCollide * BBoxToCollide(const Vector &mins, const Vector &maxs); 162 | 163 | // Misc collision shapes 164 | 165 | CPhysConvex * CylinderToConvex(const Vector &mins, const Vector &maxs); // Cylinder. Flat sides are on top/bottom (z axis) 166 | CPhysConvex * ConeToConvex(const float radius, const float height); 167 | CPhysConvex * SphereToConvex(const float radius); 168 | 169 | void TraceBox(const Vector &start, const Vector &end, const Vector &mins, const Vector &maxs, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr); 170 | void TraceBox(const Ray_t &ray, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr); 171 | void TraceBox(const Ray_t &ray, unsigned int contentsMask, IConvexInfo *pConvexInfo, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr); 172 | void TraceCollide(const Vector &start, const Vector &end, const CPhysCollide *pSweepCollide, const QAngle &sweepAngles, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr); 173 | void TraceConvex(const Vector &start, const Vector &end, const CPhysConvex *pSweepConvex, const QAngle &sweepAngles, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *pTrace); 174 | 175 | bool IsBoxIntersectingCone(const Vector &boxAbsMins, const Vector &boxAbsMaxs, const truncatedcone_t &cone); 176 | 177 | void VCollideLoad(vcollide_t *pOutput, int solidCount, const char *pBuffer, int size, bool swap = false); 178 | void VCollideUnload(vcollide_t *pVCollide); 179 | 180 | IVPhysicsKeyParser * VPhysicsKeyParserCreate(const char *pKeyData); 181 | void VPhysicsKeyParserDestroy(IVPhysicsKeyParser *pParser); 182 | 183 | int CreateDebugMesh(CPhysCollide const *pCollisionModel, Vector **outVerts); 184 | void DestroyDebugMesh(int vertCount, Vector *outVerts); 185 | 186 | ICollisionQuery * CreateQueryModel(CPhysCollide *pCollide); 187 | void DestroyQueryModel(ICollisionQuery *pQuery); 188 | 189 | IPhysicsCollision * ThreadContextCreate(); 190 | void ThreadContextDestroy(IPhysicsCollision *pThreadContex); 191 | 192 | CPhysCollide * CreateVirtualMesh(const virtualmeshparams_t ¶ms); 193 | bool SupportsVirtualMesh(); 194 | 195 | void OutputDebugInfo(const CPhysCollide *pCollide); 196 | unsigned int ReadStat(int statID); 197 | 198 | private: 199 | CUtlVector m_bboxCache; 200 | bool m_enableBBoxCache; 201 | }; 202 | 203 | extern CPhysicsCollision g_PhysicsCollision; 204 | 205 | #endif // PHYSICS_COLLISION_H 206 | -------------------------------------------------------------------------------- /src/Physics_CollisionSet.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | 3 | #include "Physics_CollisionSet.h" 4 | 5 | // memdbgon must be the last include file in a .cpp file!!! 6 | #include "tier0/memdbgon.h" 7 | 8 | /****************************** 9 | * CLASS CPhysicsCollisionSet 10 | ******************************/ 11 | 12 | // Is this class sort of like CPhysicsObjectPairHash? 13 | // ShouldCollide is called by game code from the collision event handler in CPhysicsEnvironment 14 | 15 | // TODO: Needs a better design, right now it's hardcoded to support a max of 32 entries (sizeof int). 16 | 17 | // All objects default with no collisions between other objects. 18 | // The game has to explicitly enable collisions between two objects (IVP behavior) 19 | 20 | CPhysicsCollisionSet::CPhysicsCollisionSet(int iMaxEntries) { 21 | Assert(iMaxEntries <= 32); 22 | 23 | m_iMaxEntries = iMaxEntries; 24 | 25 | m_collArray = new int[iMaxEntries]; 26 | for (int i = 0; i < iMaxEntries; i++) { 27 | m_collArray[i] = 0; 28 | } 29 | } 30 | 31 | CPhysicsCollisionSet::~CPhysicsCollisionSet() { 32 | delete [] m_collArray; 33 | } 34 | 35 | void CPhysicsCollisionSet::EnableCollisions(int index0, int index1) { 36 | Assert((index0 < m_iMaxEntries && index0 >= 0) && (index1 < m_iMaxEntries && index1 >= 0)); 37 | if ((index0 >= m_iMaxEntries || index0 < 0) || (index1 >= m_iMaxEntries || index1 < 0)) { 38 | return; 39 | } 40 | 41 | // Totally stolen from valve! 42 | m_collArray[index0] |= 1 << index1; 43 | m_collArray[index1] |= 1 << index0; 44 | } 45 | 46 | void CPhysicsCollisionSet::DisableCollisions(int index0, int index1) { 47 | Assert((index0 < m_iMaxEntries && index0 >= 0) && (index1 < m_iMaxEntries && index1 >= 0)); 48 | if ((index0 >= m_iMaxEntries || index0 < 0) || (index1 >= m_iMaxEntries || index1 < 0)) { 49 | return; 50 | } 51 | 52 | m_collArray[index0] &= ~(1 << index1); 53 | m_collArray[index1] &= ~(1 << index0); 54 | } 55 | 56 | bool CPhysicsCollisionSet::ShouldCollide(int index0, int index1) { 57 | Assert((index0 < m_iMaxEntries && index0 >= 0) && (index1 < m_iMaxEntries && index1 >= 0)); 58 | if ((index0 >= m_iMaxEntries || index0 < 0) || (index1 >= m_iMaxEntries || index1 < 0)) { 59 | return true; 60 | } 61 | 62 | return (((1 << index1) & m_collArray[index0]) != 0) || 63 | (((1 << index0) & m_collArray[index1]) != 0); 64 | } 65 | 66 | /********************* 67 | * CREATION FUNCTIONS 68 | *********************/ 69 | 70 | CPhysicsCollisionSet *CreateCollisionSet(int maxElements) { 71 | return new CPhysicsCollisionSet(maxElements); 72 | } -------------------------------------------------------------------------------- /src/Physics_CollisionSet.h: -------------------------------------------------------------------------------- 1 | #ifndef PHYSICS_COLLISIONSET_H 2 | #define PHYSICS_COLLISIONSET_H 3 | #if defined(_MSC_VER) || (defined(__GNUC__) && __GNUC__ > 3) 4 | #pragma once 5 | #endif 6 | 7 | class CPhysicsCollisionSet : public IPhysicsCollisionSet { 8 | public: 9 | CPhysicsCollisionSet(int iMaxEntries); 10 | ~CPhysicsCollisionSet(); 11 | 12 | void EnableCollisions(int index0, int index1); 13 | void DisableCollisions(int index0, int index1); 14 | 15 | bool ShouldCollide(int index0, int index1); 16 | 17 | private: 18 | int m_iMaxEntries; 19 | int * m_collArray; 20 | }; 21 | 22 | CPhysicsCollisionSet *CreateCollisionSet(int maxElements); 23 | 24 | #endif // PHYSICS_COLLISIONSET_H -------------------------------------------------------------------------------- /src/Physics_Constraint.h: -------------------------------------------------------------------------------- 1 | #ifndef PHYSICS_CONSTRAINT_H 2 | #define PHYSICS_CONSTRAINT_H 3 | #if defined(_MSC_VER) || (defined(__GNUC__) && __GNUC__ > 3) 4 | #pragma once 5 | #endif 6 | 7 | #include 8 | #include "vphysics/constraintsV32.h" 9 | 10 | #include "Physics_Object.h" 11 | 12 | class CPhysicsEnvironment; 13 | class CPhysicsConstraintGroup; 14 | class btSpringConstraint; 15 | 16 | enum EConstraintType { 17 | CONSTRAINT_UNKNOWN, 18 | CONSTRAINT_RAGDOLL, 19 | CONSTRAINT_HINGE, 20 | CONSTRAINT_FIXED, 21 | CONSTRAINT_SLIDING, 22 | CONSTRAINT_BALLSOCKET, 23 | CONSTRAINT_PULLEY, 24 | CONSTRAINT_LENGTH, 25 | CONSTRAINT_SPRING, 26 | CONSTRAINT_GEAR, 27 | CONSTRAINT_USER 28 | }; 29 | 30 | class CPhysicsConstraint : public IPhysicsConstraint, public IObjectEventListener { 31 | public: 32 | CPhysicsConstraint(CPhysicsEnvironment *pEnv, IPhysicsConstraintGroup *pGroup, CPhysicsObject *pObject1, CPhysicsObject *pObject2, btTypedConstraint *pConstraint, EConstraintType type); 33 | ~CPhysicsConstraint(); 34 | 35 | void Activate(); 36 | void Deactivate(); 37 | 38 | void SetGameData(void *gameData) { m_pGameData = gameData; }; 39 | void * GetGameData() const { return m_pGameData; }; 40 | 41 | IPhysicsObject * GetReferenceObject() const { return m_pReferenceObject; }; 42 | IPhysicsObject * GetAttachedObject() const { return m_pAttachedObject; }; 43 | 44 | void SetLinearMotor(float speed, float maxLinearImpulse); 45 | void SetAngularMotor(float rotSpeed, float maxAngularImpulse); 46 | 47 | void UpdateRagdollTransforms(const matrix3x4_t &constraintToReference, const matrix3x4_t &constraintToAttached); 48 | bool GetConstraintTransform(matrix3x4_t *pConstraintToReference, matrix3x4_t *pConstraintToAttached) const; 49 | bool GetConstraintParams(constraint_breakableparams_t *pParams) const; 50 | 51 | void OutputDebugInfo(); 52 | 53 | // UNEXPOSED FUNCTIONS 54 | public: 55 | // Call this if you're an object currently being destroyed. 56 | virtual void ObjectDestroyed(CPhysicsObject *pObject); 57 | 58 | EConstraintType GetType(); 59 | btTypedConstraint * GetConstraint(); 60 | 61 | void SetNotifyBroken(bool notify) {m_bNotifyBroken = notify;} 62 | 63 | protected: 64 | CPhysicsObject * m_pReferenceObject; 65 | CPhysicsObject * m_pAttachedObject; 66 | CPhysicsConstraintGroup *m_pGroup; 67 | void * m_pGameData; 68 | CPhysicsEnvironment * m_pEnv; 69 | EConstraintType m_type; 70 | bool m_bRemovedFromEnv; 71 | bool m_bNotifyBroken; // Should we notify the game that the constraint was broken? 72 | 73 | btTypedConstraint * m_pConstraint; 74 | }; 75 | 76 | class CPhysicsSpring : public IPhysicsSpring, public CPhysicsConstraint { 77 | public: 78 | CPhysicsSpring(CPhysicsEnvironment *pEnv, CPhysicsObject *pObject1, CPhysicsObject *pObject2, btTypedConstraint *pConstraint, EConstraintType type); 79 | ~CPhysicsSpring(); 80 | 81 | void GetEndpoints(Vector *worldPositionStart, Vector *worldPositionEnd); 82 | void SetSpringConstant(float flSpringContant); 83 | void SetSpringDamping(float flSpringDamping); 84 | void SetSpringLength(float flSpringLength); 85 | 86 | // Get the starting object 87 | IPhysicsObject *GetStartObject(); 88 | 89 | // Get the end object 90 | IPhysicsObject *GetEndObject(); 91 | }; 92 | 93 | // FIXME: I dont think we can implement this in Bullet anyways? 94 | // We'll have to emulate this on bullet. 95 | class CPhysicsConstraintGroup : public IPhysicsConstraintGroup 96 | { 97 | public: 98 | CPhysicsConstraintGroup(CPhysicsEnvironment *pEnv, const constraint_groupparams_t ¶ms); 99 | ~CPhysicsConstraintGroup(void); 100 | 101 | void Activate(); 102 | bool IsInErrorState(); 103 | void ClearErrorState(); 104 | void GetErrorParams(constraint_groupparams_t *pParams); 105 | void SetErrorParams(const constraint_groupparams_t ¶ms); 106 | void SolvePenetration(IPhysicsObject *pObj0, IPhysicsObject *pObj1); 107 | 108 | public: 109 | // Unexposed functions 110 | void AddConstraint(CPhysicsConstraint *pConstraint); 111 | void RemoveConstraint(CPhysicsConstraint *pConstraint); 112 | 113 | private: 114 | CUtlVector m_constraints; 115 | constraint_groupparams_t m_errorParams; 116 | CPhysicsEnvironment * m_pEnvironment; 117 | }; 118 | 119 | // CONSTRAINT CREATION FUNCTIONS 120 | CPhysicsSpring *CreateSpringConstraint(CPhysicsEnvironment *pEnv, IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, springparams_t *spring); 121 | CPhysicsConstraint *CreateRagdollConstraint(CPhysicsEnvironment *pEnv, IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_ragdollparams_t &ragdoll); 122 | CPhysicsConstraint *CreateHingeConstraint(CPhysicsEnvironment *pEnv, IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_hingeparams_t &hinge); 123 | CPhysicsConstraint *CreateFixedConstraint(CPhysicsEnvironment *pEnv, IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_fixedparams_t &fixed); 124 | CPhysicsConstraint *CreateSlidingConstraint(CPhysicsEnvironment *pEnv, IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_slidingparams_t &sliding); 125 | CPhysicsConstraint *CreateBallsocketConstraint(CPhysicsEnvironment *pEnv, IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_ballsocketparams_t &ballsocket); 126 | CPhysicsConstraint *CreatePulleyConstraint(CPhysicsEnvironment *pEnv, IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_pulleyparams_t &pulley); 127 | CPhysicsConstraint *CreateLengthConstraint(CPhysicsEnvironment *pEnv, IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_lengthparams_t &length); 128 | CPhysicsConstraint *CreateGearConstraint(CPhysicsEnvironment *pEnv, IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_gearparams_t &gear); 129 | CPhysicsConstraint *CreateUserConstraint(CPhysicsEnvironment *pEnv, IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, IPhysicsUserConstraint *pUserConstraint); 130 | 131 | CPhysicsConstraintGroup *CreateConstraintGroup(CPhysicsEnvironment *pEnv, const constraint_groupparams_t ¶ms); 132 | 133 | #endif // PHYSICS_CONSTRAINT_H 134 | -------------------------------------------------------------------------------- /src/Physics_DragController.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | 3 | #include "Physics_DragController.h" 4 | #include "Physics_Object.h" 5 | #include "convert.h" 6 | 7 | // memdbgon must be the last include file in a .cpp file!!! 8 | #include "tier0/memdbgon.h" 9 | 10 | /****************************** 11 | * CLASS CPhysicsDragController 12 | ******************************/ 13 | 14 | CPhysicsDragController::CPhysicsDragController() { 15 | m_airDensity = 2.f; // default 16 | } 17 | 18 | void CPhysicsDragController::SetAirDensity(float d) { 19 | // Density is kg/in^3 from HL 20 | m_airDensity = d / CUBIC_METERS_PER_CUBIC_INCH; 21 | } 22 | 23 | float CPhysicsDragController::GetAirDensity() { 24 | return m_airDensity * CUBIC_METERS_PER_CUBIC_INCH; 25 | } 26 | 27 | void CPhysicsDragController::RemovePhysicsObject(CPhysicsObject *obj) { 28 | m_ents.FindAndRemove(obj); 29 | } 30 | 31 | void CPhysicsDragController::AddPhysicsObject(CPhysicsObject *obj) { 32 | if (!IsControlling(obj)) { 33 | m_ents.AddToTail(obj); 34 | } 35 | } 36 | 37 | bool CPhysicsDragController::IsControlling(const CPhysicsObject *obj) const { 38 | return m_ents.Find((CPhysicsObject *)obj) != -1; 39 | } 40 | 41 | void CPhysicsDragController::Tick(btScalar dt) { 42 | for (int i = 0; i < m_ents.Count(); i++) { 43 | CPhysicsObject *pObject = (CPhysicsObject *)m_ents[i]; 44 | btRigidBody *body = pObject->GetObject(); 45 | if (body->getActivationState() == ISLAND_SLEEPING || body->getActivationState() == DISABLE_SIMULATION) 46 | continue; 47 | 48 | //------------------ 49 | // LINEAR DRAG 50 | //------------------ 51 | if (!btFuzzyZero(body->getLinearVelocity().length2())) { 52 | btVector3 vel(0, 0, 0); 53 | 54 | float dragForce = -1 * pObject->GetDragInDirection(body->getLinearVelocity().normalized()) * m_airDensity * dt; 55 | if (dragForce < -1.0f) 56 | dragForce = -1.0f; 57 | 58 | // If the drag force actually drags 59 | if (dragForce < 0) 60 | vel = body->getLinearVelocity() * dragForce; 61 | 62 | body->setLinearVelocity(body->getLinearVelocity() + vel); 63 | } 64 | 65 | //------------------ 66 | // ANGULAR DRAG 67 | //------------------ 68 | if (!btFuzzyZero(body->getAngularVelocity().length2())) { 69 | btVector3 ang(0, 0, 0); 70 | 71 | float angDragForce = -1 * pObject->GetAngularDragInDirection(body->getAngularVelocity().normalized()) * m_airDensity * dt; 72 | if (angDragForce < -1.0f) 73 | angDragForce = -1.0f; 74 | 75 | // If the drag force actually drags 76 | if (angDragForce < 0) 77 | ang = body->getAngularVelocity() * angDragForce; 78 | 79 | body->setAngularVelocity(body->getAngularVelocity() + ang); 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /src/Physics_DragController.h: -------------------------------------------------------------------------------- 1 | #ifndef PHYSICS_DRAGCONTROLLER_H 2 | #define PHYSICS_DRAGCONTROLLER_H 3 | #if defined(_MSC_VER) || (defined(__GNUC__) && __GNUC__ > 3) 4 | #pragma once 5 | #endif 6 | 7 | class CPhysicsObject; 8 | 9 | class CPhysicsDragController { 10 | public: 11 | CPhysicsDragController(); 12 | void SetAirDensity(float density); 13 | float GetAirDensity(); 14 | 15 | void AddPhysicsObject(CPhysicsObject *pObject); 16 | void RemovePhysicsObject(CPhysicsObject *pObject); 17 | void Tick(btScalar dt); 18 | bool IsControlling(const CPhysicsObject *pObject) const; 19 | private: 20 | float m_airDensity; 21 | 22 | CUtlVectorm_ents; 23 | }; 24 | 25 | #endif // PHYSICS_DRAGCONTROLLER_H -------------------------------------------------------------------------------- /src/Physics_Environment.h: -------------------------------------------------------------------------------- 1 | #ifndef PHYSICS_ENVIRONMENT_H 2 | #define PHYSICS_ENVIRONMENT_H 3 | #if defined(_MSC_VER) || (defined(__GNUC__) && __GNUC__ > 3) 4 | #pragma once 5 | #endif 6 | 7 | #include 8 | #include 9 | 10 | class CPhysThreadManager; 11 | class btCollisionConfiguration; 12 | class btDispatcher; 13 | class btBroadphaseInterface; 14 | class btConstraintSolver; 15 | 16 | class IPhysicsConstraintGroup; 17 | class IPhysicsUserConstraint; 18 | class IController; 19 | class CDeleteQueue; 20 | class CCollisionSolver; 21 | class CObjectTracker; 22 | class CCollisionEventListener; 23 | class CPhysicsFluidController; 24 | class CPhysicsDragController; 25 | class CPhysicsEnvironment; 26 | class CPhysicsConstraint; 27 | class CPhysicsObject; 28 | class btConstraintSolverPoolMt; 29 | 30 | class CDebugDrawer; 31 | 32 | class CCollisionSolver : public btOverlapFilterCallback { 33 | public: 34 | CCollisionSolver(CPhysicsEnvironment *pEnv) {m_pEnv = pEnv; m_pSolver = NULL;} 35 | void SetHandler(IPhysicsCollisionSolver *pSolver) {m_pSolver = pSolver;} 36 | virtual bool needBroadphaseCollision(btBroadphaseProxy *proxy0, btBroadphaseProxy *proxy1) const; 37 | 38 | bool NeedsCollision(CPhysicsObject *pObj0, CPhysicsObject *pObj1) const; 39 | private: 40 | IPhysicsCollisionSolver *m_pSolver; 41 | CPhysicsEnvironment *m_pEnv; 42 | }; 43 | 44 | enum SolverType 45 | { 46 | SOLVER_TYPE_SEQUENTIAL_IMPULSE, 47 | SOLVER_TYPE_SEQUENTIAL_IMPULSE_MT, 48 | SOLVER_TYPE_NNCG, 49 | SOLVER_TYPE_MLCP_PGS, 50 | SOLVER_TYPE_MLCP_DANTZIG, 51 | SOLVER_TYPE_MLCP_LEMKE, 52 | SOLVER_TYPE_COUNT 53 | }; 54 | 55 | class CPhysicsEnvironment : public IPhysicsEnvironment32 { 56 | public: 57 | CPhysicsEnvironment(); 58 | ~CPhysicsEnvironment(); 59 | 60 | void SetDebugOverlay(CreateInterfaceFn debugOverlayFactory); 61 | IVPhysicsDebugOverlay * GetDebugOverlay(); 62 | btIDebugDraw * GetDebugDrawer() const; 63 | 64 | void SetGravity(const Vector &gravityVector); 65 | void GetGravity(Vector *pGravityVector) const; 66 | 67 | void SetAirDensity(float density); 68 | float GetAirDensity() const; 69 | 70 | IPhysicsObject * CreatePolyObject(const CPhysCollide *pCollisionModel, int materialIndex, const Vector &position, const QAngle &angles, objectparams_t *pParams); 71 | IPhysicsObject * CreatePolyObjectStatic(const CPhysCollide *pCollisionModel, int materialIndex, const Vector &position, const QAngle &angles, objectparams_t *pParams); 72 | // Deprecated. Use the collision interface instead. 73 | IPhysicsObject * CreateSphereObject(float radius, int materialIndex, const Vector &position, const QAngle &angles, objectparams_t *pParams, bool isStatic = false); 74 | void DestroyObject(IPhysicsObject *pObject); 75 | 76 | IPhysicsFluidController * CreateFluidController(IPhysicsObject *pFluidObject, fluidparams_t *pParams); 77 | void DestroyFluidController(IPhysicsFluidController*); 78 | 79 | IPhysicsSpring * CreateSpring(IPhysicsObject *pObjectStart, IPhysicsObject *pObjectEnd, springparams_t *pParams); 80 | void DestroySpring(IPhysicsSpring*); 81 | 82 | IPhysicsConstraint * CreateRagdollConstraint(IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_ragdollparams_t &ragdoll); 83 | IPhysicsConstraint * CreateHingeConstraint(IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_hingeparams_t &hinge); 84 | IPhysicsConstraint * CreateFixedConstraint(IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_fixedparams_t &fixed); 85 | IPhysicsConstraint * CreateSlidingConstraint(IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_slidingparams_t &sliding); 86 | IPhysicsConstraint * CreateBallsocketConstraint(IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_ballsocketparams_t &ballsocket); 87 | IPhysicsConstraint * CreatePulleyConstraint(IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_pulleyparams_t &pulley); 88 | IPhysicsConstraint * CreateLengthConstraint(IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_lengthparams_t &length); 89 | IPhysicsConstraint * CreateGearConstraint(IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_gearparams_t &gear); 90 | IPhysicsConstraint * CreateUserConstraint(IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, IPhysicsUserConstraint *pConstraint); 91 | 92 | void DestroyConstraint(IPhysicsConstraint *pConstraint); 93 | 94 | IPhysicsConstraintGroup * CreateConstraintGroup(const constraint_groupparams_t &groupParams); 95 | void DestroyConstraintGroup(IPhysicsConstraintGroup *pGroup); 96 | 97 | IPhysicsShadowController * CreateShadowController(IPhysicsObject *pObject, bool allowTranslation, bool allowRotation); 98 | void DestroyShadowController(IPhysicsShadowController *pController); 99 | 100 | IPhysicsPlayerController * CreatePlayerController(IPhysicsObject *pObject); 101 | void DestroyPlayerController(IPhysicsPlayerController *pController); 102 | 103 | IPhysicsMotionController * CreateMotionController(IMotionEvent *pHandler); 104 | void DestroyMotionController(IPhysicsMotionController *pController); 105 | 106 | IPhysicsVehicleController * CreateVehicleController(IPhysicsObject *pVehicleBodyObject, const vehicleparams_t ¶ms, unsigned int nVehicleType, IPhysicsGameTrace *pGameTrace); 107 | void DestroyVehicleController(IPhysicsVehicleController *pController); 108 | 109 | void SetCollisionSolver(IPhysicsCollisionSolver *pSolver); 110 | 111 | bool IsInSimulation() const; 112 | 113 | float GetSimulationTimestep() const; 114 | void SetSimulationTimestep(float timestep); 115 | 116 | float GetSimulationTime() const; 117 | void ResetSimulationClock(); 118 | 119 | float GetNextFrameTime() const; 120 | 121 | void SetCollisionEventHandler(IPhysicsCollisionEvent *pCollisionEvents); 122 | void SetObjectEventHandler(IPhysicsObjectEvent *pObjectEvents); 123 | void SetConstraintEventHandler(IPhysicsConstraintEvent *pConstraintEvents); 124 | 125 | void SetQuickDelete(bool bQuick); 126 | 127 | int GetActiveObjectCount() const; 128 | void GetActiveObjects(IPhysicsObject **pOutputObjectList) const; 129 | 130 | const IPhysicsObject ** GetObjectList(int *pOutputObjectCount) const; 131 | int GetObjectCount() const; 132 | bool TransferObject(IPhysicsObject *pObject, IPhysicsEnvironment *pDestinationEnvironment); 133 | 134 | void CleanupDeleteList(); 135 | void EnableDeleteQueue(bool enable); 136 | 137 | bool Save(const physsaveparams_t ¶ms); 138 | void PreRestore(const physprerestoreparams_t ¶ms); 139 | bool Restore(const physrestoreparams_t ¶ms); 140 | void PostRestore(); 141 | 142 | bool IsCollisionModelUsed(CPhysCollide *pCollide) const; 143 | 144 | void TraceRay(const Ray_t &ray, unsigned int fMask, IPhysicsTraceFilter *pTraceFilter, trace_t *pTrace); 145 | void SweepCollideable(const CPhysCollide *pCollide, const Vector &vecAbsStart, const Vector &vecAbsEnd, const QAngle &vecAngles, unsigned int fMask, IPhysicsTraceFilter *pTraceFilter, trace_t *pTrace); 146 | void SweepConvex(const CPhysConvex *pConvex, const Vector &vecAbsStart, const Vector &vecAbsEnd, const QAngle &vecAngles, unsigned int fMask, IPhysicsTraceFilter *pTraceFilter, trace_t *pTrace); 147 | 148 | void GetPerformanceSettings(physics_performanceparams_t *pOutput) const; 149 | void SetPerformanceSettings(const physics_performanceparams_t *pSettings); 150 | 151 | void ReadStats(physics_stats_t *pOutput); 152 | void ClearStats(); 153 | 154 | unsigned int GetObjectSerializeSize(IPhysicsObject *pObject) const; 155 | void SerializeObjectToBuffer(IPhysicsObject *pObject, unsigned char *pBuffer, unsigned int bufferSize); 156 | IPhysicsObject * UnserializeObjectFromBuffer(void *pGameData, unsigned char *pBuffer, unsigned int bufferSize, bool enableCollisions); 157 | 158 | void EnableConstraintNotify(bool bEnable); 159 | void DebugCheckContacts(); 160 | public: 161 | // Unexposed functions 162 | btDiscreteDynamicsWorld* GetBulletEnvironment() const; 163 | 164 | float GetInvPSIScale() const; 165 | int GetSimPSI() { return m_simPSI; } 166 | float GetSubStepTime() { return m_subStepTime; } 167 | int GetNumSubSteps() { return m_numSubSteps; } 168 | int GetCurSubStep() { return m_curSubStep; } 169 | 170 | CPhysicsDragController * GetDragController() const; 171 | CCollisionSolver * GetCollisionSolver() const; 172 | 173 | physics_performanceparams_t & GetPerformanceSettings() { return m_perfparams; } 174 | const physics_performanceparams_t & GetPerformanceSettings() const { return m_perfparams; } 175 | btVector3 GetMaxLinearVelocity() const; 176 | btVector3 GetMaxAngularVelocity() const; 177 | 178 | void HandleConstraintBroken(CPhysicsConstraint *pConstraint) const; // Call this if you're a constraint that was just disabled/broken. 179 | void HandleFluidStartTouch(CPhysicsFluidController *pController, CPhysicsObject *pObject) const; 180 | void HandleFluidEndTouch(CPhysicsFluidController *pController, CPhysicsObject *pObject) const; 181 | void HandleObjectEnteredTrigger(CPhysicsObject *pTrigger, CPhysicsObject *pObject) const; 182 | void HandleObjectExitedTrigger(CPhysicsObject *pTrigger, CPhysicsObject *pObject) const; 183 | 184 | private: 185 | SolverType m_solverType; 186 | bool m_multithreadedWorld; 187 | bool m_multithreadCapable; 188 | bool m_inSimulation; 189 | bool m_bUseDeleteQueue; 190 | bool m_bConstraintNotify; 191 | bool m_deleteQuick; 192 | float m_timestep; 193 | float m_invPSIScale; 194 | int m_simPSICurrent; 195 | int m_simPSI; 196 | int m_numSubSteps; 197 | int m_curSubStep; 198 | float m_subStepTime; 199 | 200 | btCollisionConfiguration * m_pBulletConfiguration; 201 | btCollisionDispatcher * m_pBulletDispatcher; 202 | btBroadphaseInterface * m_pBulletBroadphase; 203 | btConstraintSolver * m_pBulletSolver; 204 | btDiscreteDynamicsWorld * m_pBulletDynamicsWorld; 205 | btOverlappingPairCallback * m_pBulletGhostCallback; 206 | 207 | CUtlVector m_objects; 208 | CUtlVector m_deadObjects; 209 | 210 | CUtlVector m_fluids; 211 | CUtlVector m_controllers; 212 | 213 | CCollisionEventListener * m_pCollisionListener; 214 | CCollisionSolver * m_pCollisionSolver; 215 | CDeleteQueue * m_pDeleteQueue; 216 | CObjectTracker * m_pObjectTracker; 217 | CPhysicsDragController * m_pPhysicsDragController; 218 | IVPhysicsDebugOverlay * m_pDebugOverlay; 219 | 220 | IPhysicsCollisionEvent * m_pCollisionEvent; 221 | IPhysicsConstraintEvent * m_pConstraintEvent; 222 | IPhysicsObjectEvent * m_pObjectEvent; 223 | 224 | physics_performanceparams_t m_perfparams; 225 | physics_stats_t m_stats; 226 | 227 | CDebugDrawer * m_debugdraw; 228 | 229 | CPhysThreadManager* m_pThreadManager; 230 | 231 | private: 232 | static void TickCallback(btDynamicsWorld *world, btScalar timestep); 233 | void BulletTick(btScalar timeStep); 234 | void DoCollisionEvents(float dt); 235 | void Simulate(float deltaTime); 236 | void CreateEmptyDynamicsWorld(); 237 | }; 238 | 239 | #endif // PHYSICS_ENVIRONMENT_H 240 | -------------------------------------------------------------------------------- /src/Physics_FluidController.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | 3 | #include "convert.h" 4 | #include "Physics_FluidController.h" 5 | #include "Physics_Object.h" 6 | #include "Physics_Environment.h" 7 | #include "Physics_SurfaceProps.h" 8 | #include "Physics_Collision.h" 9 | 10 | // memdbgon must be the last include file in a .cpp file!!! 11 | #include "tier0/memdbgon.h" 12 | 13 | /******************************** 14 | * CLASS CPhysicsFluidCallback 15 | ********************************/ 16 | 17 | class CPhysicsFluidCallback : public btGhostObjectCallback { 18 | public: 19 | CPhysicsFluidCallback(CPhysicsFluidController *pController) { 20 | m_pController = pController; 21 | } 22 | 23 | void addedOverlappingObject(btCollisionObject *pObject) { 24 | CPhysicsObject *pPhys = (CPhysicsObject *)pObject->getUserPointer(); 25 | if (!pPhys) return; 26 | 27 | m_pController->ObjectAdded(pPhys); 28 | } 29 | 30 | void removedOverlappingObject(btCollisionObject *pObject) { 31 | CPhysicsObject *pPhys = (CPhysicsObject *)pObject->getUserPointer(); 32 | if (!pPhys) return; 33 | 34 | m_pController->ObjectRemoved(pPhys); 35 | } 36 | 37 | private: 38 | CPhysicsFluidController *m_pController; 39 | }; 40 | 41 | /******************************** 42 | * CLASS CPhysicsFluidController 43 | ********************************/ 44 | 45 | CPhysicsFluidController::CPhysicsFluidController(CPhysicsEnvironment *pEnv, CPhysicsObject *pFluidObject, fluidparams_t *pParams) { 46 | m_pEnv = pEnv; 47 | m_pGameData = NULL; 48 | m_iContents = 0; 49 | m_vSurfacePlane = Vector4D(0, 0, 0, 0); 50 | 51 | if (pParams) { 52 | m_pGameData = pParams->pGameData; 53 | m_iContents = pParams->contents; 54 | m_vSurfacePlane = pParams->surfacePlane; 55 | ConvertPosToBull(pParams->currentVelocity, m_currentVelocity); 56 | } 57 | 58 | int matIndex = pFluidObject->GetMaterialIndex(); 59 | surfacedata_t *pSurface = g_SurfaceDatabase.GetSurfaceData(matIndex); 60 | if (pSurface) { 61 | m_fDensity = pSurface->physics.density; 62 | } 63 | 64 | pFluidObject->EnableCollisions(false); 65 | pFluidObject->SetContents(m_iContents); 66 | pFluidObject->SetFluidController(this); 67 | 68 | m_pCallback = new CPhysicsFluidCallback(this); 69 | 70 | m_pGhostObject = new btGhostObject; 71 | m_pGhostObject->setUserPointer(pFluidObject); 72 | m_pGhostObject->setCallback(m_pCallback); 73 | m_pGhostObject->setCollisionShape(pFluidObject->GetObject()->getCollisionShape()); 74 | m_pGhostObject->setWorldTransform(pFluidObject->GetObject()->getWorldTransform()); 75 | m_pGhostObject->setCollisionFlags(m_pGhostObject->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE | btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT); 76 | m_pEnv->GetBulletEnvironment()->addCollisionObject(m_pGhostObject, COLGROUP_WORLD, ~COLGROUP_WORLD); 77 | } 78 | 79 | CPhysicsFluidController::~CPhysicsFluidController() { 80 | m_pEnv->GetBulletEnvironment()->removeCollisionObject(m_pGhostObject); 81 | delete m_pGhostObject; 82 | delete m_pCallback; 83 | } 84 | 85 | void CPhysicsFluidController::WakeAllSleepingObjects() { 86 | int count = m_pGhostObject->getNumOverlappingObjects(); 87 | for (int i = 0; i < count; i++) { 88 | btRigidBody *body = btRigidBody::upcast(m_pGhostObject->getOverlappingObject(i)); 89 | if (!body) 90 | continue; 91 | 92 | body->activate(true); 93 | } 94 | } 95 | 96 | void CPhysicsFluidController::SetGameData(void *pGameData) { 97 | m_pGameData = pGameData; 98 | } 99 | 100 | void *CPhysicsFluidController::GetGameData() const { 101 | return m_pGameData; 102 | } 103 | 104 | void CPhysicsFluidController::GetSurfacePlane(Vector *pNormal, float *pDist) const { 105 | if (!pNormal && !pDist) return; 106 | 107 | if (pNormal) 108 | *pNormal = m_vSurfacePlane.AsVector3D(); 109 | 110 | if (pDist) 111 | *pDist = m_vSurfacePlane.w; 112 | } 113 | 114 | float CPhysicsFluidController::GetDensity() const { 115 | return m_fDensity; 116 | } 117 | 118 | int CPhysicsFluidController::GetContents() const { 119 | return m_iContents; 120 | } 121 | 122 | static btVector3 calcConvexCenter(btConvexHullShape *pShape, btVector3 &planePos, btVector3 &planeNorm) { 123 | // Basic average 124 | btVector3 sum(0, 0, 0); 125 | 126 | if (pShape->getNumPoints() > 0) { 127 | for (int i = 0; i < pShape->getNumPoints(); i++) { 128 | btVector3 point = pShape->getScaledPoint(i); 129 | point -= planePos; 130 | 131 | // Only add the point if it's submerged 132 | if (point.dot(planeNorm) < 0) 133 | sum += pShape->getScaledPoint(i); 134 | } 135 | 136 | sum /= static_cast(pShape->getNumPoints()); 137 | } 138 | 139 | return sum; 140 | } 141 | 142 | // Find the object's center of buoyancy 143 | // This would be the center of all submerged points 144 | // You can bisect the object by the plane of the water surface to get all points 145 | // submerged, then calculate the center of all those points 146 | // planePos: World space plane position 147 | // planeNorm: World space plane normal 148 | static btVector3 calculateBuoyantCenter(btRigidBody *pBody, btVector3 &planePos, btVector3 &planeNorm) { 149 | btVector3 center(0, 0, 0); 150 | 151 | btVector3 relPlanePos = pBody->getWorldTransform().inverse() * planePos; 152 | btVector3 relNorm = quatRotate(pBody->getWorldTransform().getRotation().inverse(), planeNorm); 153 | 154 | btCollisionShape *pShape = pBody->getCollisionShape(); 155 | if (pShape->getShapeType() == COMPOUND_SHAPE_PROXYTYPE) { 156 | btCompoundShape *pCompound = (btCompoundShape *)pShape; 157 | for (int i = 0; i < pCompound->getNumChildShapes(); i++) { 158 | btCollisionShape *pChild = pCompound->getChildShape(i); 159 | if (pChild->getShapeType() == CONVEX_HULL_SHAPE_PROXYTYPE) { 160 | center += calcConvexCenter((btConvexHullShape *)pChild, relPlanePos, relNorm); 161 | } 162 | } 163 | 164 | if (pCompound->getNumChildShapes() > 0) 165 | center /= static_cast(pCompound->getNumChildShapes()); 166 | } 167 | 168 | return center; 169 | } 170 | 171 | // TODO: Refactor this code to be less messy. 172 | void CPhysicsFluidController::Tick(float dt) { 173 | // TODO: Buoyancy calculation 174 | int numObjects = m_pGhostObject->getNumOverlappingObjects(); 175 | for (int i = 0; i < numObjects; i++) { 176 | btRigidBody *body = btRigidBody::upcast(m_pGhostObject->getOverlappingObject(i)); 177 | Assert(body); 178 | if (!body) continue; 179 | 180 | CPhysicsObject *pObject = (CPhysicsObject *)body->getUserPointer(); 181 | Assert(pObject); 182 | 183 | // Find the surface plane's world pos (center at the very top) 184 | btVector3 surfPos = m_pGhostObject->getWorldTransform().getOrigin(); 185 | btVector3 surfNorm; 186 | ConvertDirectionToBull(m_vSurfacePlane.AsVector3D(), surfNorm); 187 | 188 | // btScalar fluidLen = ConvertDistanceToBull(m_vSurfacePlane.w); 189 | 190 | btVector3 omins, omaxs; 191 | m_pGhostObject->getCollisionShape()->getAabb(m_pGhostObject->getWorldTransform(), omins, omaxs); 192 | btScalar height = omaxs.y() - omins.y(); 193 | 194 | surfPos += surfNorm * (height / 2); 195 | 196 | btVector3 center = calculateBuoyantCenter(body, surfPos, surfNorm); 197 | center = body->getWorldTransform() * center; // Convert back into world space 198 | 199 | btVector3 offset = center - surfPos; 200 | btScalar submerged = surfNorm.dot(offset); 201 | 202 | #ifdef _DEBUG 203 | IVPhysicsDebugOverlay *pOverlay = m_pEnv->GetDebugOverlay(); 204 | if (pOverlay) { 205 | Vector pos; 206 | ConvertPosToHL(surfPos, pos); 207 | pOverlay->AddBoxOverlay(pos, Vector(-8), Vector(8), QAngle(0, 0, 0), 255, 0, 0, 255, 0.f); 208 | pOverlay->AddLineOverlay(pos, pos + m_vSurfacePlane.AsVector3D() * 32, 255, 0, 0, false, 0.f); 209 | 210 | ConvertPosToHL(center, pos); 211 | pOverlay->AddBoxOverlay(pos, Vector(-8), Vector(8), QAngle(0, 0, 0), 0, 0, 255, 255, 0.f); 212 | 213 | if (submerged < 0) { 214 | pOverlay->AddTextOverlay(pos, 0.f, "submerged %+04.2f", submerged); 215 | } 216 | } 217 | #endif 218 | 219 | if (submerged < 0) { 220 | btVector3 mins, maxs; 221 | body->getAabb(mins, maxs); 222 | 223 | // Calc the volume coefficient 224 | btScalar dist = -submerged; 225 | float p = clamp(dist / 1.2f, 0.f, 1.f); 226 | btScalar vol = p * pObject->GetVolume(); 227 | 228 | // TODO: Need a way to calculate this properly 229 | // Force should be exactly equal to -gravity when submerged distance is 0 230 | // density units kg/m^3 231 | btVector3 force = (m_fDensity * -body->getGravity() * vol) * pObject->GetBuoyancyRatio(); 232 | 233 | btVector3 relPos = center - body->getWorldTransform().getOrigin(); 234 | body->applyForce(force, relPos); 235 | } 236 | 237 | // Old code that actually works better 238 | /* 239 | btVector3 mins, maxs, omins, omaxs; 240 | body->getAabb(mins, maxs); 241 | m_pGhostObject->getCollisionShape()->getAabb(m_pGhostObject->getWorldTransform(), omins, omaxs); 242 | 243 | float height = maxs.y() - mins.y(); // If the plane for the surface can be non-upwards I'm going to murder something 244 | //float height = abs(ConvertDistanceToBull(m_vSurfacePlane.w)); 245 | float dist = omaxs.y() - mins.y(); // Distance between top of water and bottom of object (how much of object is in water) 246 | float p = clamp(dist / height, 0.0f, 1.0f); 247 | float vol = (pObject->GetVolume() * p); // / 64; // Submerged volume 248 | 249 | // TODO: We need to calculate this force at several points on the object (How do we determine what points?). 250 | // Maybe have the points determined by the extents of the shape at 4 directions parallel to our surface 251 | // Simulate buoyant force per convex or just on the compound? 252 | 253 | // Simulate buoyant force per point submerged 254 | // Divide it over all of the points that are submerged 255 | 256 | // IVP calculates this force per triangle 257 | btVector3 force = (m_fDensity * -body->getGravity() * vol) * pObject->GetBuoyancyRatio(); 258 | body->applyCentralForce(force); 259 | 260 | // Damping 261 | // FIXME: Damping would be way too much for an object only partially touching our surface (ex. giant fucking bridge with like 1 pixel in the water) 262 | body->setLinearVelocity(body->getLinearVelocity() * (1.0f - (0.75f * dt))); 263 | body->setAngularVelocity(body->getAngularVelocity() * (1.0f - (0.75f * dt))); 264 | */ 265 | } 266 | } 267 | 268 | // UNEXPOSED 269 | void CPhysicsFluidController::ObjectAdded(CPhysicsObject *pObject) { 270 | m_pEnv->HandleFluidStartTouch(this, pObject); 271 | } 272 | 273 | // UNEXPOSED 274 | void CPhysicsFluidController::ObjectRemoved(CPhysicsObject *pObject) { 275 | // Don't send the callback on objects that are being removed 276 | if (!pObject->IsBeingRemoved()) 277 | m_pEnv->HandleFluidEndTouch(this, pObject); 278 | } 279 | 280 | void CPhysicsFluidController::TransferToEnvironment(CPhysicsEnvironment *pDest) { 281 | 282 | } 283 | 284 | /************************ 285 | * CREATION FUNCTIONS 286 | ************************/ 287 | 288 | CPhysicsFluidController *CreateFluidController(CPhysicsEnvironment *pEnv, CPhysicsObject *pFluidObject, fluidparams_t *pParams) { 289 | if (!pEnv || !pFluidObject) return NULL; 290 | CPhysicsFluidController *pFluid = new CPhysicsFluidController(pEnv, pFluidObject, pParams); 291 | return pFluid; 292 | } -------------------------------------------------------------------------------- /src/Physics_FluidController.h: -------------------------------------------------------------------------------- 1 | #ifndef PHYSICS_FLUIDCONTROLLER_H 2 | #define PHYSICS_FLUIDCONTROLLER_H 3 | #if defined(_MSC_VER) || (defined(__GNUC__) && __GNUC__ > 3) 4 | #pragma once 5 | #endif 6 | 7 | #include "IController.h" 8 | 9 | class CPhysicsEnvironment; 10 | class CPhysicsFluidCallback; 11 | class CPhysicsObject; 12 | 13 | class CPhysicsFluidController : public IPhysicsFluidController, public IController 14 | { 15 | public: 16 | CPhysicsFluidController(CPhysicsEnvironment *pEnv, CPhysicsObject *pFluidObject, fluidparams_t *pParams); 17 | ~CPhysicsFluidController(); 18 | 19 | void SetGameData(void *pGameData); 20 | void * GetGameData() const; 21 | 22 | void GetSurfacePlane(Vector *pNormal, float *pDist) const; 23 | float GetDensity() const; 24 | void WakeAllSleepingObjects(); 25 | int GetContents() const; 26 | 27 | // UNEXPOSED FUNCTIONS 28 | public: 29 | void Tick(float deltaTime); 30 | void ObjectRemoved(CPhysicsObject *pObject); 31 | void ObjectAdded(CPhysicsObject *pObject); 32 | 33 | void TransferToEnvironment(CPhysicsEnvironment *pDest); 34 | private: 35 | void * m_pGameData; 36 | int m_iContents; 37 | float m_fDensity; 38 | 39 | // surface plane is a Vector surface normal and float distance 40 | Vector4D m_vSurfacePlane; 41 | btVector3 m_currentVelocity; // Velocity of water current 42 | CPhysicsEnvironment * m_pEnv; 43 | btGhostObject * m_pGhostObject; 44 | CPhysicsFluidCallback * m_pCallback; 45 | }; 46 | 47 | CPhysicsFluidController *CreateFluidController(CPhysicsEnvironment *pEnv, CPhysicsObject *pFluidObject, fluidparams_t *pParams); 48 | 49 | #endif // PHYSICS_FLUIDCONTROLLER_H 50 | -------------------------------------------------------------------------------- /src/Physics_FrictionSnapshot.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | 3 | #include "Physics_FrictionSnapshot.h" 4 | #include "Physics_Object.h" 5 | #include "Physics_Environment.h" 6 | 7 | #include "convert.h" 8 | 9 | // memdbgon must be the last include file in a .cpp file!!! 10 | #include "tier0/memdbgon.h" 11 | 12 | CPhysicsFrictionSnapshot::CPhysicsFrictionSnapshot(CPhysicsObject *pObject) { 13 | m_pObject = pObject; 14 | m_iCurContactPoint = 0; 15 | m_iCurManifold = 0; 16 | 17 | CPhysicsEnvironment *pEnv = pObject->GetVPhysicsEnvironment(); 18 | btRigidBody *pBody = pObject->GetObject(); 19 | int numManifolds = pEnv->GetBulletEnvironment()->getDispatcher()->getNumManifolds(); 20 | for (int i = 0; i < numManifolds; i++) { 21 | btPersistentManifold *pManifold = pEnv->GetBulletEnvironment()->getDispatcher()->getManifoldByIndexInternal(i); 22 | const btCollisionObject *pObjA = pManifold->getBody0(); 23 | const btCollisionObject *pObjB = pManifold->getBody1(); 24 | 25 | if (pManifold->getNumContacts() <= 0) 26 | continue; 27 | 28 | if (pObjA == pBody || pObjB == pBody) { 29 | m_manifolds.AddToTail(pManifold); 30 | } 31 | } 32 | } 33 | 34 | CPhysicsFrictionSnapshot::~CPhysicsFrictionSnapshot() { 35 | m_manifolds.RemoveAll(); 36 | } 37 | 38 | bool CPhysicsFrictionSnapshot::IsValid() { 39 | return m_iCurManifold < m_manifolds.Count(); 40 | } 41 | 42 | IPhysicsObject *CPhysicsFrictionSnapshot::GetObject(int index) { 43 | const btCollisionObject *colObjA = m_manifolds[m_iCurManifold]->getBody0(); 44 | const btCollisionObject *colObjB = m_manifolds[m_iCurManifold]->getBody1(); 45 | const CPhysicsObject *pObjA = (CPhysicsObject *)colObjA->getUserPointer(); 46 | const CPhysicsObject *pObjB = (CPhysicsObject *)colObjB->getUserPointer(); 47 | 48 | // index 0 is this object, 1 is other object 49 | if (index == 0) 50 | return (pObjA == m_pObject) ? (IPhysicsObject *)pObjA : (IPhysicsObject *)pObjB; 51 | else 52 | return (pObjA != m_pObject) ? (IPhysicsObject *)pObjA : (IPhysicsObject *)pObjB; 53 | } 54 | 55 | int CPhysicsFrictionSnapshot::GetMaterial(int index) { 56 | const btCollisionObject *colObjA = m_manifolds[m_iCurManifold]->getBody0(); 57 | const btCollisionObject *colObjB = m_manifolds[m_iCurManifold]->getBody1(); 58 | const CPhysicsObject *pObjA = (CPhysicsObject *)colObjA->getUserPointer(); 59 | const CPhysicsObject *pObjB = (CPhysicsObject *)colObjB->getUserPointer(); 60 | 61 | // index 0 is this object, 1 is other object 62 | if (index == 0) 63 | return (pObjA == m_pObject) ? pObjA->GetMaterialIndex() : pObjB->GetMaterialIndex(); 64 | else 65 | return (pObjA != m_pObject) ? pObjA->GetMaterialIndex() : pObjB->GetMaterialIndex(); 66 | } 67 | 68 | void CPhysicsFrictionSnapshot::GetContactPoint(Vector &out) { 69 | btManifoldPoint bullManifoldPoint = m_manifolds[m_iCurManifold]->getContactPoint(m_iCurContactPoint); 70 | 71 | btVector3 bullPos = bullManifoldPoint.getPositionWorldOnA(); 72 | if (m_pObject->GetObject() == m_manifolds[m_iCurManifold]->getBody1()) { 73 | bullPos = bullManifoldPoint.getPositionWorldOnB(); // Our object is object B, so get the pos for B 74 | } 75 | 76 | ConvertPosToHL(bullPos, out); 77 | } 78 | 79 | void CPhysicsFrictionSnapshot::GetSurfaceNormal(Vector &out) { 80 | btManifoldPoint bullManifoldPoint = m_manifolds[m_iCurManifold]->getContactPoint(m_iCurContactPoint); 81 | btVector3 norm = bullManifoldPoint.m_normalWorldOnB; 82 | 83 | // Flip the normal so it's world on A (needs to be pointed away from m_pObject) 84 | if (m_pObject->GetObject() == m_manifolds[m_iCurManifold]->getBody0()) 85 | norm *= -1; 86 | 87 | ConvertDirectionToHL(norm, out); // The game expects the normal to point away from our object 88 | } 89 | 90 | float CPhysicsFrictionSnapshot::GetNormalForce() { 91 | btManifoldPoint bullManifoldPoint = m_manifolds[m_iCurManifold]->getContactPoint(m_iCurContactPoint); 92 | return BULL2HL(bullManifoldPoint.m_appliedImpulse); // Force impulse to HL (kg * m/s) -> (kg * in/s) 93 | } 94 | 95 | float CPhysicsFrictionSnapshot::GetEnergyAbsorbed() { 96 | NOT_IMPLEMENTED 97 | return 0; 98 | } 99 | 100 | void CPhysicsFrictionSnapshot::RecomputeFriction() { 101 | NOT_IMPLEMENTED 102 | } 103 | 104 | void CPhysicsFrictionSnapshot::ClearFrictionForce() { 105 | NOT_IMPLEMENTED 106 | } 107 | 108 | void CPhysicsFrictionSnapshot::MarkContactForDelete() { 109 | NOT_IMPLEMENTED 110 | } 111 | 112 | void CPhysicsFrictionSnapshot::DeleteAllMarkedContacts(bool wakeObjects) { 113 | NOT_IMPLEMENTED 114 | } 115 | 116 | void CPhysicsFrictionSnapshot::NextFrictionData() { 117 | m_iCurContactPoint++; 118 | if (m_iCurContactPoint >= m_manifolds[m_iCurManifold]->getNumContacts()) { 119 | m_iCurManifold++; 120 | m_iCurContactPoint = 0; 121 | } 122 | } 123 | 124 | float CPhysicsFrictionSnapshot::GetFrictionCoefficient() { 125 | btManifoldPoint bullManifoldPoint = m_manifolds[m_iCurManifold]->getContactPoint(m_iCurContactPoint); 126 | return bullManifoldPoint.m_combinedFriction; 127 | } 128 | 129 | /*********************** 130 | * CREATION FUNCTIONS 131 | ***********************/ 132 | 133 | CPhysicsFrictionSnapshot *CreateFrictionSnapshot(CPhysicsObject *pObject) { 134 | if (!pObject) return NULL; 135 | 136 | return new CPhysicsFrictionSnapshot(pObject); 137 | } -------------------------------------------------------------------------------- /src/Physics_FrictionSnapshot.h: -------------------------------------------------------------------------------- 1 | #ifndef PHYSICS_FRICTIONSNAPSHOT_H 2 | #define PHYSICS_FRICTIONSNAPSHOT_H 3 | #if defined(_MSC_VER) || (defined(__GNUC__) && __GNUC__ > 3) 4 | #pragma once 5 | #endif 6 | 7 | #include 8 | 9 | class CPhysicsObject; 10 | class btPersistentManifold; 11 | 12 | class CPhysicsFrictionSnapshot : public IPhysicsFrictionSnapshot 13 | { 14 | public: 15 | CPhysicsFrictionSnapshot(CPhysicsObject *pObject); 16 | ~CPhysicsFrictionSnapshot(); 17 | 18 | bool IsValid(); 19 | 20 | IPhysicsObject * GetObject(int index); 21 | int GetMaterial(int index); 22 | 23 | void GetContactPoint(Vector &out); 24 | 25 | void GetSurfaceNormal(Vector &out); 26 | float GetNormalForce(); 27 | float GetEnergyAbsorbed(); 28 | 29 | void RecomputeFriction(); 30 | void ClearFrictionForce(); 31 | 32 | void MarkContactForDelete(); 33 | void DeleteAllMarkedContacts(bool wakeObjects); 34 | 35 | void NextFrictionData(); 36 | float GetFrictionCoefficient(); 37 | private: 38 | CUtlVector m_manifolds; 39 | CPhysicsObject * m_pObject; 40 | int m_iCurManifold; 41 | int m_iCurContactPoint; 42 | }; 43 | 44 | CPhysicsFrictionSnapshot *CreateFrictionSnapshot(CPhysicsObject *pObject); 45 | 46 | #endif // PHYSICS_FRICTIONSNAPSHOT_H 47 | -------------------------------------------------------------------------------- /src/Physics_KeyParser.h: -------------------------------------------------------------------------------- 1 | #ifndef PHYSICS_KEYPARSER_H 2 | #define PHYSICS_KEYPARSER_H 3 | #if defined(_MSC_VER) || (defined(__GNUC__) && __GNUC__ > 3) 4 | #pragma once 5 | #endif 6 | 7 | #include 8 | #include 9 | 10 | class KeyValues; 11 | 12 | class CPhysicsKeyParser : public IVPhysicsKeyParser 13 | { 14 | public: 15 | CPhysicsKeyParser(const char *pKeyValues); 16 | ~CPhysicsKeyParser(); 17 | 18 | void NextBlock(); 19 | 20 | const char * GetCurrentBlockName(); 21 | bool Finished(); 22 | void ParseSolid(solid_t *pSolid, IVPhysicsKeyHandler *unknownKeyHandler); 23 | void ParseFluid(fluid_t *pFluid, IVPhysicsKeyHandler *unknownKeyHandler); 24 | void ParseRagdollConstraint(constraint_ragdollparams_t *pConstraint, IVPhysicsKeyHandler *unknownKeyHandler); 25 | void ParseSurfaceTable(int *table, IVPhysicsKeyHandler *unknownKeyHandler); 26 | void ParseCustom(void *pCustom, IVPhysicsKeyHandler *unknownKeyHandler); 27 | void ParseVehicle(vehicleparams_t *pVehicle, IVPhysicsKeyHandler *unknownKeyHandler); 28 | void SkipBlock() { NextBlock(); }; 29 | 30 | // Unexposed functions 31 | public: 32 | void ParseVehicleAxle(vehicle_axleparams_t &axle, KeyValues *kv); 33 | void ParseVehicleWheel(vehicle_wheelparams_t &wheel, KeyValues *kv); 34 | void ParseVehicleSuspension(vehicle_suspensionparams_t &suspension, KeyValues *kv); 35 | void ParseVehicleBody(vehicle_bodyparams_t &body, KeyValues *kv); 36 | void ParseVehicleEngine(vehicle_engineparams_t &engine, KeyValues *kv); 37 | void ParseVehicleEngineBoost(vehicle_engineparams_t &engine, KeyValues *kv); 38 | void ParseVehicleSteering(vehicle_steeringparams_t &steering, KeyValues *kv); 39 | 40 | private: 41 | KeyValues * m_pKeyValues; 42 | KeyValues * m_pCurrentBlock; 43 | }; 44 | 45 | #endif // PHYSICS_KEYPARSER_H 46 | -------------------------------------------------------------------------------- /src/Physics_MotionController.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | 3 | #include "Physics_MotionController.h" 4 | #include "Physics_Object.h" 5 | #include "convert.h" 6 | 7 | // memdbgon must be the last include file in a .cpp file!!! 8 | #include "tier0/memdbgon.h" 9 | 10 | IPhysicsMotionController *CreateMotionController(CPhysicsEnvironment *pEnv, IMotionEvent *pHandler) { 11 | if (!pEnv) return NULL; 12 | return new CPhysicsMotionController(pHandler, pEnv); 13 | } 14 | 15 | /*********************************** 16 | * CLASS CPhysicsMotionController 17 | ***********************************/ 18 | 19 | // This class can totally be moved back to game code. 20 | 21 | CPhysicsMotionController::CPhysicsMotionController(IMotionEvent *pHandler, CPhysicsEnvironment *pEnv) { 22 | m_handler = pHandler; 23 | m_pEnv = pEnv; 24 | } 25 | 26 | CPhysicsMotionController::~CPhysicsMotionController() { 27 | for (int i = m_objectList.Count()-1; i >= 0; i--) { 28 | CPhysicsMotionController::DetachObject(m_objectList[i]); 29 | } 30 | } 31 | 32 | void CPhysicsMotionController::Tick(float deltaTime) { 33 | if (!m_handler) return; 34 | 35 | for (int i = 0; i < m_objectList.Count(); i++) { 36 | Vector speed; 37 | AngularImpulse rot; 38 | 39 | CPhysicsObject *pObject = m_objectList[i]; 40 | IMotionEvent::simresult_e ret = m_handler->Simulate(this, pObject, deltaTime, speed, rot); 41 | 42 | speed *= deltaTime; 43 | rot *= deltaTime; 44 | 45 | Vector curVel, curAngVel; 46 | pObject->GetVelocity(&curVel, &curAngVel); 47 | 48 | switch (ret) { 49 | case IMotionEvent::SIM_NOTHING: { 50 | break; 51 | } 52 | case IMotionEvent::SIM_LOCAL_ACCELERATION: { 53 | // Convert velocity to world space 54 | Vector newVel; 55 | pObject->LocalToWorldVector(&newVel, speed); 56 | 57 | pObject->AddVelocity(&newVel, &rot); // Rotation already in local space. 58 | break; 59 | } 60 | case IMotionEvent::SIM_LOCAL_FORCE: { 61 | Vector newVel; 62 | pObject->LocalToWorldVector(&newVel, speed); 63 | 64 | pObject->ApplyForceCenter(newVel); 65 | pObject->ApplyTorqueCenter(rot); 66 | break; 67 | } 68 | case IMotionEvent::SIM_GLOBAL_ACCELERATION: { 69 | pObject->AddVelocity(&speed, &rot); 70 | break; 71 | } 72 | case IMotionEvent::SIM_GLOBAL_FORCE: { 73 | pObject->ApplyForceCenter(speed); 74 | pObject->ApplyTorqueCenter(rot); 75 | break; 76 | } 77 | default: { 78 | DevWarning("VPhysics: Invalid motion controller event type returned (%d)\n", ret); 79 | } 80 | } 81 | } 82 | } 83 | 84 | void CPhysicsMotionController::ObjectDestroyed(CPhysicsObject *pObject) { 85 | m_objectList.FindAndRemove(pObject); 86 | } 87 | 88 | void CPhysicsMotionController::SetEventHandler(IMotionEvent *handler) { 89 | m_handler = handler; 90 | } 91 | 92 | void CPhysicsMotionController::AttachObject(IPhysicsObject *pObject, bool checkIfAlreadyAttached) { 93 | Assert(pObject); 94 | if (!pObject || pObject->IsStatic()) return; 95 | 96 | CPhysicsObject *pPhys = (CPhysicsObject *)pObject; 97 | 98 | if (m_objectList.Find(pPhys) != -1 && checkIfAlreadyAttached) 99 | return; 100 | 101 | pPhys->AttachedToController(this); 102 | pPhys->AttachEventListener(this); 103 | m_objectList.AddToTail(pPhys); 104 | } 105 | 106 | void CPhysicsMotionController::DetachObject(IPhysicsObject *pObject) { 107 | CPhysicsObject *pPhys = (CPhysicsObject *)pObject; 108 | 109 | int index = m_objectList.Find(pPhys); 110 | if (!m_objectList.IsValidIndex(index)) return; 111 | 112 | pPhys->DetachedFromController(this); 113 | pPhys->DetachEventListener(this); 114 | m_objectList.Remove(index); 115 | } 116 | 117 | int CPhysicsMotionController::CountObjects() { 118 | return m_objectList.Count(); 119 | } 120 | 121 | void CPhysicsMotionController::GetObjects(IPhysicsObject **pObjectList) { 122 | if (!pObjectList) return; 123 | 124 | for (int i = 0; i < m_objectList.Count(); i++) { 125 | pObjectList[i] = (IPhysicsObject *)m_objectList[i]; 126 | } 127 | } 128 | 129 | void CPhysicsMotionController::ClearObjects() { 130 | m_objectList.Purge(); 131 | } 132 | 133 | void CPhysicsMotionController::WakeObjects() { 134 | for (int i = 0; i < m_objectList.Count(); i++) { 135 | m_objectList[i]->GetObject()->setActivationState(ACTIVE_TAG); 136 | } 137 | } 138 | 139 | void CPhysicsMotionController::SetPriority(priority_t priority) { 140 | // IVP Controllers had a priority. Since bullet doesn't have controllers, this function is useless. 141 | } 142 | -------------------------------------------------------------------------------- /src/Physics_MotionController.h: -------------------------------------------------------------------------------- 1 | #ifndef PHYSICS_MOTIONCONTROLLER_H 2 | #define PHYSICS_MOTIONCONTROLLER_H 3 | #if defined(_MSC_VER) || (defined(__GNUC__) && __GNUC__ > 3) 4 | #pragma once 5 | #endif 6 | 7 | #include "IController.h" 8 | 9 | #include "Physics_Object.h" 10 | 11 | class CPhysicsEnvironment; 12 | 13 | class CPhysicsMotionController : public IController, public IPhysicsMotionController, public IObjectEventListener 14 | { 15 | public: 16 | CPhysicsMotionController(IMotionEvent *pHandler, CPhysicsEnvironment *pEnv); 17 | ~CPhysicsMotionController(); 18 | 19 | void SetEventHandler(IMotionEvent *handler); 20 | void AttachObject(IPhysicsObject *pObject, bool checkIfAlreadyAttached); 21 | void DetachObject(IPhysicsObject *pObject); 22 | 23 | int CountObjects(); 24 | void GetObjects(IPhysicsObject **pObjectList); 25 | void ClearObjects(); 26 | void WakeObjects(); 27 | 28 | void SetPriority(priority_t priority); 29 | public: 30 | void Tick(float deltaTime); 31 | void ObjectDestroyed(CPhysicsObject *pObject); 32 | 33 | private: 34 | IMotionEvent * m_handler; 35 | CUtlVector m_objectList; 36 | CPhysicsEnvironment * m_pEnv; 37 | 38 | int m_priority; 39 | }; 40 | 41 | IPhysicsMotionController *CreateMotionController(CPhysicsEnvironment *pEnv, IMotionEvent *pHandler); 42 | 43 | #endif // PHYSICS_MOTIONCONTROLLER_H 44 | -------------------------------------------------------------------------------- /src/Physics_Object.h: -------------------------------------------------------------------------------- 1 | #ifndef PHYSICS_OBJECT_H 2 | #define PHYSICS_OBJECT_H 3 | #if defined(_MSC_VER) || (defined(__GNUC__) && __GNUC__ > 3) 4 | #pragma once 5 | #endif 6 | 7 | class CPhysicsEnvironment; 8 | class CPhysicsVehicleController; 9 | class CShadowController; 10 | class CPhysicsFluidController; 11 | class CPhysicsConstraint; 12 | class IController; 13 | 14 | // Bullet uses this so we can sync the graphics representation of the object. 15 | struct btMassCenterMotionState : public btMotionState { 16 | btTransform m_centerOfMassOffset; 17 | btTransform m_worldTrans; 18 | void * m_userPointer; 19 | 20 | btMassCenterMotionState(const btTransform ¢erOfMassOffset = btTransform::getIdentity()) 21 | : m_centerOfMassOffset(centerOfMassOffset), m_worldTrans(btTransform::getIdentity()), m_userPointer(0) 22 | { 23 | } 24 | 25 | void getWorldTransform(btTransform &worldTrans) const { worldTrans = m_worldTrans; } // FYI: Bullet calls this ONLY when we're a kinematic object. 26 | void setWorldTransform(const btTransform &worldTrans) { m_worldTrans = worldTrans; } // FYI: Bullet calls this to update the motion state if we're not a kinematic object. 27 | 28 | void getGraphicTransform(btTransform &graphTrans) const { graphTrans = m_worldTrans * m_centerOfMassOffset.inverse(); } // Bullet -> HL 29 | void setGraphicTransform(const btTransform &graphTrans) { m_worldTrans = graphTrans * m_centerOfMassOffset; } // HL -> Bullet 30 | }; 31 | 32 | class CPhysicsObject; 33 | class IObjectEventListener { 34 | public: 35 | virtual void ObjectDestroyed(CPhysicsObject *pObject) {} 36 | }; 37 | 38 | class CPhysicsObject : public IPhysicsObject32 { 39 | public: 40 | CPhysicsObject(); 41 | ~CPhysicsObject(); 42 | 43 | bool IsStatic() const; 44 | bool IsAsleep() const; 45 | bool IsFluid() const; 46 | bool IsHinged() const; 47 | bool IsMoveable() const; 48 | bool IsAttachedToConstraint(bool bExternalOnly) const; 49 | 50 | bool IsCollisionEnabled() const; 51 | bool IsGravityEnabled() const; 52 | bool IsDragEnabled() const; 53 | bool IsMotionEnabled() const; 54 | 55 | void EnableCollisions(bool enable); 56 | void EnableGravity(bool enable); 57 | void EnableDrag(bool enable); 58 | void EnableMotion(bool enable); 59 | 60 | void SetGameData(void *pGameData); 61 | void * GetGameData() const; 62 | void SetGameFlags(unsigned short userFlags); 63 | unsigned short GetGameFlags() const; 64 | void SetGameIndex(unsigned short gameIndex); 65 | unsigned short GetGameIndex() const; 66 | void SetCallbackFlags(unsigned short callbackflags); 67 | unsigned short GetCallbackFlags() const; 68 | 69 | void Wake(); 70 | void Sleep(); 71 | 72 | void RecheckCollisionFilter(); 73 | void RecheckContactPoints(); 74 | 75 | void SetMass(float mass); 76 | float GetMass() const; 77 | float GetInvMass() const; 78 | 79 | Vector GetInertia() const; 80 | Vector GetInvInertia() const; 81 | void SetInertia(const Vector &inertia); 82 | 83 | void SetLocalGravity(const Vector &gravityVector); 84 | Vector GetLocalGravity() const; 85 | 86 | void SetDamping(const float *speed, const float *rot); 87 | void GetDamping(float *speed, float *rot) const; 88 | 89 | void SetDragCoefficient(float *pDrag, float *pAngularDrag); 90 | void SetBuoyancyRatio(float ratio); 91 | 92 | int GetMaterialIndex() const; 93 | void SetMaterialIndex(int materialIndex); 94 | 95 | unsigned int GetContents() const; 96 | void SetContents(unsigned int contents); 97 | 98 | void SetSleepThresholds(const float *linVel, const float *angVel); 99 | void GetSleepThresholds(float *linVel, float *angVel) const; 100 | 101 | float GetSphereRadius() const; 102 | float GetEnergy() const; 103 | Vector GetMassCenterLocalSpace() const; 104 | 105 | void SetPosition(const Vector &worldPosition, const QAngle &angles, bool isTeleport); 106 | void SetPositionMatrix(const matrix3x4_t&matrix, bool isTeleport); 107 | void GetPosition(Vector *worldPosition, QAngle *angles) const; 108 | void GetPositionMatrix(matrix3x4_t *positionMatrix) const; 109 | 110 | void SetVelocity(const Vector *velocity, const AngularImpulse *angularVelocity); 111 | void SetVelocityInstantaneous(const Vector *velocity, const AngularImpulse *angularVelocity); 112 | void GetVelocity(Vector *velocity, AngularImpulse *angularVelocity) const; 113 | void AddVelocity(const Vector *velocity, const AngularImpulse *angularVelocity); 114 | void GetVelocityAtPoint(const Vector &worldPosition, Vector *pVelocity) const; 115 | void GetImplicitVelocity(Vector *velocity, AngularImpulse *angularVelocity) const; 116 | 117 | void LocalToWorld(Vector *worldPosition, const Vector &localPosition) const; 118 | void WorldToLocal(Vector *localPosition, const Vector &worldPosition) const; 119 | void LocalToWorldVector(Vector *worldVector, const Vector &localVector) const; 120 | void WorldToLocalVector(Vector *localVector, const Vector &worldVector) const; 121 | 122 | void ApplyForceCenter(const Vector &forceVector); 123 | void ApplyForceOffset(const Vector &forceVector, const Vector &worldPosition); 124 | void ApplyTorqueCenter(const AngularImpulse &torque); 125 | 126 | void CalculateForceOffset(const Vector &forceVector, const Vector &worldPosition, Vector *centerForce, AngularImpulse *centerTorque) const; 127 | void CalculateVelocityOffset(const Vector &forceVector, const Vector &worldPosition, Vector *centerVelocity, AngularImpulse *centerAngularVelocity) const; 128 | 129 | float CalculateLinearDrag(const Vector &unitDirection) const; 130 | float CalculateAngularDrag(const Vector &objectSpaceRotationAxis) const; 131 | 132 | bool GetContactPoint(Vector *contactPoint, IPhysicsObject **contactObject) const; 133 | 134 | void SetShadow(float maxSpeed, float maxAngularSpeed, bool allowPhysicsMovement, bool allowPhysicsRotation); 135 | void UpdateShadow(const Vector &targetPosition, const QAngle &targetAngles, bool tempDisableGravity, float timeOffset); 136 | 137 | int GetShadowPosition(Vector *position, QAngle *angles) const; 138 | IPhysicsShadowController * GetShadowController() const; 139 | void RemoveShadowController(); 140 | float ComputeShadowControl(const hlshadowcontrol_params_t ¶ms, float secondsToArrival, float dt); 141 | 142 | IPhysicsVehicleController * GetVehicleController() const; 143 | 144 | // Call this if you have recently changed the collision shape we're using (without setting a new one with SetCollide) 145 | void UpdateCollide(); 146 | 147 | const CPhysCollide * GetCollide() const; 148 | CPhysCollide * GetCollide(); 149 | void SetCollide(CPhysCollide *pCollide); 150 | 151 | const char * GetName() const; 152 | IPhysicsEnvironment32 * GetEnvironment() const; 153 | 154 | bool IsTrigger() const; 155 | void BecomeTrigger(); 156 | void RemoveTrigger(); 157 | 158 | void BecomeHinged(int localAxis); 159 | void RemoveHinged(); 160 | 161 | IPhysicsFrictionSnapshot * CreateFrictionSnapshot(); 162 | void DestroyFrictionSnapshot(IPhysicsFrictionSnapshot *pSnapshot); 163 | 164 | void OutputDebugInfo() const; 165 | 166 | // UNEXPOSED FUNCTIONS 167 | public: 168 | void Init(CPhysicsEnvironment *pEnv, btRigidBody *pObject, int materialIndex, objectparams_t *pParams, bool isStatic, bool isSphere = false); 169 | 170 | CPhysicsEnvironment * GetVPhysicsEnvironment(); 171 | btRigidBody * GetObject(); 172 | 173 | void AttachedToConstraint(CPhysicsConstraint *pConstraint); 174 | void DetachedFromConstraint(CPhysicsConstraint *pConstraint); 175 | 176 | void AttachedToController(IController *pController); 177 | void DetachedFromController(IController *pController); 178 | 179 | void AttachEventListener(IObjectEventListener *pListener); 180 | void DetachEventListener(IObjectEventListener *pListener); 181 | 182 | void AddCallbackFlags(unsigned short flag); 183 | void RemoveCallbackFlags(unsigned short flag); 184 | 185 | float GetDragInDirection(const btVector3 &direction) const; // Function is not interfaced anymore 186 | float GetAngularDragInDirection(const btVector3 &direction) const; 187 | void ComputeDragBasis(bool isStatic); 188 | 189 | float GetVolume() const { return m_fVolume; } 190 | float GetBuoyancyRatio() const { return m_fBuoyancyRatio; } // [0..1] value 191 | 192 | void TriggerObjectEntered(CPhysicsObject *pObject); 193 | void TriggerObjectExited(CPhysicsObject *pObject); 194 | 195 | btVector3 GetBullMassCenterOffset() const; 196 | 197 | int GetLastActivationState() { return m_iLastActivationState; } 198 | void SetLastActivationState(int iState) { m_iLastActivationState = iState; } 199 | 200 | CPhysicsFluidController * GetFluidController() { return m_pFluidController; } 201 | void SetFluidController(CPhysicsFluidController *controller) { m_pFluidController = controller; } 202 | 203 | void SetVehicleController(CPhysicsVehicleController *pController) { m_pVehicleController = pController; } 204 | 205 | bool IsBeingRemoved() { return m_bRemoving; } 206 | 207 | void TransferToEnvironment(CPhysicsEnvironment *pDest); 208 | 209 | private: 210 | CPhysicsEnvironment * m_pEnv; 211 | void * m_pGameData; 212 | btRigidBody * m_pObject; 213 | char * m_pName; 214 | 215 | btGhostObject * m_pGhostObject; // For triggers 216 | btGhostObjectCallback * m_pGhostCallback; 217 | 218 | unsigned int m_materialIndex; 219 | unsigned short m_callbacks; 220 | unsigned short m_gameFlags; 221 | unsigned int m_contents; 222 | unsigned short m_iGameIndex; 223 | 224 | bool m_bRemoving; // Object being removed? (in destructor or something) 225 | 226 | bool m_bIsSphere; 227 | float m_fMass; 228 | float m_fVolume; 229 | float m_fBuoyancyRatio; 230 | float m_dragCoefficient; 231 | float m_angDragCoefficient; 232 | btVector3 m_dragBasis; 233 | btVector3 m_angDragBasis; 234 | Vector m_massCenterOverride; 235 | CShadowController * m_pShadow; 236 | CPhysicsVehicleController * m_pVehicleController; 237 | CPhysicsFluidController * m_pFluidController; 238 | CUtlVector m_pConstraintVec; 239 | CUtlVector m_pControllers; 240 | CUtlVector m_pEventListeners; 241 | 242 | int m_iLastActivationState; 243 | }; 244 | 245 | CPhysicsObject *CreatePhysicsObject(CPhysicsEnvironment *pEnvironment, const CPhysCollide *pCollisionModel, int materialIndex, const Vector &position, const QAngle &angles, objectparams_t *pParams, bool isStatic); 246 | CPhysicsObject *CreatePhysicsSphere(CPhysicsEnvironment *pEnvironment, float radius, int materialIndex, const Vector &position, const QAngle &angles, objectparams_t *pParams, bool isStatic); 247 | 248 | #endif // PHYSICS_OBJECT_H 249 | -------------------------------------------------------------------------------- /src/Physics_ObjectPairHash.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | #include "Physics_ObjectPairHash.h" 3 | 4 | // memdbgon must be the last include file in a .cpp file!!! 5 | #include "tier0/memdbgon.h" 6 | 7 | /*********************************** 8 | * CLASS CPhysicsObjectPairHash 9 | ***********************************/ 10 | 11 | CPhysicsObjectPairHash::CPhysicsObjectPairHash() { 12 | for (int i = 0; i < 256; i++) 13 | m_pHashList[i] = NULL; 14 | } 15 | 16 | void CPhysicsObjectPairHash::AddObjectPair(void *pObject0, void *pObject1) { 17 | int entry = GetEntry(pObject0, pObject1); 18 | 19 | // This particular entry may have more than one hash, so find the last one. 20 | pair_hash_list *last = NULL; 21 | for (pair_hash_list *hash = m_pHashList[entry]; hash; hash = hash->next) 22 | last = hash; 23 | 24 | // Setup our hash 25 | pair_hash_list *hash = new pair_hash_list; 26 | hash->object0 = pObject0; 27 | hash->object1 = pObject1; 28 | //hash->previous = last; 29 | hash->next = NULL; 30 | 31 | // Now link ourselves up to the list. 32 | if (last) 33 | last->next = hash; 34 | else 35 | m_pHashList[entry] = hash; 36 | } 37 | 38 | void CPhysicsObjectPairHash::RemoveObjectPair(void *pObject0, void *pObject1) { 39 | int entry = GetEntry(pObject0, pObject1); 40 | 41 | pair_hash_list *next = NULL; 42 | pair_hash_list *last = NULL; 43 | 44 | for (pair_hash_list *hash = m_pHashList[entry]; hash; hash = next) { 45 | if ((hash->object0 == pObject0 || hash->object0 == pObject1) && (hash->object1 == pObject0 || hash->object1 == pObject1)) { 46 | if (last) 47 | last->next = hash->next; 48 | else 49 | m_pHashList[entry] = hash->next; 50 | 51 | //if (hash->next) 52 | // hash->next->previous = hash->previous; 53 | next = hash->next; // Fix for access violation 54 | 55 | delete hash; 56 | } else { 57 | next = hash->next; 58 | last = hash; 59 | } 60 | } 61 | } 62 | 63 | void CPhysicsObjectPairHash::RemoveAllPairsForObject(void *pObject0) { 64 | // Loop through all entries 65 | for (int i = 0; i < 256; i++) { 66 | pair_hash_list *next = NULL; 67 | pair_hash_list *last = NULL; 68 | 69 | for (pair_hash_list *hash = m_pHashList[i]; hash; hash = next) { 70 | if (hash->object0 == pObject0 || hash->object1 == pObject0) { 71 | if (last) 72 | last->next = hash->next; 73 | else 74 | m_pHashList[i] = hash->next; 75 | 76 | //if (hash->next) 77 | // hash->next->previous = hash->previous; 78 | next = hash->next; // Fix for access violation 79 | 80 | delete hash; 81 | } else { 82 | next = hash->next; 83 | last = hash; 84 | } 85 | } 86 | } 87 | } 88 | 89 | bool CPhysicsObjectPairHash::IsObjectPairInHash(void *pObject0, void *pObject1) { 90 | int entry = GetEntry(pObject0, pObject1); 91 | for (pair_hash_list *hash = m_pHashList[entry]; hash; hash = hash->next) { 92 | if ((hash->object0 == pObject0 || hash->object0 == pObject1) && (hash->object1 == pObject0 || hash->object1 == pObject1)) 93 | return true; 94 | } 95 | 96 | return false; 97 | } 98 | 99 | bool CPhysicsObjectPairHash::IsObjectInHash(void *pObject0) { 100 | for (int i = 0; i < 256; i++) { 101 | for (pair_hash_list *hash = m_pHashList[i]; hash; hash = hash->next) { 102 | if (hash->object0 == pObject0 || hash->object1 == pObject0) 103 | return true; 104 | } 105 | } 106 | 107 | return false; 108 | } 109 | 110 | int CPhysicsObjectPairHash::GetPairCountForObject(void *pObject0) { 111 | int c = 0; 112 | for (int i = 0; i < 256; i++) { 113 | for (pair_hash_list *hash = m_pHashList[i]; hash; hash = hash->next) { 114 | if (hash->object0 == pObject0 || hash->object1 == pObject0) 115 | c++; 116 | } 117 | } 118 | 119 | return c; 120 | } 121 | 122 | int CPhysicsObjectPairHash::GetPairListForObject(void *pObject0, int nMaxCount, void **ppObjectList) { 123 | int c = 0; 124 | for (int i = 0; i < 256; i++) { 125 | if (c >= nMaxCount) 126 | break; 127 | 128 | for (pair_hash_list *hash = m_pHashList[i]; hash; hash = hash->next) { 129 | if (c >= nMaxCount) 130 | break; 131 | 132 | // Get the opposite object in the pair 133 | ppObjectList[c++] = hash->object0 == pObject0 ? hash->object1 : hash->object0; 134 | } 135 | } 136 | 137 | return c; 138 | } 139 | 140 | // Purpose: Generate a number in [0,255] given 2 pointers. Must be the same for the same 2 pointers. 141 | int CPhysicsObjectPairHash::GetEntry(void *pObject0, void *pObject1) { 142 | return (((int)pObject0 ^ (int)pObject1) >> 4) & 0xFF; 143 | } -------------------------------------------------------------------------------- /src/Physics_ObjectPairHash.h: -------------------------------------------------------------------------------- 1 | #ifndef PHYSICS_OBJECTPAIRHASH_H 2 | #define PHYSICS_OBJECTPAIRHASH_H 3 | #if defined(_MSC_VER) || (defined(__GNUC__) && __GNUC__ > 3) 4 | #pragma once 5 | #endif 6 | 7 | #include 8 | 9 | struct pair_hash_list { 10 | void *object0; 11 | void *object1; 12 | 13 | pair_hash_list *next; 14 | }; 15 | 16 | class CPhysicsObjectPairHash : public IPhysicsObjectPairHash { 17 | public: 18 | CPhysicsObjectPairHash(); 19 | 20 | void AddObjectPair(void *pObject0, void *pObject1); 21 | void RemoveObjectPair(void *pObject0, void *pObject1); 22 | bool IsObjectPairInHash(void *pObject0, void *pObject1); 23 | void RemoveAllPairsForObject(void *pObject0); 24 | bool IsObjectInHash(void *pObject0); 25 | 26 | int GetPairCountForObject(void *pObject0); 27 | int GetPairListForObject(void *pObject0, int nMaxCount, void **ppObjectList); 28 | 29 | int GetEntry(void *pObject0, void *pObject1); 30 | 31 | private: 32 | pair_hash_list *m_pHashList[256]; 33 | }; 34 | 35 | #endif // PHYSICS_OBJECTPAIRHASH_H 36 | -------------------------------------------------------------------------------- /src/Physics_PlayerController.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | 3 | #include "Physics_PlayerController.h" 4 | #include "Physics_Object.h" 5 | #include "Physics_Environment.h" 6 | #include "convert.h" 7 | #include "miscmath.h" 8 | 9 | // memdbgon must be the last include file in a .cpp file!!! 10 | #include "tier0/memdbgon.h" 11 | 12 | void ComputeController(btVector3 ¤tSpeed, const btVector3 &delta, const btVector3 &maxSpeed, float scaleDelta, float damping, btVector3 *accelOut) { 13 | // Timestep scale 14 | btVector3 acceleration = delta * scaleDelta; 15 | 16 | if (currentSpeed.fuzzyZero() && !currentSpeed.isZero()) { 17 | currentSpeed.setZero(); 18 | } 19 | acceleration += currentSpeed * -damping; 20 | 21 | // Clamp the acceleration to max speed 22 | for (int i = 2; i >= 0; i--) { 23 | if (fabs(acceleration[i]) < maxSpeed[i]) continue; 24 | acceleration[i] = (acceleration[i] < 0) ? -maxSpeed[i] : maxSpeed[i]; 25 | } 26 | 27 | currentSpeed += acceleration; 28 | 29 | if (accelOut) { 30 | *accelOut = acceleration; 31 | } 32 | } 33 | 34 | /**************************** 35 | * CLASS CPlayerController 36 | ****************************/ 37 | 38 | CPlayerController::CPlayerController(CPhysicsEnvironment *pEnv, CPhysicsObject *pObject) { 39 | m_pObject = pObject; 40 | m_pGround = NULL; 41 | m_pEnv = pEnv; 42 | m_handler = NULL; 43 | m_maxDeltaPosition = ConvertDistanceToBull(24); 44 | m_dampFactor = 1.f; 45 | m_ticksSinceUpdate = 0; 46 | m_lastImpulse = btVector3(0, 0, 0); 47 | m_secondsToArrival = 0; 48 | 49 | AttachObject(); 50 | } 51 | 52 | CPlayerController::~CPlayerController() { 53 | DetachObject(); 54 | } 55 | 56 | // FIXME: Jumping does not work because as soon as the player leaves the object, the target position delta is exactly 57 | // zero and his velocity gets completely emptied! 58 | void CPlayerController::Update(const Vector &position, const Vector &velocity, float secondsToArrival, bool onground, IPhysicsObject *pGround) { 59 | btVector3 bullTargetPosition, bullMaxVelocity; 60 | 61 | ConvertPosToBull(position, bullTargetPosition); 62 | ConvertPosToBull(velocity, bullMaxVelocity); 63 | 64 | // Reset the ticks since update counter 65 | m_ticksSinceUpdate = 0; 66 | 67 | // If the targets haven't changed, abort. 68 | if (bullMaxVelocity.distance2(m_maxVelocity) < FLT_EPSILON && bullTargetPosition.distance2(m_targetPosition) < FLT_EPSILON) { 69 | return; 70 | } 71 | 72 | // FIXME: If we're walking on a physics object, the game's input position DOES NOT FACTOR IN the base velocity of the 73 | // physics object! 74 | // Target position is just the target velocity integrated into our current position via the timestep 75 | m_targetPosition = bullTargetPosition; 76 | m_maxVelocity = bullMaxVelocity; 77 | 78 | // FYI: The onground stuff includes any props we may be standing on as well as the world. 79 | // The ground object is non-NULL only if it's significantly heavier than our object ("Rideable physics" > our mass * 2) 80 | m_onground = onground; 81 | 82 | m_enable = true; 83 | if (velocity.LengthSqr() <= 0.1f) { 84 | m_enable = false; // No input velocity, just go where physics takes you 85 | pGround = NULL; 86 | } else { 87 | MaxSpeed(velocity); 88 | } 89 | 90 | ConvertPosToBull(velocity, m_inputVelocity); 91 | 92 | m_secondsToArrival = secondsToArrival; 93 | 94 | // Detach ourselves from any existing ground 95 | if (m_pGround) 96 | m_pGround->DetachEventListener(this); 97 | 98 | m_pGround = (CPhysicsObject *)pGround; 99 | 100 | if (m_pGround) { 101 | // Attach ourself to the ground so we can listen to see if it gets destroyed 102 | m_pGround->AttachEventListener(this); 103 | 104 | // Where we are relative to the ground 105 | m_groundPos = m_pGround->GetObject()->getWorldTransform().inverse() * m_targetPosition; 106 | } 107 | } 108 | 109 | void CPlayerController::SetEventHandler(IPhysicsPlayerControllerEvent *handler) { 110 | m_handler = handler; 111 | } 112 | 113 | bool CPlayerController::IsInContact() { 114 | btDispatcher *pDispatcher = m_pEnv->GetBulletEnvironment()->getDispatcher(); 115 | 116 | int numManifolds = pDispatcher->getNumManifolds(); 117 | for (int i = 0; i < numManifolds; i++) { 118 | btPersistentManifold *contactManifold = pDispatcher->getManifoldByIndexInternal(i); 119 | const btCollisionObject *obA = contactManifold->getBody0(); 120 | const btCollisionObject *obB = contactManifold->getBody1(); 121 | CPhysicsObject *pPhysUs = NULL; 122 | CPhysicsObject *pPhysOther = NULL; 123 | 124 | if (contactManifold->getNumContacts() > 0 && (obA == m_pObject->GetObject() || obB == m_pObject->GetObject())) { 125 | if (obA == m_pObject->GetObject()) { 126 | pPhysUs = (CPhysicsObject *)obA->getUserPointer(); 127 | pPhysOther = (CPhysicsObject *)obB->getUserPointer(); 128 | } else if (obB == m_pObject->GetObject()) { 129 | pPhysUs = (CPhysicsObject *)obB->getUserPointer(); 130 | pPhysOther = (CPhysicsObject *)obA->getUserPointer(); 131 | } 132 | 133 | // If it's static or controlled by the game 134 | if (pPhysOther->IsStatic() || !pPhysOther->IsMotionEnabled() || (pPhysOther->GetCallbackFlags() & CALLBACK_SHADOW_COLLISION)) 135 | continue; 136 | 137 | return true; 138 | } 139 | } 140 | 141 | return false; 142 | } 143 | 144 | // Purpose: Calculate the maximum speed we can accelerate. 145 | void CPlayerController::MaxSpeed(const Vector &hlMaxVelocity) { 146 | btVector3 maxVel; 147 | ConvertPosToBull(hlMaxVelocity, maxVel); 148 | btVector3 available = maxVel; 149 | 150 | float maxVelLen = maxVel.length(); 151 | maxVel.normalize(); 152 | 153 | // Only if we're headed in the same direction as maxVelocity 154 | float dot = maxVel.dot(m_pObject->GetObject()->getLinearVelocity()); // Magnitude of our speed in the same direction as maxVel 155 | if (dot > 0) { 156 | maxVel *= dot * maxVelLen; // maxVel(normalized) *= dot(maxVel(norm), linVel) * len(maxVel) 157 | available -= maxVel; // Now subtract the magnitude of our current speed along the maxVelocity vector 158 | } 159 | 160 | m_maxSpeed = available.absolute(); 161 | } 162 | 163 | // Called when the game wants to swap hulls (such as from standing to crouching) 164 | void CPlayerController::SetObject(IPhysicsObject *pObject) { 165 | if (pObject == m_pObject) 166 | return; 167 | 168 | // HACK: Freeze our current object (so it doesn't fall through the world and create nastiness when the AABB overflows) 169 | m_pObject->EnableMotion(false); 170 | 171 | DetachObject(); 172 | m_pObject = (CPhysicsObject *)pObject; 173 | AttachObject(); 174 | 175 | // Enable motion for our new object (which was probably previously frozen by the above code) 176 | m_pObject->EnableMotion(true); 177 | } 178 | 179 | // Amazing! It absolutely does not matter what values we return here (except for the return value) 180 | // The one implementation in the 2013 SDK that calls this discards the position we return! 181 | // Also the angles parameter is unused because our controller cannot rotate 182 | int CPlayerController::GetShadowPosition(Vector *position, QAngle *angles) { 183 | btRigidBody *pObject = m_pObject->GetObject(); 184 | 185 | btTransform transform; 186 | ((btMassCenterMotionState *)pObject->getMotionState())->getGraphicTransform(transform); 187 | 188 | if (position) ConvertPosToHL(transform.getOrigin(), *position); 189 | if (angles) ConvertRotationToHL(transform.getBasis(), *angles); 190 | 191 | // Yep. We're returning a variable totally unrelated to the shadow's position. 192 | // Returns whether the physics object was updated this frame or not 193 | return 1; 194 | } 195 | 196 | void CPlayerController::GetShadowVelocity(Vector *velocity) { 197 | if (!velocity) return; 198 | 199 | btRigidBody *body = m_pObject->GetObject(); 200 | btVector3 linVel = body->getLinearVelocity(); 201 | 202 | // Velocity is relative to the ground velocity 203 | if (m_pGround) { 204 | linVel -= m_pGround->GetObject()->getVelocityInLocalPoint(m_groundPos); 205 | } 206 | 207 | ConvertPosToHL(linVel, *velocity); 208 | } 209 | 210 | void CPlayerController::StepUp(float height) { 211 | btVector3 step; 212 | ConvertPosToBull(Vector(0, 0, height), step); 213 | 214 | btRigidBody *pObject = m_pObject->GetObject(); 215 | btTransform transform = pObject->getWorldTransform(); 216 | transform.setOrigin(transform.getOrigin() + step); 217 | 218 | pObject->getMotionState()->setWorldTransform(transform); 219 | } 220 | 221 | void CPlayerController::Jump() { 222 | // This function does absolutely nothing! 223 | return; 224 | } 225 | 226 | IPhysicsObject *CPlayerController::GetObject() { 227 | return m_pObject; 228 | } 229 | 230 | void CPlayerController::GetLastImpulse(Vector *pOut) { 231 | if (!pOut) return; 232 | 233 | ConvertForceImpulseToHL(m_lastImpulse, *pOut); 234 | } 235 | 236 | // Purpose: Loop through all of our contact points and see if we're standing on ground anywhere 237 | // Returns NULL if we're not standing on ground or if we're standing on a static/frozen object (or game physics object) 238 | CPhysicsObject *CPlayerController::GetGroundObject() { 239 | btDispatcher *pDispatcher = m_pEnv->GetBulletEnvironment()->getDispatcher(); 240 | 241 | // Loop through the collision pair manifolds 242 | int numManifolds = pDispatcher->getNumManifolds(); 243 | for (int i = 0; i < numManifolds; i++) { 244 | btPersistentManifold *pManifold = pDispatcher->getManifoldByIndexInternal(i); 245 | if (pManifold->getNumContacts() <= 0) 246 | continue; 247 | 248 | const btCollisionObject *objA = pManifold->getBody0(); 249 | const btCollisionObject *objB = pManifold->getBody1(); 250 | 251 | // Skip if one object is static/kinematic 252 | if (objA->isStaticOrKinematicObject() || objB->isStaticOrKinematicObject()) 253 | continue; 254 | 255 | CPhysicsObject *pPhysA = (CPhysicsObject *)objA->getUserPointer(); 256 | CPhysicsObject *pPhysB = (CPhysicsObject *)objB->getUserPointer(); 257 | 258 | // Collision that involves us! 259 | if (objA == m_pObject->GetObject() || objB == m_pObject->GetObject()) { 260 | int ourID = m_pObject->GetObject() == objA ? 0 : 1; 261 | 262 | for (int i = 0; i < pManifold->getNumContacts(); i++) { 263 | btManifoldPoint &point = pManifold->getContactPoint(i); 264 | 265 | btVector3 norm = point.m_normalWorldOnB; // Normal worldspace A->B 266 | if (ourID == 1) { 267 | // Flip it because we're object B and we need norm B->A. 268 | norm *= -1; 269 | } 270 | 271 | // HACK: Guessing which way is up (as currently defined in our implementation y is up) 272 | // If the normal is up enough then assume it's some sort of ground 273 | if (norm.y() > 0.8) { 274 | return ourID == 0 ? pPhysB : pPhysA; 275 | } 276 | } 277 | } 278 | } 279 | 280 | return NULL; 281 | } 282 | 283 | void CPlayerController::Tick(float deltaTime) { 284 | if (!m_enable) 285 | return; 286 | 287 | // HACK: Only run this controller once per step (until I can figure out the math to fix per-tick simulation) 288 | if (m_pEnv->GetCurSubStep() != 0) 289 | return; 290 | deltaTime *= m_pEnv->GetNumSubSteps(); 291 | 292 | btRigidBody *body = m_pObject->GetObject(); 293 | btMassCenterMotionState *motionState = (btMassCenterMotionState *)body->getMotionState(); 294 | 295 | // Don't let the player controller travel too far away from the target position. 296 | btTransform transform; 297 | motionState->getGraphicTransform(transform); 298 | btVector3 delta_position = m_targetPosition - transform.getOrigin(); 299 | 300 | btScalar qdist = delta_position.length2(); 301 | if (qdist > m_maxDeltaPosition * m_maxDeltaPosition && TryTeleportObject()) { 302 | // Teleported the controller, so no need to calculate velocity 303 | return; 304 | } 305 | 306 | CalculateVelocity(deltaTime); 307 | 308 | m_ticksSinceUpdate++; 309 | } 310 | 311 | void CPlayerController::CalculateVelocity(float dt) { 312 | btRigidBody *body = m_pObject->GetObject(); 313 | 314 | // Fraction of the movement we need to complete this tick 315 | float fraction = 1.f; 316 | if (m_secondsToArrival > 0) { 317 | fraction = dt / m_secondsToArrival; 318 | if (fraction > 1) fraction = 1; 319 | } 320 | 321 | // FIXME: We're trying to do a move in too small of a timespan, so the move completes this tick 322 | // but it needed a crazy high velocity to work. 323 | float scale = SAFE_DIVIDE(fraction, dt); 324 | 325 | m_secondsToArrival -= dt; 326 | if (m_secondsToArrival < 0) m_secondsToArrival = 0; 327 | 328 | // Float to allow stepping 329 | btVector3 gravDt = m_pEnv->GetBulletEnvironment()->getGravity() * dt; 330 | if (m_onground) { 331 | body->setLinearVelocity(body->getLinearVelocity() - gravDt); 332 | } 333 | 334 | btTransform transform; 335 | ((btMassCenterMotionState *)body->getMotionState())->getGraphicTransform(transform); 336 | btVector3 deltaPos = m_targetPosition - transform.getOrigin(); 337 | 338 | btVector3 baseVelocity(0); 339 | 340 | // Are we walking on some sort of vphysics ground? Add their velocity in as a base then 341 | // because the game doesn't do this for us! 342 | CPhysicsObject *pGround = GetGroundObject(); 343 | if (pGround) { 344 | btTransform relTrans = pGround->GetObject()->getWorldTransform().inverse() * m_pObject->GetObject()->getWorldTransform(); 345 | btVector3 relPos = relTrans.getOrigin(); 346 | 347 | baseVelocity = pGround->GetObject()->getVelocityInLocalPoint(relPos); 348 | } 349 | 350 | btVector3 linVel = body->getLinearVelocity() - baseVelocity; 351 | if (m_ticksSinceUpdate == 0) { 352 | // TODO: We're applying too high acceleration when we get closer to the target position! 353 | ComputeController(linVel, deltaPos, m_maxSpeed, scale, m_dampFactor, &m_lastImpulse); 354 | } else { 355 | btScalar len = m_lastImpulse.length(); 356 | btVector3 limit(len, len, len); 357 | 358 | ComputeController(linVel, deltaPos, limit, scale, m_dampFactor); 359 | } 360 | 361 | // TODO: Clamp the velocity based on collisions (using variables such as push max mass, max speed etc) 362 | // btScalar velLen = linVel.length2(); 363 | 364 | body->setLinearVelocity(linVel + baseVelocity); 365 | } 366 | 367 | bool CPlayerController::TryTeleportObject() { 368 | if (m_handler) { 369 | Vector hlPosition; 370 | ConvertPosToHL(m_targetPosition, hlPosition); 371 | if (!m_handler->ShouldMoveTo(m_pObject, hlPosition)) return false; 372 | } 373 | 374 | btRigidBody *body = m_pObject->GetObject(); 375 | 376 | btTransform trans = body->getWorldTransform(); 377 | trans.setOrigin(m_targetPosition); 378 | 379 | body->setWorldTransform(trans * ((btMassCenterMotionState *)body->getMotionState())->m_centerOfMassOffset); 380 | ((btMassCenterMotionState *)body->getMotionState())->setGraphicTransform(trans); 381 | 382 | // Kill the velocity 383 | body->setLinearVelocity(btVector3(0)); 384 | 385 | return true; 386 | } 387 | 388 | void CPlayerController::ObjectDestroyed(CPhysicsObject *pObject) { 389 | if (pObject == m_pObject) 390 | DetachObject(); 391 | else if (pObject == m_pGround) 392 | m_pGround = NULL; 393 | 394 | Assert(0); // Object isn't related to us, why are we getting this notification? 395 | } 396 | 397 | void CPlayerController::AttachObject() { 398 | btRigidBody *body = btRigidBody::upcast(m_pObject->GetObject()); 399 | m_saveRot = body->getAngularFactor(); 400 | body->setAngularFactor(0); 401 | 402 | m_pObject->AddCallbackFlags(CALLBACK_IS_PLAYER_CONTROLLER); 403 | 404 | body->setActivationState(DISABLE_DEACTIVATION, true); 405 | } 406 | 407 | void CPlayerController::DetachObject() { 408 | btRigidBody *body = btRigidBody::upcast(m_pObject->GetObject()); 409 | body->setAngularFactor(m_saveRot); 410 | body->setActivationState(ACTIVE_TAG, true); 411 | 412 | m_pObject->RemoveCallbackFlags(CALLBACK_IS_PLAYER_CONTROLLER); 413 | 414 | m_pObject = NULL; 415 | } 416 | 417 | void CPlayerController::SetPushMassLimit(float maxPushMass) { 418 | m_pushMassLimit = maxPushMass; 419 | } 420 | 421 | void CPlayerController::SetPushSpeedLimit(float maxPushSpeed) { 422 | m_pushSpeedLimit = maxPushSpeed; 423 | } 424 | 425 | float CPlayerController::GetPushMassLimit() { 426 | return m_pushMassLimit; 427 | } 428 | 429 | float CPlayerController::GetPushSpeedLimit() { 430 | return m_pushSpeedLimit; 431 | } 432 | 433 | bool CPlayerController::WasFrozen() { 434 | // Appears that if we were frozen, the game will try and update our position to the player's current position. 435 | // Probably used for when the controller object is frozen due to performance limits (max collisions per timestep, etc) 436 | // TODO: Implement this if we ever implement performance limitations 437 | 438 | //NOT_IMPLEMENTED 439 | return false; 440 | } 441 | 442 | /*********************** 443 | * CREATION FUNCTIONS 444 | ***********************/ 445 | 446 | CPlayerController *CreatePlayerController(CPhysicsEnvironment *pEnv, IPhysicsObject *pObject) { 447 | if (!pObject) return NULL; 448 | 449 | return new CPlayerController(pEnv, (CPhysicsObject *)pObject); 450 | } 451 | -------------------------------------------------------------------------------- /src/Physics_PlayerController.h: -------------------------------------------------------------------------------- 1 | #ifndef PHYSICS_PLAYERCONTROLLER_H 2 | #define PHYSICS_PLAYERCONTROLLER_H 3 | #if defined(_MSC_VER) || (defined(__GNUC__) && __GNUC__ > 3) 4 | #pragma once 5 | #endif 6 | 7 | #include 8 | #include "IController.h" 9 | 10 | #include "Physics_Object.h" 11 | 12 | class CPhysicsEnvironment; 13 | class CPhysicsObject; 14 | class IPhysicsObject; 15 | 16 | class CPlayerControllerEventListener; 17 | 18 | class CPlayerController : public IController, public IPhysicsPlayerController, public IObjectEventListener 19 | { 20 | public: 21 | CPlayerController(CPhysicsEnvironment *pEnv, CPhysicsObject *pObject); 22 | ~CPlayerController(); 23 | 24 | void Update(const Vector &position, const Vector &velocity, float secondsToArrival, bool onground, IPhysicsObject *ground); 25 | void SetEventHandler(IPhysicsPlayerControllerEvent *handler); 26 | bool IsInContact(); 27 | void MaxSpeed(const Vector &maxVelocity); 28 | 29 | void SetObject(IPhysicsObject *pObject); 30 | int GetShadowPosition(Vector *position, QAngle *angles); 31 | void StepUp(float height); 32 | void Jump(); 33 | void GetShadowVelocity(Vector *velocity); 34 | IPhysicsObject * GetObject(); 35 | void GetLastImpulse(Vector *pOut); 36 | 37 | void SetPushMassLimit(float maxPushMass); 38 | void SetPushSpeedLimit(float maxPushSpeed); 39 | 40 | float GetPushMassLimit(); 41 | float GetPushSpeedLimit(); 42 | bool WasFrozen(); 43 | 44 | // Unexposed functions 45 | public: 46 | CPhysicsObject * GetGroundObject(); 47 | 48 | void Tick(float deltaTime); 49 | void ObjectDestroyed(CPhysicsObject *pObject); 50 | 51 | private: 52 | void AttachObject(); 53 | void DetachObject(); 54 | bool TryTeleportObject(); 55 | 56 | void CalculateVelocity(float dt); 57 | 58 | bool m_enable; 59 | 60 | bool m_onground; 61 | CPhysicsObject * m_pGround; 62 | btVector3 m_groundPos; 63 | 64 | CPhysicsObject * m_pObject; 65 | CPhysicsEnvironment * m_pEnv; 66 | btVector3 m_saveRot; 67 | IPhysicsPlayerControllerEvent * m_handler; 68 | float m_maxDeltaPosition; 69 | float m_dampFactor; 70 | float m_secondsToArrival; 71 | btVector3 m_maxSpeed; // Maximum acceleration speed. 72 | btVector3 m_currentSpeed; 73 | btVector3 m_lastImpulse; 74 | btVector3 m_inputVelocity; 75 | 76 | float m_pushMassLimit; 77 | float m_pushSpeedLimit; 78 | 79 | btVector3 m_targetPosition; 80 | btVector3 m_maxVelocity; 81 | 82 | int m_ticksSinceUpdate; 83 | }; 84 | 85 | void ComputeController(btVector3 ¤tSpeed, const btVector3 &delta, const btVector3 &maxSpeed, float scaleDelta, float damping, btVector3 *accelOut = NULL); 86 | 87 | CPlayerController *CreatePlayerController(CPhysicsEnvironment *pEnv, IPhysicsObject *pObject); 88 | 89 | #endif // PHYSICS_PLAYERCONTROLLER_H 90 | -------------------------------------------------------------------------------- /src/Physics_ShadowController.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | 3 | #include "Physics_Environment.h" 4 | #include "Physics_ShadowController.h" 5 | #include "Physics_PlayerController.h" 6 | #include "Physics_Object.h" 7 | #include "Physics_SurfaceProps.h" 8 | 9 | #include "convert.h" 10 | #include "miscmath.h" 11 | 12 | #include 13 | 14 | // memdbgon must be the last include file in a .cpp file!!! 15 | #include "tier0/memdbgon.h" 16 | 17 | float ComputeShadowControllerBull(btRigidBody *object, shadowcontrol_params_t ¶ms, float secondsToArrival, float dt) { 18 | // Fraction of the movement we need to complete by this tick 19 | float fraction = 1; 20 | if (secondsToArrival > 0) { 21 | fraction = dt / secondsToArrival; 22 | if (fraction > 1) fraction = 1; 23 | } 24 | 25 | secondsToArrival -= dt; 26 | if (secondsToArrival < 0) secondsToArrival = 0; 27 | 28 | if (fraction <= 0) return secondsToArrival; 29 | float scale = SAFE_DIVIDE(fraction, dt); 30 | 31 | btTransform transform = object->getWorldTransform(); 32 | transform *= ((btMassCenterMotionState *)object->getMotionState())->m_centerOfMassOffset.inverse(); 33 | 34 | //------------------- 35 | // Translation 36 | //------------------- 37 | 38 | btVector3 posbull = transform.getOrigin(); 39 | btVector3 delta_position = params.targetPosition - posbull; 40 | 41 | // Teleportation 42 | // If our distance is greater than teleport distance, teleport instead. 43 | if (params.teleportDistance > 0) { 44 | btScalar qdist; 45 | if (!params.lastPosition.isZero()) { 46 | btVector3 tmpDelta = posbull - params.lastPosition; 47 | qdist = tmpDelta.length2(); 48 | } else { 49 | qdist = delta_position.length2(); 50 | } 51 | 52 | if (qdist > params.teleportDistance * params.teleportDistance) { 53 | transform.setOrigin(params.targetPosition); 54 | transform.setRotation(params.targetRotation); 55 | object->setWorldTransform(transform * ((btMassCenterMotionState *)object->getMotionState())->m_centerOfMassOffset); 56 | } 57 | } 58 | 59 | btVector3 speed = object->getLinearVelocity(); 60 | ComputeController(speed, delta_position, btVector3(params.maxSpeed, params.maxSpeed, params.maxSpeed), scale, params.dampFactor); 61 | object->setLinearVelocity(speed); 62 | 63 | params.lastPosition = posbull + (speed * dt); 64 | 65 | //------------------- 66 | // Rotation 67 | //------------------- 68 | 69 | btVector3 axis; 70 | btScalar angle; 71 | btTransformUtil::calculateDiffAxisAngleQuaternion(transform.getRotation(), params.targetRotation, axis, angle); 72 | 73 | // So we don't end up having a huge delta angle (such as instead of doing 379 deg turn, do a -1 deg turn) 74 | if (angle > M_PI) { 75 | angle -= btScalar(2 * M_PI); 76 | } 77 | 78 | btVector3 deltaAngles = axis * angle; 79 | btVector3 rot_speed = object->getAngularVelocity(); 80 | ComputeController(rot_speed, deltaAngles, btVector3(params.maxAngular, params.maxAngular, params.maxAngular), scale, params.dampFactor); 81 | object->setAngularVelocity(rot_speed); 82 | 83 | object->activate(); 84 | 85 | return secondsToArrival; 86 | } 87 | 88 | void ConvertShadowControllerToBull(const hlshadowcontrol_params_t &in, shadowcontrol_params_t &out) { 89 | ConvertPosToBull(in.targetPosition, out.targetPosition); 90 | ConvertRotationToBull(in.targetRotation, out.targetRotation); 91 | out.teleportDistance = ConvertDistanceToBull(in.teleportDistance); 92 | 93 | out.maxSpeed = ConvertDistanceToBull(in.maxSpeed); 94 | out.maxDampSpeed = ConvertDistanceToBull(in.maxDampSpeed); 95 | out.maxAngular = ConvertAngleToBull(in.maxAngular); 96 | out.maxDampAngular = ConvertAngleToBull(in.maxDampAngular); 97 | out.dampFactor = in.dampFactor; 98 | } 99 | 100 | float ComputeShadowControllerHL(CPhysicsObject *pObject, const hlshadowcontrol_params_t ¶ms, float secondsToArrival, float dt) { 101 | shadowcontrol_params_t bullParams; 102 | ConvertShadowControllerToBull(params, bullParams); 103 | return ComputeShadowControllerBull(pObject->GetObject(), bullParams, secondsToArrival, dt); 104 | } 105 | 106 | static bool IsEqual(const btQuaternion &pt0, const btQuaternion &pt1a) { 107 | btQuaternion pt1 = pt0.nearest(pt1a); 108 | 109 | btScalar dot = pt0.normalized().dot(pt1.normalized()); 110 | return dot >= 1 - SIMD_EPSILON || dot <= -1 + SIMD_EPSILON; 111 | } 112 | 113 | static bool IsEqual(const btVector3 &pt0, const btVector3 &pt1) { 114 | return pt0.distance2(pt1) < 1e-8f; 115 | } 116 | 117 | /*************************** 118 | * CLASS CShadowController 119 | ***************************/ 120 | 121 | CShadowController::CShadowController(CPhysicsObject *pObject, bool allowTranslation, bool allowRotation) { 122 | m_pObject = pObject; 123 | m_shadow.dampFactor = 1.0f; 124 | m_shadow.teleportDistance = 0; 125 | m_shadow.targetPosition.setZero(); 126 | m_shadow.targetRotation = btQuaternion::getIdentity(); 127 | m_flags = 0; 128 | m_ticksSinceUpdate = 0; 129 | 130 | SetAllowsTranslation(allowTranslation); 131 | SetAllowsRotation(allowRotation); 132 | AttachObject(); 133 | } 134 | 135 | CShadowController::~CShadowController() { 136 | DetachObject(); 137 | } 138 | 139 | // UNEXPOSED 140 | void CShadowController::Tick(float deltaTime) { 141 | if (m_enable) { 142 | if (IsPhysicallyControlled()) { 143 | ComputeShadowControllerBull(m_pObject->GetObject(), m_shadow, m_secondsToArrival, deltaTime); 144 | m_secondsToArrival -= deltaTime; 145 | if (m_secondsToArrival < 0) m_secondsToArrival = 0; 146 | } else { 147 | // TODO: Need to use secondsToArrival 148 | 149 | btTransform target(m_shadow.targetRotation, m_shadow.targetPosition); 150 | target *= ((btMassCenterMotionState *)m_pObject->GetObject()->getMotionState())->m_centerOfMassOffset; 151 | m_pObject->GetObject()->setWorldTransform(target); 152 | } 153 | } else { 154 | m_shadow.lastPosition.setZero(); 155 | } 156 | 157 | m_ticksSinceUpdate++; 158 | } 159 | 160 | void CShadowController::ObjectDestroyed(CPhysicsObject *pObject) { 161 | if (pObject == m_pObject) 162 | DetachObject(); 163 | } 164 | 165 | void CShadowController::Update(const Vector &position, const QAngle &angles, float timeOffset) { 166 | btVector3 targetPosition = m_shadow.targetPosition; 167 | btQuaternion targetRotation = m_shadow.targetRotation; 168 | 169 | ConvertPosToBull(position, m_shadow.targetPosition); 170 | ConvertRotationToBull(angles, m_shadow.targetRotation); 171 | m_secondsToArrival = timeOffset < 0 ? 0 : timeOffset; 172 | 173 | m_enable = true; 174 | m_timeOffset = timeOffset; 175 | m_ticksSinceUpdate = 0; 176 | 177 | if (IsEqual(targetPosition, m_shadow.targetPosition) && IsEqual(targetRotation, m_shadow.targetRotation)) return; 178 | 179 | //m_pObject->Wake(); 180 | } 181 | 182 | void CShadowController::MaxSpeed(float maxSpeed, float maxAngularSpeed) { 183 | btRigidBody *body = m_pObject->GetObject(); 184 | 185 | //---------------- 186 | // Linear 187 | //---------------- 188 | 189 | btVector3 bullSpeed; 190 | ConvertPosToBull(Vector(maxSpeed), bullSpeed); 191 | btVector3 available = bullSpeed; 192 | 193 | // m_currentSpeed = bullSpeed; 194 | 195 | float length = bullSpeed.length(); 196 | bullSpeed.normalize(); 197 | 198 | float dot = bullSpeed.dot(body->getLinearVelocity()); 199 | if (dot > 0) { 200 | bullSpeed *= dot * length; 201 | available -= bullSpeed; 202 | } 203 | 204 | // FIXME: This is wrong. Rewrite this later. 205 | m_shadow.maxSpeed = available.length(); 206 | 207 | //---------------- 208 | // Angular 209 | //---------------- 210 | 211 | btVector3 bullAngular; 212 | ConvertAngularImpulseToBull(Vector(maxAngularSpeed), bullAngular); 213 | btVector3 availableAngular; 214 | 215 | float lengthAngular = bullAngular.length(); 216 | bullAngular.normalize(); 217 | 218 | float dotAngular = bullAngular.dot(body->getAngularVelocity()); 219 | if (dotAngular > 0) { 220 | bullAngular *= dotAngular * lengthAngular; 221 | availableAngular -= bullAngular; 222 | } 223 | 224 | // FIXME: This is wrong. Rewrite this later. 225 | m_shadow.maxAngular = availableAngular.length(); 226 | } 227 | 228 | void CShadowController::StepUp(float height) { 229 | btVector3 step; 230 | ConvertPosToBull(Vector(0, 0, height), step); 231 | 232 | btRigidBody *pObject = m_pObject->GetObject(); 233 | btTransform transform = pObject->getWorldTransform(); 234 | transform.setOrigin(transform.getOrigin() + step); 235 | 236 | pObject->setWorldTransform(transform); 237 | } 238 | 239 | void CShadowController::SetTeleportDistance(float teleportDistance) { 240 | m_shadow.teleportDistance = ConvertDistanceToBull(teleportDistance); 241 | } 242 | 243 | bool CShadowController::AllowsTranslation() { 244 | return (m_flags & FLAG_ALLOWPHYSICSMOVEMENT) != 0; 245 | } 246 | 247 | bool CShadowController::AllowsRotation() { 248 | return (m_flags & FLAG_ALLOWPHYSICSROTATION) != 0; 249 | } 250 | 251 | // There are two classes of shadow objects: 252 | // 1) Game physics controlled, shadow follows game physics (this is the default) 253 | // 2) Physically controlled - shadow position is a target, but the game hasn't guaranteed that the space can be occupied by this object 254 | bool CShadowController::IsPhysicallyControlled() { 255 | return (m_flags & FLAG_PHYSICALLYCONTROLLED) != 0; 256 | } 257 | 258 | void CShadowController::SetAllowsTranslation(bool enable) { 259 | enable ? m_flags |= FLAG_ALLOWPHYSICSMOVEMENT : m_flags &= ~(FLAG_ALLOWPHYSICSMOVEMENT); 260 | } 261 | 262 | void CShadowController::SetAllowsRotation(bool enable) { 263 | enable ? m_flags |= FLAG_ALLOWPHYSICSROTATION : m_flags &= ~(FLAG_ALLOWPHYSICSROTATION); 264 | } 265 | 266 | void CShadowController::SetPhysicallyControlled(bool enable) { 267 | if (IsPhysicallyControlled() == enable) 268 | return; 269 | 270 | if (enable) { 271 | m_flags |= FLAG_PHYSICALLYCONTROLLED; 272 | 273 | btRigidBody *body = m_pObject->GetObject(); 274 | body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); 275 | } else { 276 | m_flags &= ~(FLAG_PHYSICALLYCONTROLLED); 277 | 278 | btRigidBody *body = m_pObject->GetObject(); 279 | body->setCollisionFlags(body->getCollisionFlags() & ~(btCollisionObject::CF_KINEMATIC_OBJECT)); 280 | } 281 | } 282 | 283 | // NPCs call this 284 | void CShadowController::GetLastImpulse(Vector *pOut) { 285 | if (!pOut) return; 286 | 287 | //NOT_IMPLEMENTED 288 | *pOut = Vector(0,0,0); 289 | } 290 | 291 | void CShadowController::UseShadowMaterial(bool enable) { 292 | enable ? m_flags |= FLAG_USESHADOWMATERIAL : m_flags &= ~(FLAG_USESHADOWMATERIAL); 293 | } 294 | 295 | void CShadowController::ObjectMaterialChanged(int materialIndex) { 296 | // (assumed) 297 | // if (m_bUseShadowMaterial) { 298 | // m_iObjectMaterial = materialIndex 299 | // } 300 | 301 | NOT_IMPLEMENTED 302 | } 303 | 304 | // Basically get the last inputs to IPhysicsShadowController::Update(), returns last input to timeOffset in Update() 305 | float CShadowController::GetTargetPosition(Vector *pPositionOut, QAngle *pAnglesOut) { 306 | if (pPositionOut) 307 | ConvertPosToHL(m_shadow.targetPosition, *pPositionOut); 308 | 309 | if (pAnglesOut) 310 | ConvertRotationToHL(m_shadow.targetRotation, *pAnglesOut); 311 | 312 | return m_timeOffset; 313 | } 314 | 315 | float CShadowController::GetTeleportDistance() { 316 | return ConvertDistanceToHL(m_shadow.teleportDistance); 317 | } 318 | 319 | void CShadowController::GetMaxSpeed(float *pMaxSpeedOut, float *pMaxAngularSpeedOut) { 320 | if (!pMaxSpeedOut && !pMaxAngularSpeedOut) return; 321 | NOT_IMPLEMENTED 322 | } 323 | 324 | void CShadowController::AttachObject() { 325 | if (!m_pObject) 326 | return; 327 | 328 | btRigidBody *body = btRigidBody::upcast(m_pObject->GetObject()); 329 | m_savedMass = SAFE_DIVIDE(1, body->getInvMass()); 330 | m_savedMaterialIndex = m_pObject->GetMaterialIndex(); 331 | 332 | m_pObject->SetMaterialIndex(MATERIAL_INDEX_SHADOW); 333 | 334 | if (!AllowsTranslation()) { 335 | m_pObject->SetMass(0); 336 | m_pObject->EnableGravity(false); 337 | } 338 | 339 | body->setActivationState(DISABLE_DEACTIVATION); 340 | 341 | m_pObject->AttachEventListener(this); 342 | } 343 | 344 | void CShadowController::DetachObject() { 345 | if (!m_pObject) 346 | return; 347 | 348 | btRigidBody *body = btRigidBody::upcast(m_pObject->GetObject()); 349 | btVector3 btvec = body->getInvInertiaDiagLocal(); 350 | btvec.setX(SAFE_DIVIDE(1.0f, btvec.x())); 351 | btvec.setY(SAFE_DIVIDE(1.0f, btvec.y())); 352 | btvec.setZ(SAFE_DIVIDE(1.0f, btvec.z())); 353 | body->setMassProps(m_savedMass, btvec); 354 | m_pObject->SetMaterialIndex(m_savedMaterialIndex); 355 | 356 | body->setActivationState(ACTIVE_TAG); 357 | 358 | m_pObject->DetachEventListener(this); 359 | m_pObject = NULL; 360 | } 361 | 362 | int CShadowController::GetTicksSinceUpdate() { 363 | return m_ticksSinceUpdate; 364 | } 365 | 366 | /************************* 367 | * CREATION FUNCTIONS 368 | *************************/ 369 | 370 | CShadowController *CreateShadowController(IPhysicsObject *pObject, bool allowPhysicsMovement, bool allowPhysicsRotation) { 371 | if (!pObject) 372 | return NULL; 373 | 374 | return new CShadowController((CPhysicsObject *)pObject, allowPhysicsMovement, allowPhysicsRotation); 375 | } -------------------------------------------------------------------------------- /src/Physics_ShadowController.h: -------------------------------------------------------------------------------- 1 | #ifndef PHYSICS_SHADOWCONTROLLER_H 2 | #define PHYSICS_SHADOWCONTROLLER_H 3 | #if defined(_MSC_VER) || (defined(__GNUC__) && __GNUC__ > 3) 4 | #pragma once 5 | #endif 6 | 7 | #include "IController.h" 8 | 9 | #include "Physics_Object.h" 10 | 11 | struct shadowcontrol_params_t { 12 | shadowcontrol_params_t() {lastPosition.setZero();} 13 | 14 | btVector3 targetPosition; 15 | btQuaternion targetRotation; 16 | btScalar maxSpeed; 17 | btScalar maxDampSpeed; 18 | btScalar maxAngular; 19 | btScalar maxDampAngular; 20 | btVector3 lastPosition; 21 | float dampFactor; 22 | float teleportDistance; 23 | }; 24 | 25 | class CShadowController : public IController, public IPhysicsShadowController, public IObjectEventListener 26 | { 27 | public: 28 | CShadowController(CPhysicsObject *pObject, bool allowTranslation, bool allowRotation); 29 | ~CShadowController(); 30 | 31 | void Update(const Vector &position, const QAngle &angles, float timeOffset); 32 | void MaxSpeed(float maxSpeed, float maxAngularSpeed); 33 | void StepUp(float height); 34 | void SetTeleportDistance(float teleportDistance); 35 | 36 | bool AllowsTranslation(); 37 | bool AllowsRotation(); 38 | 39 | void SetPhysicallyControlled(bool isPhysicallyControlled); 40 | bool IsPhysicallyControlled(); 41 | 42 | void GetLastImpulse(Vector *pOut); 43 | void UseShadowMaterial(bool bUseShadowMaterial); 44 | void ObjectMaterialChanged(int materialIndex); 45 | 46 | float GetTargetPosition(Vector *pPositionOut, QAngle *pAnglesOut); 47 | float GetTeleportDistance(); 48 | void GetMaxSpeed(float *pMaxSpeedOut, float *pMaxAngularSpeedOut); 49 | 50 | // UNEXPOSED FUNCTIONS 51 | void Tick(float deltaTime); 52 | void SetAllowsTranslation(bool enable); 53 | void SetAllowsRotation(bool enable); 54 | 55 | void ObjectDestroyed(CPhysicsObject *pObject); 56 | 57 | int GetTicksSinceUpdate(); 58 | private: 59 | void AttachObject(); 60 | void DetachObject(); 61 | 62 | // NOTE: If you add more than 7 flags, change the m_flags variable type to a short. 63 | enum EShadowFlags { 64 | FLAG_ALLOWPHYSICSMOVEMENT = 1<<0, 65 | FLAG_ALLOWPHYSICSROTATION = 1<<1, 66 | FLAG_PHYSICALLYCONTROLLED = 1<<2, 67 | FLAG_USESHADOWMATERIAL = 1<<3, 68 | }; 69 | 70 | CPhysicsObject * m_pObject; 71 | float m_secondsToArrival; 72 | btVector3 m_currentSpeed; 73 | float m_savedMass; 74 | float m_timeOffset; 75 | int m_savedMaterialIndex; 76 | int m_ticksSinceUpdate; 77 | bool m_enable; 78 | char m_flags; 79 | shadowcontrol_params_t m_shadow; 80 | }; 81 | 82 | float ComputeShadowControllerHL(CPhysicsObject *pObject, const hlshadowcontrol_params_t ¶ms, float secondsToArrival, float dt); 83 | 84 | CShadowController *CreateShadowController(IPhysicsObject *pObject, bool allowPhysicsMovement, bool allowPhysicsRotation); 85 | 86 | #endif // PHYSICS_SHADOWCONTROLLER_H 87 | -------------------------------------------------------------------------------- /src/Physics_SoftBody.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | #if 0 3 | #include "convert.h" 4 | #include "Physics_SoftBody.h" 5 | #include "Physics_Environment.h" 6 | #include "Physics_Object.h" 7 | 8 | #include "BulletSoftBody/btSoftBodyHelpers.h" 9 | 10 | // memdbgon must be the last include file in a .cpp file!!! 11 | #include "tier0/memdbgon.h" 12 | 13 | void ConvertNodeToHL(const btSoftBody::Node *node, softbodynode_t &nodeOut) { 14 | ConvertPosToHL(node->m_x, nodeOut.pos); 15 | ConvertPosToHL(node->m_v, nodeOut.vel); 16 | nodeOut.invMass = node->m_im; 17 | } 18 | 19 | void ConvertNodeToBull(const softbodynode_t &node, btSoftBody::Node &nodeOut) { 20 | ConvertPosToBull(node.pos, nodeOut.m_x); 21 | ConvertPosToBull(node.vel, nodeOut.m_v); 22 | nodeOut.m_im = node.invMass; 23 | } 24 | 25 | void ConvertFaceToHL(const btSoftBody::Face *face, softbodyface_t &faceOut) { 26 | for (int i = 0; i < 3; i++) { 27 | btSoftBody::Node *node = face->m_n[i]; 28 | ConvertNodeToHL(node, faceOut.nodes[i]); 29 | } 30 | 31 | ConvertDirectionToHL(face->m_normal, faceOut.normal); 32 | } 33 | 34 | void ConvertLinkToHL(const btSoftBody::Link *link, softbodylink_t &linkOut) { 35 | for (int i = 0; i < 2; i++) { 36 | btSoftBody::Node *node = link->m_n[i]; 37 | ConvertNodeToHL(node, linkOut.nodes[i]); 38 | } 39 | } 40 | 41 | /************************* 42 | * CLASS CPhysicsSoftBody 43 | *************************/ 44 | 45 | CPhysicsSoftBody::CPhysicsSoftBody() { 46 | m_pEnv = NULL; 47 | m_pSoftBody = NULL; 48 | } 49 | 50 | CPhysicsSoftBody::~CPhysicsSoftBody() { 51 | m_pEnv->GetBulletEnvironment()->removeSoftBody(m_pSoftBody); 52 | delete m_pSoftBody; 53 | } 54 | 55 | bool CPhysicsSoftBody::IsAsleep() const { 56 | return m_pSoftBody->getActivationState() == ISLAND_SLEEPING || m_pSoftBody->getActivationState() == DISABLE_SIMULATION; 57 | } 58 | 59 | void CPhysicsSoftBody::SetTotalMass(float fMass, bool bFromFaces) { 60 | m_pSoftBody->setTotalMass(fMass, bFromFaces); 61 | } 62 | 63 | void CPhysicsSoftBody::Anchor(int node, IPhysicsObject *pObj) { 64 | m_pSoftBody->appendAnchor(node, ((CPhysicsObject *)pObj)->GetObject()); 65 | } 66 | 67 | int CPhysicsSoftBody::GetNodeCount() const { 68 | return m_pSoftBody->m_nodes.size(); 69 | } 70 | 71 | int CPhysicsSoftBody::GetFaceCount() const { 72 | return m_pSoftBody->m_faces.size(); 73 | } 74 | 75 | int CPhysicsSoftBody::GetLinkCount() const { 76 | return m_pSoftBody->m_links.size(); 77 | } 78 | 79 | softbodynode_t CPhysicsSoftBody::GetNode(int i) const { 80 | Assert(i >= 0 && i < m_pSoftBody->m_nodes.size()); 81 | btSoftBody::Node &node = m_pSoftBody->m_nodes[i]; 82 | 83 | softbodynode_t out; 84 | ConvertNodeToHL(&node, out); 85 | return out; 86 | } 87 | 88 | softbodylink_t CPhysicsSoftBody::GetLink(int i) const { 89 | Assert(i >= 0 && i < m_pSoftBody->m_links.size()); 90 | btSoftBody::Link &link = m_pSoftBody->m_links[i]; 91 | 92 | softbodylink_t out; 93 | ConvertLinkToHL(&link, out); 94 | 95 | // Find the node ids with an educated guess (this will be some huge number if something bad happened) 96 | for (int i = 0; i < 2; i++) { 97 | out.nodeIndexes[i] = (int)(link.m_n[i] - &m_pSoftBody->m_nodes[0]); 98 | } 99 | 100 | return out; 101 | } 102 | 103 | softbodyface_t CPhysicsSoftBody::GetFace(int i) const { 104 | Assert(i >= 0 && i < m_pSoftBody->m_faces.size()); 105 | btSoftBody::Face &face = m_pSoftBody->m_faces[i]; 106 | 107 | softbodyface_t out; 108 | ConvertFaceToHL(&face, out); 109 | 110 | // Find the node ids with an educated guess 111 | for (int i = 0; i < 3; i++) { 112 | out.nodeIndexes[i] = (int)(face.m_n[i] - &m_pSoftBody->m_nodes[0]); 113 | } 114 | 115 | return out; 116 | } 117 | 118 | void CPhysicsSoftBody::SetNode(int i, softbodynode_t &node) { 119 | Assert(i >= 0 && i < m_pSoftBody->m_nodes.size()); 120 | 121 | btSoftBody::Node &bnode = m_pSoftBody->m_nodes[i]; 122 | ConvertNodeToBull(node, bnode); 123 | } 124 | 125 | void CPhysicsSoftBody::AddNode(const Vector &pos, float mass) { 126 | btVector3 btpos; 127 | ConvertPosToBull(pos, btpos); 128 | 129 | m_pSoftBody->appendNode(btpos, mass); 130 | } 131 | 132 | void CPhysicsSoftBody::AddLink(int node1, int node2, bool bCheckExist) { 133 | m_pSoftBody->appendLink(node1, node2, NULL, bCheckExist); 134 | } 135 | 136 | void CPhysicsSoftBody::GetAABB(Vector *mins, Vector *maxs) const { 137 | if (!mins && !maxs) return; 138 | 139 | btVector3 btmins, btmaxs; 140 | m_pSoftBody->getAabb(btmins, btmaxs); 141 | 142 | Vector tMins, tMaxs; 143 | ConvertAABBToHL(btmins, btmaxs, tMins, tMaxs); 144 | 145 | if (mins) 146 | *mins = tMins; 147 | 148 | if (maxs) 149 | *maxs = tMaxs; 150 | } 151 | 152 | void CPhysicsSoftBody::RemoveNode(int i) { 153 | Assert(i >= 0 && i < m_pSoftBody->m_nodes.size()); 154 | 155 | m_pSoftBody->pointersToIndices(); 156 | //m_pSoftBody->m_nodes.remove(m_pSoftBody->m_nodes[i]); 157 | m_pSoftBody->indicesToPointers(); 158 | } 159 | 160 | void CPhysicsSoftBody::RemoveLink(int i) { 161 | Assert(i >= 0 && i < m_pSoftBody->m_links.size()); 162 | 163 | btSoftBody::Link &link = m_pSoftBody->m_links[i]; 164 | 165 | m_pSoftBody->pointersToIndices(); 166 | // TODO: Need to update the indices of anything referencing 167 | // the link that is swapped to this position 168 | //m_pSoftBody->m_links.remove(link); 169 | m_pSoftBody->indicesToPointers(); 170 | } 171 | 172 | void CPhysicsSoftBody::RemoveFace(int i) { 173 | Assert(i >= 0 && i < m_pSoftBody->m_faces.size()); 174 | 175 | btSoftBody::Face &face = m_pSoftBody->m_faces[i]; 176 | 177 | m_pSoftBody->pointersToIndices(); 178 | //m_pSoftBody->m_faces.remove(face); 179 | m_pSoftBody->indicesToPointers(); 180 | } 181 | 182 | void CPhysicsSoftBody::RayTest(Ray_t &ray, trace_t *pTrace) const { 183 | if (!pTrace) return; 184 | 185 | btVector3 start, end; 186 | ConvertPosToBull(ray.m_Start, start); 187 | ConvertPosToBull(ray.m_Start + ray.m_Delta, end); 188 | 189 | btSoftBody::sRayCast rayCast; 190 | m_pSoftBody->rayTest(start, end, rayCast); 191 | pTrace->fraction = rayCast.fraction; 192 | pTrace->startpos = ray.m_Start + ray.m_StartOffset; 193 | pTrace->endpos = ray.m_Start + ray.m_StartOffset + (ray.m_Delta * rayCast.fraction); 194 | } 195 | 196 | void CPhysicsSoftBody::BoxTest(Ray_t &ray, trace_t *pTrace) const { 197 | if (!pTrace) return; 198 | 199 | btVector3 start, end; 200 | ConvertPosToBull(ray.m_Start, start); 201 | ConvertPosToBull(ray.m_Start + ray.m_Delta, end); 202 | 203 | NOT_IMPLEMENTED 204 | } 205 | 206 | void CPhysicsSoftBody::Transform(const matrix3x4_t &mat) { 207 | btTransform trans; 208 | ConvertMatrixToBull(mat, trans); 209 | 210 | m_pSoftBody->transform(trans); 211 | } 212 | 213 | void CPhysicsSoftBody::Transform(const Vector *vec, const QAngle *ang) { 214 | if (!vec && !ang) return; 215 | 216 | if (vec) { 217 | btVector3 bVec; 218 | ConvertPosToBull(*vec, bVec); 219 | 220 | m_pSoftBody->translate(bVec); 221 | } 222 | 223 | if (ang) { 224 | btQuaternion quat; 225 | ConvertRotationToBull(*ang, quat); 226 | 227 | m_pSoftBody->rotate(quat); 228 | } 229 | } 230 | 231 | void CPhysicsSoftBody::Scale(const Vector &scale) { 232 | // No conversion 233 | btVector3 btScale; 234 | btScale.setX(scale.x); 235 | btScale.setY(scale.z); 236 | btScale.setZ(scale.y); 237 | 238 | m_pSoftBody->scale(btScale); 239 | } 240 | 241 | void CPhysicsSoftBody::Init(CPhysicsEnvironment *pEnv, btSoftBody *pSoftBody, const softbodyparams_t *pParams) { 242 | m_pEnv = pEnv; 243 | m_pSoftBody = pSoftBody; 244 | 245 | m_pSoftBody->m_cfg.collisions |= btSoftBody::fCollision::VF_SS; 246 | m_pSoftBody->m_cfg.viterations = 1; 247 | pEnv->GetBulletEnvironment()->addSoftBody(m_pSoftBody); 248 | } 249 | 250 | btSoftBody *CPhysicsSoftBody::GetSoftBody() { 251 | return m_pSoftBody; 252 | } 253 | 254 | /************************* 255 | * CREATION FUNCTIONS 256 | *************************/ 257 | 258 | CPhysicsSoftBody *CreateSoftBody(CPhysicsEnvironment *pEnv) { 259 | btSoftBody *pSoftBody = new btSoftBody(&pEnv->GetSoftBodyWorldInfo()); 260 | CPhysicsSoftBody *pPhysBody = new CPhysicsSoftBody; 261 | return pPhysBody; 262 | } 263 | 264 | CPhysicsSoftBody *CreateSoftBodyFromTriMesh(CPhysicsEnvironment *pEnv, const Vector *vertices, int numVertices, const int *indices, int numIndices, const Vector &position, const QAngle &angles, const softbodyparams_t *pParams) { 265 | btVector3 *bullVerts = new btVector3[numVertices]; 266 | 267 | // Make sure numIndices is evenly divisible by 3 268 | Assert(numIndices % 3 == 0); 269 | 270 | for (int i = 0; i < numVertices; i++) { 271 | ConvertPosToBull(vertices[i], bullVerts[i]); 272 | } 273 | 274 | /* 275 | btSoftBody *pSoftBody = new btSoftBody(&pEnv->GetSoftBodyWorldInfo(), numVertices, bullVerts, NULL); 276 | for (int i = 0; i < numIndices; i++) { 277 | 278 | } 279 | */ 280 | 281 | delete [] bullVerts; 282 | 283 | NOT_IMPLEMENTED 284 | return NULL; 285 | } 286 | 287 | CPhysicsSoftBody *CreateSoftBodyFromVertices(CPhysicsEnvironment *pEnv, const Vector *vertices, int numVertices, const softbodyparams_t *pParams) { 288 | btVector3 *bullVerts = new btVector3[numVertices]; 289 | 290 | for (int i = 0; i < numVertices; i++) { 291 | ConvertPosToBull(vertices[i], bullVerts[i]); 292 | } 293 | 294 | btSoftBodyWorldInfo &wi = pEnv->GetSoftBodyWorldInfo(); 295 | 296 | btSoftBody *pSoftBody = btSoftBodyHelpers::CreateFromConvexHull(wi, bullVerts, numVertices); 297 | delete [] bullVerts; 298 | 299 | CPhysicsSoftBody *pBody = new CPhysicsSoftBody; 300 | pBody->Init(pEnv, pSoftBody, pParams); 301 | 302 | return pBody; 303 | } 304 | 305 | CPhysicsSoftBody *CreateSoftBodyRope(CPhysicsEnvironment *pEnv, const Vector &position, const Vector &end, int resolution, const softbodyparams_t *pParams) { 306 | btSoftBodyWorldInfo &wi = pEnv->GetSoftBodyWorldInfo(); 307 | 308 | btVector3 btStart, btEnd; 309 | ConvertPosToBull(position, btStart); 310 | ConvertPosToBull(end, btEnd); 311 | 312 | // Last parameter is fixed sides of the soft body (which we don't set - dev can set these elsewhere) 313 | btSoftBody *pSoftBody = btSoftBodyHelpers::CreateRope(wi, btStart, btEnd, resolution, 0); 314 | if (pParams) { 315 | pSoftBody->setTotalMass(pParams->totalMass); 316 | } 317 | 318 | CPhysicsSoftBody *pPhysBody = new CPhysicsSoftBody; 319 | pPhysBody->Init(pEnv, pSoftBody, pParams); 320 | 321 | return pPhysBody; 322 | } 323 | 324 | CPhysicsSoftBody *CreateSoftBodyPatch(CPhysicsEnvironment *pEnv, const Vector *corners, int resx, int resy, const softbodyparams_t *pParams) { 325 | btSoftBodyWorldInfo &wi = pEnv->GetSoftBodyWorldInfo(); 326 | 327 | btVector3 bcorners[4]; 328 | for (int i = 0; i < 4; i++) { 329 | ConvertPosToBull(corners[i], bcorners[i]); 330 | } 331 | 332 | btSoftBody *pSoftBody = btSoftBodyHelpers::CreatePatch(wi, bcorners[0], bcorners[1], bcorners[2], bcorners[3], resx, resy, 0, false); 333 | if (pParams) { 334 | pSoftBody->setTotalMass(pParams->totalMass); 335 | } 336 | 337 | CPhysicsSoftBody *pPhysBody = new CPhysicsSoftBody; 338 | pPhysBody->Init(pEnv, pSoftBody, pParams); 339 | 340 | return pPhysBody; 341 | } 342 | #endif -------------------------------------------------------------------------------- /src/Physics_SoftBody.h: -------------------------------------------------------------------------------- 1 | #if 0 2 | 3 | #ifndef PHYSICS_SOFTBODY_H 4 | #define PHYSICS_SOFTBODY_H 5 | #if defined(_MSC_VER) || (defined(__GNUC__) && __GNUC__ > 3) 6 | #pragma once 7 | #endif 8 | 9 | #include "vphysics/softbodyV32.h" 10 | 11 | // Purpose: Dynamically deforming meshes (blankets, dents in objects, etc.) 12 | 13 | // Class declarations 14 | class CPhysicsEnvironment; 15 | class CPhysicsObject; 16 | 17 | class btSoftBody; 18 | 19 | class CPhysicsSoftBody : public IPhysicsSoftBody { 20 | public: 21 | CPhysicsSoftBody(); 22 | ~CPhysicsSoftBody(); 23 | 24 | bool IsAsleep() const; 25 | 26 | void SetTotalMass(float fMass, bool bFromFaces = false); 27 | void Anchor(int node, IPhysicsObject *pObj); 28 | 29 | int GetNodeCount() const; 30 | int GetFaceCount() const; 31 | int GetLinkCount() const; 32 | 33 | softbodynode_t GetNode(int i) const; 34 | softbodylink_t GetLink(int i) const; 35 | softbodyface_t GetFace(int i) const; 36 | 37 | void SetNode(int i, softbodynode_t &node); 38 | 39 | void AddNode(const Vector &pos, float mass); // Appends a new node to the end of the list (size-1) 40 | void AddLink(int node1, int node2, bool bCheckExist = false); 41 | 42 | void RemoveNode(int i); 43 | void RemoveLink(int i); 44 | void RemoveFace(int i); 45 | 46 | // Get soft body AABB (cannot be implemented in collision interface because soft bodies change shape) 47 | void GetAABB(Vector *mins, Vector *maxs) const; 48 | void RayTest(Ray_t &ray, trace_t *pTrace) const; 49 | void BoxTest(Ray_t &ray, trace_t *pTrace) const; 50 | 51 | void Transform(const matrix3x4_t &mat); 52 | void Transform(const Vector *vec, const QAngle *ang); 53 | void Scale(const Vector &scale); 54 | 55 | IPhysicsEnvironment32 *GetPhysicsEnvironment() const { return (IPhysicsEnvironment32 *)m_pEnv; } 56 | 57 | // UNEXPOSED FUNCTIONS 58 | public: 59 | void Init(CPhysicsEnvironment *pEnv, btSoftBody *pSoftBody, const softbodyparams_t *pParams); 60 | 61 | btSoftBody * GetSoftBody(); 62 | 63 | private: 64 | CPhysicsEnvironment * m_pEnv; 65 | btSoftBody * m_pSoftBody; 66 | }; 67 | 68 | CPhysicsSoftBody *CreateSoftBody(CPhysicsEnvironment *pEnv); 69 | CPhysicsSoftBody *CreateSoftBodyFromTriMesh(CPhysicsEnvironment *pEnv); // TODO: Not complete 70 | // Vertices are in world space! (You can create this in local space then call Transform to move this to the start position) 71 | CPhysicsSoftBody *CreateSoftBodyFromVertices(CPhysicsEnvironment *pEnv, const Vector *vertices, int numVertices, const softbodyparams_t *pParams); 72 | CPhysicsSoftBody *CreateSoftBodyRope(CPhysicsEnvironment *pEnv, const Vector &position, const Vector &end, int resolution, const softbodyparams_t *pParams); 73 | CPhysicsSoftBody *CreateSoftBodyPatch(CPhysicsEnvironment *pEnv, const Vector *corners, int resx, int resy, const softbodyparams_t *pParams); 74 | 75 | #endif // PHYSICS_SOFTBODY_H 76 | #endif -------------------------------------------------------------------------------- /src/Physics_SurfaceProps.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | 3 | #include 4 | 5 | #include "Physics_SurfaceProps.h" 6 | 7 | // memdbgon must be the last include file in a .cpp file!!! 8 | #include "tier0/memdbgon.h" 9 | 10 | /***************************** 11 | * CLASS CPhysicsSurfaceProps 12 | *****************************/ 13 | 14 | CPhysicsSurfaceProps::CPhysicsSurfaceProps() { 15 | m_strings = new CUtlSymbolTable(0, 32, true); 16 | 17 | // HACK: Prevent sound list from starting at index 0 (invalid index) 18 | m_soundList.AddToHead(); 19 | } 20 | 21 | CPhysicsSurfaceProps::~CPhysicsSurfaceProps() { 22 | delete m_strings; 23 | } 24 | 25 | int CPhysicsSurfaceProps::ParseSurfaceData(const char *pFilename, const char *pTextfile) { 26 | if (!AddFileToDatabase(pFilename)) return 0; 27 | DevMsg("VPhysics: Parsing surface data (file: %s)\n", pFilename); 28 | 29 | KeyValues *surfprops = new KeyValues("CPhysicsSurfaceProps"); 30 | surfprops->LoadFromBuffer(pFilename, pTextfile); 31 | 32 | // Loop the outer elements (prop names with the data as subkeys) 33 | for (KeyValues *surface = surfprops; surface; surface = surface->GetNextKey()) { 34 | // Ignore duplicates 35 | if (GetSurfaceIndex(surface->GetName()) >= 0) { 36 | DevWarning("VPhysics: Ignoring duplicate surfaceprop \"%s\"\n", surface->GetName()); 37 | continue; 38 | } 39 | 40 | CSurface prop; 41 | memset(&prop.data, 0, sizeof(prop.data)); 42 | prop.m_name = m_strings->AddString(surface->GetName()); 43 | prop.data.game.material = 0; 44 | prop.data.game.maxSpeedFactor = 1.0f; 45 | prop.data.game.jumpFactor = 1.0f; 46 | prop.data.game.climbable = 0.0f; 47 | 48 | int baseMaterial = GetSurfaceIndex("default"); 49 | if (baseMaterial != -1) { 50 | CopyPhysicsProperties(&prop, baseMaterial); 51 | 52 | const CSurface *pSurface = GetInternalSurface(baseMaterial); 53 | prop.data.audio = pSurface->data.audio; 54 | prop.data.game = pSurface->data.game; 55 | prop.data.sounds = pSurface->data.sounds; 56 | } 57 | 58 | // Subkeys that contain the actual data 59 | for (KeyValues *data = surface->GetFirstSubKey(); data; data = data->GetNextKey()) { 60 | const char *key = data->GetName(); 61 | if (!Q_stricmp(key, "base")) { 62 | baseMaterial = GetSurfaceIndex(data->GetString()); 63 | CopyPhysicsProperties(&prop, baseMaterial); 64 | } else if (!Q_stricmp(key, "thickness")) 65 | prop.data.physics.thickness = data->GetFloat(); 66 | else if (!Q_stricmp(key, "density")) 67 | prop.data.physics.density = data->GetFloat(); 68 | else if (!Q_stricmp(key, "elasticity")) 69 | prop.data.physics.elasticity = data->GetFloat(); 70 | else if (!Q_stricmp(key, "friction")) 71 | prop.data.physics.friction = data->GetFloat(); 72 | else if (!Q_stricmp(key, "dampening")) 73 | prop.data.physics.dampening = data->GetFloat(); 74 | else if (!Q_stricmp(key, "audioreflectivity")) 75 | prop.data.audio.reflectivity = data->GetFloat(); 76 | else if (!Q_stricmp(key, "audiohardnessfactor")) 77 | prop.data.audio.hardnessFactor = data->GetFloat(); 78 | else if (!Q_stricmp(key, "audioroughnessfactor")) 79 | prop.data.audio.roughnessFactor = data->GetFloat(); 80 | else if (!Q_stricmp(key, "scrapeRoughThreshold")) 81 | prop.data.audio.roughThreshold = data->GetFloat(); 82 | else if (!Q_stricmp(key, "impactHardThreshold")) 83 | prop.data.audio.hardThreshold = data->GetFloat(); 84 | else if (!Q_stricmp(key, "audioHardMinVelocity")) 85 | prop.data.audio.hardVelocityThreshold = data->GetFloat(); 86 | else if (!Q_stricmp(key, "maxspeedfactor")) 87 | prop.data.game.maxSpeedFactor = data->GetFloat(); 88 | else if (!Q_stricmp(key, "jumpfactor")) 89 | prop.data.game.jumpFactor = data->GetFloat(); 90 | else if (!Q_stricmp(key, "climbable")) 91 | prop.data.game.climbable = data->GetInt(); 92 | else if (!Q_stricmp(key, "gamematerial")) { 93 | if (data->GetDataType() == KeyValues::TYPE_STRING && strlen(data->GetString()) == 1) { 94 | prop.data.game.material = toupper(data->GetString()[0]); 95 | } else { 96 | prop.data.game.material = data->GetInt(); 97 | } 98 | } else if (!Q_stricmp(key, "stepleft")) { 99 | CUtlSymbol sym = m_strings->AddString(data->GetString()); 100 | prop.data.sounds.stepleft = FindOrAddSound(sym); 101 | } else if (!Q_stricmp(key, "stepright")) { 102 | CUtlSymbol sym = m_strings->AddString(data->GetString()); 103 | prop.data.sounds.stepright = FindOrAddSound(sym); 104 | } else if (!Q_stricmp(key, "impactsoft")) { 105 | CUtlSymbol sym = m_strings->AddString(data->GetString()); 106 | prop.data.sounds.impactSoft = FindOrAddSound(sym); 107 | } else if (!Q_stricmp(key, "impacthard")) { 108 | CUtlSymbol sym = m_strings->AddString(data->GetString()); 109 | prop.data.sounds.impactHard = FindOrAddSound(sym); 110 | } else if (!Q_stricmp(key, "scrapesmooth")) { 111 | CUtlSymbol sym = m_strings->AddString(data->GetString()); 112 | prop.data.sounds.scrapeSmooth = FindOrAddSound(sym); 113 | } else if (!Q_stricmp(key, "scraperough")) { 114 | CUtlSymbol sym = m_strings->AddString(data->GetString()); 115 | prop.data.sounds.scrapeRough = FindOrAddSound(sym); 116 | } else if (!Q_stricmp(key, "bulletimpact")) { 117 | CUtlSymbol sym = m_strings->AddString(data->GetString()); 118 | prop.data.sounds.bulletImpact = FindOrAddSound(sym); 119 | } else if (!Q_stricmp(key, "break")) { 120 | CUtlSymbol sym = m_strings->AddString(data->GetString()); 121 | prop.data.sounds.breakSound = FindOrAddSound(sym); 122 | } else if (!Q_stricmp(key, "strain")) { 123 | CUtlSymbol sym = m_strings->AddString(data->GetString()); 124 | prop.data.sounds.strainSound = FindOrAddSound(sym); 125 | } else if (!Q_stricmp(key, "rolling") || !Q_stricmp(key, "roll")) { 126 | CUtlSymbol sym = m_strings->AddString(data->GetString()); 127 | prop.data.sounds.rolling = FindOrAddSound(sym); 128 | } else 129 | DevWarning("VPhysics: Surfaceprop \"%s\" has unknown key %s (data: %s)\n", surface->GetName(), key, data->GetString()); 130 | } 131 | 132 | m_props.AddToTail(prop); 133 | } 134 | surfprops->deleteThis(); 135 | return 0; 136 | } 137 | 138 | int CPhysicsSurfaceProps::SurfacePropCount() const { 139 | return m_props.Count(); 140 | } 141 | 142 | int CPhysicsSurfaceProps::GetSurfaceIndex(const char *pSurfacePropName) const { 143 | if (pSurfacePropName[0] == '$') { 144 | int index = GetReservedSurfaceIndex(pSurfacePropName); 145 | if (index >= 0) return index; 146 | } 147 | 148 | CUtlSymbol id = m_strings->Find(pSurfacePropName); 149 | if (id.IsValid()) { 150 | for (int i = 0; i < m_props.Size(); i++) { 151 | if (m_props[i].m_name == id) 152 | return i; 153 | } 154 | } 155 | 156 | return -1; 157 | } 158 | 159 | void CPhysicsSurfaceProps::GetPhysicsProperties(int surfaceDataIndex, float *density, float *thickness, float *friction, float *elasticity) const { 160 | const CSurface *pSurface = GetInternalSurface(surfaceDataIndex); 161 | if (pSurface) { 162 | if (friction) *friction = pSurface->data.physics.friction; 163 | if (elasticity) *elasticity = pSurface->data.physics.elasticity; 164 | if (density) *density = pSurface->data.physics.density; 165 | if (thickness) *thickness = pSurface->data.physics.thickness; 166 | } 167 | } 168 | 169 | surfacedata_t *CPhysicsSurfaceProps::GetSurfaceData(int surfaceDataIndex) { 170 | CSurface *pSurface = GetInternalSurface(surfaceDataIndex); 171 | if (!pSurface) pSurface = GetInternalSurface(GetSurfaceIndex("default")); 172 | Assert(pSurface); 173 | 174 | return &pSurface->data; 175 | } 176 | 177 | const char *CPhysicsSurfaceProps::GetString(unsigned short stringTableIndex) const { 178 | if (stringTableIndex < 1 || stringTableIndex >= m_soundList.Count()) 179 | return NULL; 180 | 181 | CUtlSymbol index = m_soundList[stringTableIndex]; 182 | return m_strings->String(index); 183 | } 184 | 185 | const char *CPhysicsSurfaceProps::GetPropName(int surfaceDataIndex) const { 186 | if (surfaceDataIndex < 0 || surfaceDataIndex > m_props.Size()) 187 | return "default"; 188 | 189 | return m_strings->String(m_props[surfaceDataIndex].m_name); 190 | } 191 | 192 | void CPhysicsSurfaceProps::SetWorldMaterialIndexTable(int *pMapArray, int mapSize) { 193 | NOT_IMPLEMENTED 194 | } 195 | 196 | void CPhysicsSurfaceProps::GetPhysicsParameters(int surfaceDataIndex, surfacephysicsparams_t *pParamsOut) const { 197 | if (!pParamsOut) return; 198 | 199 | const CSurface *pSurface = GetInternalSurface(surfaceDataIndex); 200 | if (pSurface) { 201 | *pParamsOut = pSurface->data.physics; 202 | } 203 | } 204 | 205 | int CPhysicsSurfaceProps::GetReservedSurfaceIndex(const char *pSurfacePropName) const { 206 | if (!Q_stricmp(pSurfacePropName, "$MATERIAL_INDEX_SHADOW")) 207 | return MATERIAL_INDEX_SHADOW; 208 | 209 | return -1; 210 | } 211 | 212 | CSurface *CPhysicsSurfaceProps::GetInternalSurface(int materialIndex) { 213 | if (materialIndex < 0 || materialIndex > m_props.Size()-1) 214 | return NULL; 215 | 216 | return &m_props[materialIndex]; 217 | } 218 | 219 | const CSurface *CPhysicsSurfaceProps::GetInternalSurface(int materialIndex) const { 220 | if (materialIndex < 0 || materialIndex > m_props.Size()-1) 221 | return NULL; 222 | 223 | return &m_props[materialIndex]; 224 | } 225 | 226 | void CPhysicsSurfaceProps::CopyPhysicsProperties(CSurface *pOut, int baseIndex) { 227 | if (!pOut) return; 228 | 229 | const CSurface *pSurface = GetInternalSurface(baseIndex); 230 | if (pSurface) { 231 | pOut->data.physics = pSurface->data.physics; 232 | } 233 | } 234 | 235 | bool CPhysicsSurfaceProps::AddFileToDatabase(const char *pFilename) { 236 | CUtlSymbol id = m_strings->AddString(pFilename); 237 | 238 | for (int i = 0; i < m_fileList.Size(); i++) 239 | if (m_fileList[i] == id) return false; 240 | 241 | m_fileList.AddToTail(id); 242 | return true; 243 | } 244 | 245 | int CPhysicsSurfaceProps::FindOrAddSound(CUtlSymbol sym) { 246 | int id = m_soundList.Find(sym); 247 | if (id != -1) 248 | return id; 249 | else 250 | return m_soundList.AddToTail(sym); 251 | } 252 | 253 | CPhysicsSurfaceProps g_SurfaceDatabase; 254 | EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CPhysicsSurfaceProps, IPhysicsSurfaceProps, VPHYSICS_SURFACEPROPS_INTERFACE_VERSION, g_SurfaceDatabase); -------------------------------------------------------------------------------- /src/Physics_SurfaceProps.h: -------------------------------------------------------------------------------- 1 | #ifndef PHYSICS_SURFACEPROPS_H 2 | #define PHYSICS_SURFACEPROPS_H 3 | #if defined(_MSC_VER) || (defined(__GNUC__) && __GNUC__ > 3) 4 | #pragma once 5 | #endif 6 | 7 | enum { 8 | MATERIAL_INDEX_SHADOW = 0xF000, 9 | }; 10 | 11 | class CSurface { 12 | public: 13 | CUtlSymbol m_name; 14 | surfacedata_t data; 15 | }; 16 | 17 | class CPhysicsSurfaceProps : public IPhysicsSurfaceProps { 18 | public: 19 | CPhysicsSurfaceProps(); 20 | ~CPhysicsSurfaceProps(); 21 | 22 | int ParseSurfaceData(const char *pFilename, const char *pTextfile); 23 | int SurfacePropCount() const; 24 | 25 | int GetSurfaceIndex(const char *pSurfacePropName) const; 26 | void GetPhysicsProperties(int surfaceDataIndex, float *density, float *thickness, float *friction, float *elasticity) const; 27 | 28 | surfacedata_t * GetSurfaceData(int surfaceDataIndex); 29 | const char * GetString(unsigned short stringTableIndex) const; 30 | 31 | const char * GetPropName(int surfaceDataIndex) const; 32 | 33 | void SetWorldMaterialIndexTable(int *pMapArray, int mapSize); 34 | 35 | void GetPhysicsParameters(int surfaceDataIndex, surfacephysicsparams_t *pParamsOut) const; 36 | 37 | private: 38 | int GetReservedSurfaceIndex(const char *pSurfacePropName) const; 39 | 40 | CSurface * GetInternalSurface(int materialIndex); 41 | const CSurface * GetInternalSurface(int materialIndex) const; 42 | 43 | void CopyPhysicsProperties(CSurface *pOut, int baseIndex); 44 | bool AddFileToDatabase(const char *pFilename); 45 | int FindOrAddSound(CUtlSymbol sym); 46 | 47 | private: 48 | CUtlSymbolTable * m_strings; 49 | CUtlVector m_soundList; 50 | CUtlVector m_props; 51 | CUtlVector m_fileList; 52 | }; 53 | 54 | extern CPhysicsSurfaceProps g_SurfaceDatabase; 55 | 56 | #endif // PHYSICS_SURFACEPROPS_H 57 | -------------------------------------------------------------------------------- /src/Physics_VehicleAirboat.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | 3 | #include "Physics_VehicleAirboat.h" 4 | 5 | CAirboatVehicle::CAirboatVehicle(CPhysicsObject *pBody, IPhysicsGameTrace *pGameTrace) { 6 | 7 | } 8 | 9 | CAirboatVehicle::~CAirboatVehicle() { 10 | 11 | } 12 | 13 | void CAirboatVehicle::updateAction(btCollisionWorld *pWorld, btScalar dt) { 14 | 15 | } 16 | 17 | void CAirboatVehicle::debugDraw(btIDebugDraw *pDebugDrawer) { 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/Physics_VehicleAirboat.h: -------------------------------------------------------------------------------- 1 | #ifndef PHYSICS_VEHICLEAIRBOAT_H 2 | #define PHYSICS_VEHICLEAIRBOAT_H 3 | 4 | class CPhysicsObject; 5 | class IPhysicsGameTrace; 6 | 7 | class CAirboatVehicle : public btActionInterface { 8 | public: 9 | CAirboatVehicle(CPhysicsObject *pBody, IPhysicsGameTrace *pGameTrace); 10 | ~CAirboatVehicle(); 11 | 12 | virtual void updateAction(btCollisionWorld *pWorld, btScalar dt); 13 | virtual void debugDraw(btIDebugDraw *pDebugDrawer); 14 | 15 | private: 16 | CPhysicsObject *m_pBody; 17 | IPhysicsGameTrace *m_pGameTrace; 18 | }; 19 | 20 | #endif // PHYSICS_VEHICLEAIRBOAT_H -------------------------------------------------------------------------------- /src/Physics_VehicleController.h: -------------------------------------------------------------------------------- 1 | #ifndef PHYSICS_VEHICLECONTROLLER_H 2 | #define PHYSICS_VEHICLECONTROLLER_H 3 | #if defined(_MSC_VER) || (defined(__GNUC__) && __GNUC__ > 3) 4 | #pragma once 5 | #endif 6 | 7 | #include 8 | #include "vphysics/vehiclesV32.h" 9 | 10 | class IPhysicsObject; 11 | class CPhysicsObject; 12 | class CPhysicsEnvironment; 13 | 14 | struct btVehicleRaycaster; 15 | class btRaycastVehicle; 16 | class btWheeledVehicle; 17 | 18 | // Toggle wheeled/raycast car (wheeled is not complete yet) 19 | //#define USE_WHEELED_VEHICLE 20 | 21 | // TODO: Implement this class and move it to the public interface. 22 | // The game can implement this class to override wheel ray traces. 23 | class IPhysicsVehicleWheelTrace { 24 | public: 25 | // Return the object if the ray hits, otherwise NULL 26 | // Also, be sure to fill the result trace. 27 | virtual IPhysicsObject * CastRay(int wheelIndex, const Vector &start, const Vector &end, trace_t &result) = 0; 28 | }; 29 | 30 | class CPhysicsVehicleController : public IPhysicsVehicleController32 { 31 | public: 32 | CPhysicsVehicleController(CPhysicsEnvironment *pEnv, CPhysicsObject *pBody, const vehicleparams_t ¶ms, unsigned int nVehicleType, IPhysicsGameTrace *pGameTrace); 33 | ~CPhysicsVehicleController(); 34 | 35 | const vehicle_operatingparams_t & GetOperatingParams() { return m_vehicleState; }; 36 | const vehicleparams_t & GetVehicleParams() { return m_vehicleParams; } 37 | vehicleparams_t & GetVehicleParamsForChange() { return m_vehicleParams; } 38 | 39 | // force in kg*in/s 40 | void SetWheelForce(int wheelIndex, float force); 41 | void SetWheelBrake(int wheelIndex, float brakeVal); 42 | // steerVal is in degrees! 43 | void SetWheelSteering(int wheelIndex, float steerVal); 44 | 45 | // Default vehicle handling... 46 | void Update(float dt, vehicle_controlparams_t &controls); 47 | float UpdateBooster(float dt); 48 | int GetWheelCount(); 49 | IPhysicsObject * GetWheel(int index); 50 | bool GetWheelContactPoint(int index, Vector *pContactPoint, int *pSurfaceProps); 51 | void SetSpringLength(int wheelIndex, float length); 52 | void SetWheelFriction(int wheelIndex, float friction); 53 | 54 | void OnVehicleEnter() { m_bOccupied = true; } 55 | void OnVehicleExit() { m_bOccupied = false; } 56 | 57 | void SetEngineDisabled(bool bDisable) { m_bEngineDisabled = bDisable; } 58 | bool IsEngineDisabled() { return m_bEngineDisabled; } 59 | 60 | // Set the position of the vehicle controller and its wheels (wheels relative to vehicle pos). 61 | // Use this instead of calling SetPosition on the chassis. 62 | void SetPosition(const Vector *pos, const QAngle *ang); 63 | 64 | // Debug 65 | void GetCarSystemDebugData(vehicle_debugcarsystem_t &debugCarSystem); 66 | void VehicleDataReload(); 67 | 68 | public: 69 | // Unexposed functions 70 | 71 | void InitVehicleParams(const vehicleparams_t ¶ms); 72 | void InitBullVehicle(); 73 | 74 | void InitCarWheels(); 75 | void DestroyCarWheels(); 76 | CPhysicsObject * CreateWheel(int wheelIndex, vehicle_axleparams_t &axle); 77 | 78 | CPhysicsObject * GetBody(); 79 | 80 | void UpdateSteering(vehicle_controlparams_t &controls, float dt); 81 | void UpdateEngine(vehicle_controlparams_t &controls, float dt); 82 | void UpdateWheels(vehicle_controlparams_t &controls, float dt); 83 | 84 | void CalcEngineTransmission(vehicle_controlparams_t &controls, float dt); 85 | void CalcEngine(vehicle_controlparams_t &controls, float dt); 86 | 87 | void ShutdownBullVehicle(); 88 | 89 | // To be exposed functions 90 | CPhysicsObject * AddWheel(); 91 | private: 92 | vehicleparams_t m_vehicleParams; 93 | vehicle_operatingparams_t m_vehicleState; 94 | CPhysicsObject * m_pBody; 95 | CPhysicsEnvironment * m_pEnv; 96 | IPhysicsGameTrace * m_pGameTrace; 97 | unsigned int m_iVehicleType; 98 | bool m_bEngineDisabled; 99 | bool m_bOccupied; 100 | CPhysicsObject * m_pWheels[VEHICLE_MAX_WHEEL_COUNT]; 101 | int m_iWheelCount; 102 | bool m_bSlipperyWheels; 103 | 104 | #ifdef USE_WHEELED_VEHICLE 105 | btWheeledVehicle * m_pVehicle; 106 | #else 107 | btRaycastVehicle * m_pVehicle; 108 | btVehicleRaycaster * m_pRaycaster; 109 | btRaycastVehicle::btVehicleTuning m_tuning; 110 | #endif 111 | }; 112 | 113 | IPhysicsVehicleController *CreateVehicleController(CPhysicsEnvironment *pEnv, CPhysicsObject *pBody, const vehicleparams_t ¶ms, unsigned int nVehicleType, IPhysicsGameTrace *pGameTrace); 114 | 115 | #endif // PHYSICS_VEHICLECONTROLLER_H 116 | -------------------------------------------------------------------------------- /src/Physics_VehicleControllerCustom.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | 3 | #include "Physics_Environment.h" 4 | #include "Physics_Object.h" 5 | #include "Physics_VehicleControllerCustom.h" 6 | 7 | // memdbgon must be the last include file in a .cpp file!!! 8 | #include "tier0/memdbgon.h" 9 | 10 | class CWheelVehicle : public btActionInterface { 11 | public: 12 | CWheelVehicle(btRigidBody *chassis); 13 | 14 | void updateAction(btCollisionWorld *collisionWorld, btScalar dt); 15 | void debugDraw(btIDebugDraw *pDebugDraw); 16 | 17 | private: 18 | btRigidBody * m_pChassis; 19 | }; 20 | 21 | CWheelVehicle::CWheelVehicle(btRigidBody *chassis) { 22 | m_pChassis = chassis; 23 | } 24 | 25 | void CWheelVehicle::updateAction(btCollisionWorld *collisionWorld, btScalar dt) { 26 | 27 | } 28 | 29 | void CWheelVehicle::debugDraw(btIDebugDraw *pDebugDraw) { 30 | 31 | } 32 | 33 | /***************************************** 34 | * CLASS CPhysicsVehicleControllerCustom 35 | *****************************************/ 36 | 37 | CPhysicsVehicleControllerCustom::CPhysicsVehicleControllerCustom(CPhysicsEnvironment *pEnv, CPhysicsObject *pBody, IPhysicsGameTrace *pGameTrace) { 38 | m_pEnv = pEnv; 39 | m_pBody = pBody; 40 | m_pGameTrace = pGameTrace; 41 | } 42 | 43 | CPhysicsVehicleControllerCustom::~CPhysicsVehicleControllerCustom() { 44 | 45 | } 46 | 47 | void CPhysicsVehicleControllerCustom::SetWheelForce(int wheelIndex, float force) { 48 | NOT_IMPLEMENTED 49 | } 50 | 51 | void CPhysicsVehicleControllerCustom::SetWheelBrake(int wheelIndex, float brakeVal) { 52 | NOT_IMPLEMENTED 53 | } 54 | 55 | void CPhysicsVehicleControllerCustom::SetWheelSteering(int wheelIndex, float steerVal) { 56 | NOT_IMPLEMENTED 57 | } 58 | 59 | void CPhysicsVehicleControllerCustom::Update(float dt) { 60 | NOT_IMPLEMENTED 61 | } 62 | 63 | void CPhysicsVehicleControllerCustom::CreateWheel(const vehicle_customwheelparams_t ¶ms) { 64 | NOT_IMPLEMENTED 65 | } 66 | -------------------------------------------------------------------------------- /src/Physics_VehicleControllerCustom.h: -------------------------------------------------------------------------------- 1 | #ifndef PHYSICS_VEHICLECONTROLLERCUSTOM_H 2 | #define PHYSICS_VEHICLECONTROLLERCUSTOM_H 3 | #if defined(_MSC_VER) || (defined(__GNUC__) && __GNUC__ > 3) 4 | #pragma once 5 | #endif 6 | 7 | // Class declarations 8 | 9 | class CPhysicsEnvironment; 10 | class CPhysicsObject; 11 | 12 | class IPhysicsGameTrace; 13 | 14 | // TODO: Move these classes to a public interface 15 | 16 | struct vehicle_customwheelparams_t { 17 | // Position of wheel in world space 18 | Vector worldPosition; 19 | 20 | // Normalized direction the wheel is facing in local space (normally straight down, used for raytrace direction) 21 | Vector wheelDirection; 22 | 23 | // Normalized direction of the axle from the wheel in local space (normally straight left, used for which way the wheel rolls and turns) 24 | Vector wheelAxleDirection; 25 | 26 | // Radius of wheel in inches 27 | float wheelRadius; 28 | 29 | // Width of cylinder wheel in inches 30 | float wheelWidth; 31 | 32 | // Max suspension length in inches 33 | float maxSuspensionLength; 34 | 35 | // How stiff the suspension is. Lower values make the vehicle sit on the ground, higher ones make the suspension hard (Usually some param * body mass) 36 | float suspensionStiffness; 37 | 38 | inline void Defaults() { 39 | worldPosition.Zero(); 40 | wheelDirection.Zero(); 41 | wheelAxleDirection.Zero(); 42 | 43 | wheelRadius = 16; 44 | wheelWidth = 8; 45 | maxSuspensionLength = 16; 46 | suspensionStiffness = 32; 47 | } 48 | }; 49 | 50 | // Purpose: Structure to pass information about wheels back to the game 51 | struct vehicle_wheelinfo_t { 52 | // Position of wheel in world space 53 | Vector worldPosition; 54 | 55 | // Turn angle in degrees (-left/+right) 56 | float turnAngle; 57 | 58 | // Speed in rpm 59 | float speed; 60 | }; 61 | 62 | // Purpose: Custom wheel ray tracing 63 | class IPhysicsVehicleWheelTrace { 64 | public: 65 | // Return the physics object the trace hit, or NULL 66 | virtual IPhysicsObject *CastRay(int wheelIndex, const Vector &start, const Vector &end, trace_t &result) = 0; 67 | }; 68 | 69 | // Purpose: Brand new vehicle controller class for the purposes of allowing the game to implement 70 | // their own vehicle types. (Too messy to add this functionality to the normal one) 71 | class CPhysicsVehicleControllerCustom { 72 | public: 73 | CPhysicsVehicleControllerCustom(CPhysicsEnvironment *pEnv, CPhysicsObject *pBody, IPhysicsGameTrace *pGameTrace); 74 | ~CPhysicsVehicleControllerCustom(); 75 | 76 | // force in kg*in/s 77 | void SetWheelForce(int wheelIndex, float force); 78 | void SetWheelBrake(int wheelIndex, float brakeVal); 79 | // steerVal is in degrees! 80 | void SetWheelSteering(int wheelIndex, float steerVal); 81 | 82 | void Update(float dt); 83 | 84 | void CreateWheel(const vehicle_customwheelparams_t ¶ms); 85 | 86 | public: 87 | // Unexposed functions 88 | 89 | private: 90 | CPhysicsEnvironment * m_pEnv; 91 | CPhysicsObject * m_pBody; 92 | IPhysicsGameTrace * m_pGameTrace; 93 | }; 94 | 95 | CPhysicsVehicleControllerCustom CreateVehicleControllerCustom(CPhysicsEnvironment *pEnv, CPhysicsObject *pBody, IPhysicsGameTrace *pGameTrace); 96 | 97 | #endif // PHYSICS_VEHICLECONTROLLERCUSTOM_H -------------------------------------------------------------------------------- /src/StdAfx.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | -------------------------------------------------------------------------------- /src/StdAfx.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include // THIS FILE HAS NO INCLUDE GUARDS! 9 | 10 | // NEW INTERFACE HEADERS 11 | #include "vphysics_interfaceV32.h" 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #if defined(_WIN32) 22 | #define DEBUG_DRAW 0 23 | #endif 24 | 25 | // Thread support is enabled by default 26 | #define BT_THREADSAFE 27 | 28 | // Probably shouldn't be using defines for these. 29 | #define SLEEP_LINEAR_THRESHOLD 0.15 // m/s 30 | #define SLEEP_ANGULAR_THRESHOLD 0.1 // rad/s 31 | 32 | #define NOT_IMPLEMENTED DevWarning("VPhysics UNIMPLEMENTED: %s (%s:%u)\n", __FUNCTION__, __FILE__, __LINE__); 33 | #define NOT_IMPLEMENTED_CRITICAL Error("VPhysics UNIMPLEMENTED: %s (%s:%u)\n", __FUNCTION__, __FILE__, __LINE__); 34 | 35 | // NOTE: Not available on non-MSVC builds due to use of __asm. 36 | //#define NOT_IMPLEMENTED_BREAK {DevWarning("VPhysics UNIMPLEMENTED: %s (%s:%u)\n", __FUNCTION__, __FILE__, __LINE__); __asm int 3;} 37 | -------------------------------------------------------------------------------- /src/convert.h: -------------------------------------------------------------------------------- 1 | #ifndef CONVERT_H 2 | #define CONVERT_H 3 | 4 | #define HL2BULL_FACTOR METERS_PER_INCH 5 | #define HL2BULL_INSQR_PER_METERSQR (1.f / (HL2BULL_FACTOR*HL2BULL_FACTOR)) 6 | 7 | #define BULL2HL(x) (float)((x) * (1.0f/HL2BULL_FACTOR)) 8 | #define HL2BULL(x) (float)((x) * HL2BULL_FACTOR) 9 | 10 | #ifdef _MSC_VER 11 | // Conversion from x to x, possible loss of data 12 | #pragma warning(disable: 4244) 13 | #endif 14 | 15 | // Declarations 16 | inline void ConvertIVPPosToBull(const float *pos, btVector3 &bull); 17 | inline void ConvertPosToBull(const Vector &pos, btVector3 &bull); 18 | inline void ConvertPosToHL(const btVector3 &pos, Vector &hl); 19 | inline void ConvertDirectionToBull(const Vector &dir, btVector3 &bull); 20 | inline void ConvertDirectionToHL(const btVector3 &dir, Vector &hl); 21 | 22 | inline void ConvertAABBToBull(const Vector &hlMins, const Vector &hlMaxs, btVector3 &bullMins, btVector3 &bullMaxs); 23 | inline void ConvertAABBToHL(const btVector3 &bullMins, const btVector3 &bullMaxs, Vector &hlMins, Vector &hlMaxs); 24 | 25 | inline void ConvertForceImpulseToBull(const Vector &pos, btVector3 &bull); 26 | inline void ConvertForceImpulseToHL(const btVector3 &pos, Vector &hl); 27 | inline btScalar ConvertForceImpulseToBull(float hl); 28 | inline float ConvertForceImpulseToHL(btScalar bull); 29 | 30 | inline btScalar ConvertAngleToBull(const float angle); 31 | inline float ConvertAngleToHL(const btScalar &angle); 32 | inline void ConvertRotationToBull(const QAngle &angles, btMatrix3x3 &bull); 33 | inline void ConvertRotationToBull(const QAngle &angles, btQuaternion &bull); 34 | inline void ConvertRotationToHL(const btMatrix3x3 &matrix, QAngle &hl); 35 | inline void ConvertRotationToHL(const btQuaternion &quat, QAngle &hl); 36 | inline void ConvertAngularImpulseToBull(const AngularImpulse &angularimp, btVector3 &bull); 37 | inline void ConvertAngularImpulseToHL(const btVector3 &angularimp, AngularImpulse &hl); 38 | inline void ConvertMatrixToHL(const btTransform &transform, matrix3x4_t &hl); 39 | inline void ConvertMatrixToBull(const matrix3x4_t &hl, btTransform &transform); 40 | 41 | inline float ConvertDistanceToBull(float distance); 42 | inline float ConvertDistanceToHL(float distance); 43 | inline float ConvertEnergyToHL(float energy); 44 | 45 | /************************************************ 46 | * COORDINATE SYSTEMS: 47 | * Bullet vector: Forward, Up, Right 48 | * +x: forward (east) 49 | * +y: up 50 | * +z: right (south) 51 | * 52 | * 53 | * 54 | * HL Vector: Forward, Left, Up 55 | * +x: forward (east) 56 | * +y: left (north) 57 | * +z: up 58 | * 59 | * (top down) 60 | * 61 | * left (y) 62 | * ^ 63 | * | 64 | * (*)------> forward (x) 65 | * up (z) 66 | * 67 | ************************************************/ 68 | 69 | // IVP: Forward down left 70 | // IVP Units in meters 71 | inline void ConvertIVPPosToBull(const float *pos, btVector3 &bull) { 72 | if (!pos) return; 73 | 74 | bull.setX(pos[0]); 75 | bull.setY(-pos[1]); 76 | bull.setZ(-pos[2]); 77 | } 78 | 79 | inline void ConvertPosToBull(const Vector &pos, btVector3 &bull) { 80 | bull.setX(HL2BULL(pos.x)); 81 | bull.setY(HL2BULL(pos.z)); 82 | bull.setZ(-HL2BULL(pos.y)); 83 | } 84 | 85 | inline void ConvertPosToHL(const btVector3 &pos, Vector &hl) { 86 | hl.x = BULL2HL(pos.x()); 87 | hl.y = -BULL2HL(pos.z()); 88 | hl.z = BULL2HL(pos.y()); 89 | } 90 | 91 | inline void ConvertAABBToBull(const Vector &hlMins, const Vector &hlMaxs, btVector3 &bullMins, btVector3 &bullMaxs) { 92 | Assert(hlMins.x <= hlMaxs.x); 93 | Assert(hlMins.y <= hlMaxs.y); 94 | Assert(hlMins.z <= hlMaxs.z); 95 | 96 | Vector halfExtents = (hlMaxs - hlMins) / 2; 97 | btVector3 bullHalfExtents; 98 | ConvertPosToBull(halfExtents, bullHalfExtents); 99 | 100 | Vector center = hlMins + halfExtents; 101 | btVector3 bullCenter; 102 | ConvertPosToBull(center, bullCenter); 103 | 104 | // Half Life AABBs use different corners. 105 | bullHalfExtents.setZ(-bullHalfExtents.z()); 106 | 107 | bullMins = bullCenter - bullHalfExtents; 108 | bullMaxs = bullCenter + bullHalfExtents; 109 | } 110 | 111 | inline void ConvertAABBToHL(const btVector3 &bullMins, const btVector3 &bullMaxs, Vector &hlMins, Vector &hlMaxs) { 112 | Assert(bullMins.x() <= bullMaxs.x()); 113 | Assert(bullMins.y() <= bullMaxs.y()); 114 | Assert(bullMins.z() <= bullMaxs.z()); 115 | 116 | btVector3 halfExtents = (bullMaxs - bullMins) / 2; 117 | Vector hlHalfExtents; 118 | ConvertPosToHL(halfExtents, hlHalfExtents); 119 | 120 | btVector3 center = bullMins + halfExtents; 121 | Vector hlCenter; 122 | ConvertPosToHL(center, hlCenter); 123 | 124 | // Half Life AABBs use different corners. 125 | hlHalfExtents.y = -hlHalfExtents.y; 126 | 127 | hlMins = hlCenter - hlHalfExtents; 128 | hlMaxs = hlCenter + hlHalfExtents; 129 | } 130 | 131 | inline void ConvertDirectionToBull(const Vector &dir, btVector3 &bull) { 132 | bull.setX(dir.x); 133 | bull.setY(dir.z); 134 | bull.setZ(-dir.y); 135 | } 136 | 137 | inline void ConvertDirectionToHL(const btVector3 &dir, Vector &hl) { 138 | hl.x = dir.x(); 139 | hl.y = -dir.z(); 140 | hl.z = dir.y(); 141 | } 142 | 143 | inline void ConvertForceImpulseToBull(const Vector &hl, btVector3 &bull) { 144 | return ConvertPosToBull(hl, bull); 145 | } 146 | 147 | inline void ConvertForceImpulseToHL(const btVector3 &bull, Vector &hl) { 148 | return ConvertPosToHL(bull, hl); 149 | } 150 | 151 | inline btScalar ConvertForceImpulseToBull(float hl) { 152 | return HL2BULL(hl); 153 | } 154 | 155 | inline float ConvertForceImpulseToHL(btScalar bull) { 156 | return BULL2HL(bull); 157 | } 158 | 159 | inline btScalar ConvertAngleToBull(const float angle) { 160 | return DEG2RAD(angle); 161 | } 162 | 163 | inline float ConvertAngleToHL(const btScalar &angle) { 164 | return RAD2DEG(angle); 165 | } 166 | 167 | inline void ConvertRotationToBull(const QAngle &angles, btMatrix3x3 &bull) { 168 | btQuaternion quat; 169 | ConvertRotationToBull(angles, quat); 170 | bull.setRotation(quat); 171 | } 172 | 173 | inline void ConvertRotationToBull(const QAngle &angles, btQuaternion &bull) { 174 | RadianEuler radian(angles); 175 | Quaternion q(radian); 176 | bull.setValue(q.x, q.z, -q.y, q.w); 177 | } 178 | 179 | inline void ConvertRotationToHL(const btMatrix3x3 &matrix, QAngle &hl) { 180 | btQuaternion quat; 181 | matrix.getRotation(quat); 182 | ConvertRotationToHL(quat, hl); 183 | } 184 | 185 | inline void ConvertRotationToHL(const btQuaternion &quat, QAngle &hl) { 186 | Quaternion q(quat.getX(), -quat.getZ(), quat.getY(), quat.getW()); 187 | RadianEuler radian(q); 188 | hl = radian.ToQAngle(); 189 | } 190 | 191 | inline void ConvertAngularImpulseToBull(const AngularImpulse &angularimp, btVector3 &bull) { 192 | bull.setX(DEG2RAD(angularimp.x)); 193 | bull.setY(DEG2RAD(angularimp.z)); 194 | bull.setZ(-DEG2RAD(angularimp.y)); 195 | } 196 | 197 | inline void ConvertAngularImpulseToHL(const btVector3 &angularimp, AngularImpulse &hl) { 198 | hl.x = RAD2DEG(angularimp.x()); 199 | hl.y = -RAD2DEG(angularimp.z()); 200 | hl.z = RAD2DEG(angularimp.y()); 201 | } 202 | 203 | inline void ConvertMatrixToHL(const btTransform &transform, matrix3x4_t &hl) { 204 | Vector forward, left, up, pos; 205 | 206 | ConvertDirectionToHL(transform.getBasis().getColumn(0), forward); 207 | ConvertDirectionToHL(-transform.getBasis().getColumn(2), left); 208 | ConvertDirectionToHL(transform.getBasis().getColumn(1), up); 209 | ConvertPosToHL(transform.getOrigin(), pos); 210 | 211 | hl.Init(forward, left, up, pos); 212 | } 213 | 214 | inline Vector HLGetMatrixColumn(const matrix3x4_t &hl, int col) { 215 | Vector ret; 216 | ret.x = hl[0][col]; 217 | ret.y = hl[1][col]; 218 | ret.z = hl[2][col]; 219 | 220 | return ret; 221 | } 222 | 223 | inline void ConvertMatrixToBull(const matrix3x4_t &hl, btTransform &transform) { 224 | Vector forward, left, up, pos; 225 | 226 | forward = HLGetMatrixColumn(hl, 0); 227 | left = HLGetMatrixColumn(hl, 1); 228 | up = HLGetMatrixColumn(hl, 2); 229 | pos = HLGetMatrixColumn(hl, 3); 230 | 231 | btVector3 bullForward, bullRight, bullUp, origin; 232 | ConvertDirectionToBull(forward, bullForward); 233 | ConvertDirectionToBull(-left, bullRight); 234 | ConvertDirectionToBull(up, bullUp); 235 | ConvertPosToBull(pos, origin); 236 | 237 | transform.setBasis(btMatrix3x3(bullForward.x(), bullUp.x(), bullRight.x(), 238 | bullForward.y(), bullUp.y(), bullRight.y(), 239 | bullForward.z(), bullUp.z(), bullRight.z())); 240 | transform.setOrigin(origin); 241 | } 242 | 243 | inline float ConvertDistanceToBull(float distance) { 244 | return HL2BULL(distance); 245 | } 246 | 247 | inline float ConvertDistanceToHL(float distance) { 248 | return BULL2HL(distance); 249 | } 250 | 251 | inline float ConvertEnergyToHL(float energy) { 252 | return energy * HL2BULL_INSQR_PER_METERSQR; 253 | } 254 | 255 | #ifdef _MSC_VER 256 | #pragma warning (default: 4244) 257 | #endif 258 | 259 | #endif 260 | -------------------------------------------------------------------------------- /src/miscmath.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | 3 | #include "miscmath.h" 4 | 5 | // memdbgon must be the last include file in a .cpp file!!! 6 | #include "tier0/memdbgon.h" 7 | 8 | float AngDragIntegral(float invInertia, float l, float w, float h) { 9 | float w2 = w*w; 10 | float l2 = l*l; 11 | float h2 = h*h; 12 | 13 | return invInertia * ((1.f/3.f)*w2*l*l2 + 0.5 * w2*w2*l + l*w2*h2); 14 | } 15 | 16 | void BtMatrix_vimult(const btMatrix3x3 &matrix, const btVector3 &in, btVector3 &out) { 17 | btScalar a = (matrix.getRow(0).getX()) * in.getX() + (matrix.getRow(1).getX()) * in.getY() + (matrix.getRow(2).getX()) * in.getZ(); 18 | btScalar b = (matrix.getRow(0).getY()) * in.getX() + (matrix.getRow(1).getY()) * in.getY() + (matrix.getRow(2).getY()) * in.getZ(); 19 | btScalar c = (matrix.getRow(0).getZ()) * in.getX() + (matrix.getRow(1).getZ()) * in.getY() + (matrix.getRow(2).getZ()) * in.getZ(); 20 | 21 | out.setX(a); 22 | out.setY(b); 23 | out.setZ(c); 24 | } 25 | 26 | -------------------------------------------------------------------------------- /src/miscmath.h: -------------------------------------------------------------------------------- 1 | #ifndef MISCMATH_H 2 | #define MISCMATH_H 3 | 4 | #include 5 | #include 6 | 7 | #define SAFE_DIVIDE(a, b) ((b) != 0 ? (a)/(b) : 0) 8 | 9 | void BtMatrix_vimult(const btMatrix3x3 &matrix, const btVector3 &in, btVector3 &out); 10 | float AngDragIntegral(float invInertia, float l, float w, float h); 11 | 12 | #endif -------------------------------------------------------------------------------- /src/phydata.h: -------------------------------------------------------------------------------- 1 | #ifndef PHYDATA_H 2 | #define PHYDATA_H 3 | 4 | // Various structures used in ivp mesh parsing. 5 | #include 6 | 7 | // 12 bytes 8 | struct collideheader_t { 9 | DECLARE_BYTESWAP_DATADESC() 10 | 11 | int size; 12 | int vphysicsID; // Generally the ASCII for "VPHY" in newer files 13 | short version; 14 | short modelType; 15 | }; 16 | 17 | // 20 bytes 18 | struct compactsurfaceheader_t { 19 | DECLARE_BYTESWAP_DATADESC() 20 | 21 | int surfaceSize; 22 | Vector dragAxisAreas; 23 | int axisMapSize; 24 | }; 25 | 26 | // 4 bytes 27 | struct moppsurfaceheader_t { 28 | DECLARE_BYTESWAP_DATADESC() 29 | 30 | int moppSize; 31 | }; 32 | 33 | // 48 bytes 34 | // Just like a btCompoundShape. 35 | struct ivpcompactsurface_t { 36 | DECLARE_BYTESWAP_DATADESC() 37 | 38 | float mass_center[3]; 39 | float rotation_inertia[3]; 40 | float upper_limit_radius; 41 | 42 | union { 43 | int bf1; // HACK: Allow datamap to take address of this bitfield 44 | 45 | struct { 46 | int max_deviation : 8; 47 | int byte_size : 24; 48 | }; 49 | }; 50 | 51 | int offset_ledgetree_root; 52 | int dummy[3]; // dummy[2] is "IVPS" or 0 53 | }; 54 | 55 | // Appears to be used on older maps to represent displacements (someone at valve must've been out of their mind when writing that) 56 | struct ivpcompactmopp_t { 57 | DECLARE_BYTESWAP_DATADESC() 58 | 59 | float mass_center[3]; 60 | float rotation_inertia[3]; 61 | float upper_limit_radius; 62 | 63 | union { 64 | int bf1; // HACK: Allow datamap to take address of this bitfield 65 | 66 | struct { 67 | int max_deviation : 8; 68 | int byte_size : 24; 69 | }; 70 | }; 71 | 72 | int offset_ledgetree_root; // offset to root node of internal ledgetree 73 | int offset_ledges; // offset to the ledges 74 | int size_convex_hull; 75 | int dummy; // 16byte memory align 76 | }; 77 | 78 | // 16 bytes 79 | // Just like a btTriangleMesh (although we use btConvexHullShape) 80 | struct ivpcompactledge_t { 81 | DECLARE_BYTESWAP_DATADESC() 82 | 83 | int c_point_offset; // byte offset from 'this' to (ledge) point array 84 | union { 85 | int ledgetree_node_offset; 86 | int client_data; // if indicates a non terminal ledge 87 | }; 88 | 89 | union { 90 | int bf1; 91 | 92 | struct { 93 | uint has_chilren_flag:2; 94 | int is_compact_flag:2; // if false than compact ledge uses points outside this piece of memory 95 | uint dummy:4; 96 | uint size_div_16:24; 97 | }; 98 | }; 99 | 100 | short n_triangles; 101 | short for_future_use; 102 | }; 103 | 104 | // 4 bytes 105 | struct ivpcompactedge_t { 106 | DECLARE_BYTESWAP_DATADESC() 107 | 108 | union { 109 | int bf1; 110 | 111 | struct { 112 | uint start_point_index:16; // point index 113 | int opposite_index:15; // rel to this // maybe extra array, 3 bits more than tri_index/pierce_index 114 | uint is_virtual:1; 115 | }; 116 | }; 117 | }; 118 | 119 | // 16 bytes (4 bytes + 12 bytes edge array) 120 | struct ivpcompacttriangle_t { 121 | DECLARE_BYTESWAP_DATADESC() 122 | 123 | union { 124 | int bf1; 125 | 126 | struct { 127 | uint tri_index : 12; // used for upward navigation 128 | uint pierce_index : 12; 129 | uint material_index : 7; 130 | uint is_virtual : 1; 131 | }; 132 | }; 133 | ivpcompactedge_t c_three_edges[3]; 134 | }; 135 | 136 | // 18 bytes 137 | // IVP has a ledge tree after the vertex data in every solid. 138 | // If this is terminal, offset_compact_ledge is a ledge. Otherwise, it is shape hull. 139 | struct ivpcompactledgenode_t { 140 | DECLARE_BYTESWAP_DATADESC() 141 | 142 | int offset_right_node; // (if != 0 than children 143 | int offset_compact_ledge; // (if != 0, pointer to hull that contains all subelements 144 | float center[3]; // in object_coords 145 | float radius; // size of sphere 146 | unsigned char box_sizes[3]; 147 | unsigned char free_0; 148 | 149 | // Functions 150 | 151 | const ivpcompactledge_t *GetCompactLedge() const { 152 | Assert(this->offset_right_node == 0); 153 | return (ivpcompactledge_t *)((char *)this + this->offset_compact_ledge); 154 | } 155 | 156 | const ivpcompactledgenode_t *GetLeftSon() const { 157 | Assert(this->offset_right_node); 158 | return this + 1; 159 | } 160 | 161 | const ivpcompactledgenode_t *GetRightSon() const { 162 | Assert(this->offset_right_node); 163 | return (ivpcompactledgenode_t *)((char *)this + this->offset_right_node); 164 | } 165 | 166 | bool IsTerminal() const { 167 | return (this->offset_right_node == 0); 168 | } 169 | 170 | const ivpcompactledge_t *GetCompactHull() const { 171 | if (this->offset_compact_ledge) 172 | return (ivpcompactledge_t *)((char *)this + this->offset_compact_ledge); 173 | else 174 | return NULL; 175 | } 176 | }; 177 | 178 | #endif // PHYDATA_H 179 | -------------------------------------------------------------------------------- /src/premake4.lua: -------------------------------------------------------------------------------- 1 | project "vphysics" 2 | 3 | language "C++" 4 | 5 | kind "SharedLib" 6 | 7 | -- Visual studio specific copy command 8 | configuration { "windows", "vs*" } 9 | if GEN_POSTBUILDCOMMANDS then 10 | postbuildcommands { 11 | 'if defined VPHYSICS_GAME_PATH (\n' 12 | .. ' if exist "%VPHYSICS_GAME_PATH%\bin\$(TargetFileName)" (\n' 13 | .. ' attrib -r "%VPHYSICS_GAME_PATH%\bin\$(TargetFileName)"\n' 14 | .. ' del "%VPHYSICS_GAME_PATH%\bin\$(TargetFileName)"\n' 15 | .. ' )\n' 16 | .. ' \n' 17 | .. ' copy "$(TargetPath)" "%VPHYSICS_GAME_PATH%\bin\$(TargetFileName)"\n' 18 | .. ')\n' 19 | } 20 | end 21 | 22 | linkoptions { "/NODEFAULTLIB:\"LIBCMT\"" } 23 | 24 | -- Part of a rediculous hack to get source sdk to build 25 | configuration { "linux", "gmake" } 26 | targetname "vphysics_srv" 27 | targetprefix "" 28 | buildoptions { "-w", "-fpermissive" } 29 | defines { "sprintf_s=snprintf", "strcmpi=strcasecmp", "_alloca=alloca", "stricmp=strcasecmp", "_stricmp=strcasecmp", "strcpy_s=strncpy", "_strnicmp=strncasecmp", "strnicmp=strncasecmp", "_snprintf=snprintf", "_vsnprintf=vsnprintf", "_alloca=alloca", "strcmpi=strcasecmp", "NO_MALLOC_OVERRIDE" } 30 | 31 | configuration {} 32 | 33 | links { "BulletCollision", "BulletDynamics", "LinearMath", "BulletSoftBody", "BulletMultiThreaded" } 34 | 35 | if _PREMAKE_VERSION == "4.4" then 36 | vpaths { 37 | ["Header Files"] = "**.h", 38 | ["Source Files"] = "**.cpp", 39 | ["Resource Files"] = {"**.rc", "resource.h"}, 40 | } 41 | end 42 | 43 | includedirs { 44 | SDK_DIR, 45 | SDK_DIR .. "/public", 46 | SDK_DIR .. "/public/tier0", 47 | SDK_DIR .. "/public/tier1", 48 | "../bullet/src", 49 | "../include" 50 | } 51 | 52 | configuration { "windows" } 53 | libdirs { 54 | SDK_DIR .. "/lib/public", 55 | } 56 | 57 | links { "tier0", "tier1", "tier2", "vstdlib", "mathlib" } 58 | 59 | configuration { "linux", "gmake" } 60 | -- SRCDS_BIN_DIR is nil on windows, and this code runs anyways :( 61 | if os.is("linux") then 62 | libdirs { 63 | SDK_DIR .. "/lib/linux", 64 | SRCDS_BIN_DIR, 65 | } 66 | 67 | -- GCC is terrible with static vs. dynamic 68 | -- FIXME: This doesn't work at all! 69 | linkoptions { 70 | "-static", 71 | "\"" .. path.getabsolute(SDK_DIR) .. "/lib/linux/libtier1_i486.a\"", 72 | "\"" .. path.getabsolute(SDK_DIR) .. "/lib/linux/libmathlib_i486.a\"", 73 | "\"" .. path.getabsolute(SRCDS_BIN_DIR) .. "/libtier0_srv.so\"", 74 | "\"" .. path.getabsolute(SRCDS_BIN_DIR) .. "/libvstdlib_srv.so\"", 75 | } 76 | end 77 | 78 | configuration {} 79 | 80 | files { 81 | "**.cpp", 82 | "**.h" 83 | } -------------------------------------------------------------------------------- /src/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by vphysics.rc 4 | 5 | // Next default values for new objects 6 | // 7 | #ifdef APSTUDIO_INVOKED 8 | #ifndef APSTUDIO_READONLY_SYMBOLS 9 | #define _APS_NEXT_RESOURCE_VALUE 101 10 | #define _APS_NEXT_COMMAND_VALUE 40001 11 | #define _APS_NEXT_CONTROL_VALUE 1001 12 | #define _APS_NEXT_SYMED_VALUE 101 13 | #endif 14 | #endif 15 | -------------------------------------------------------------------------------- /src/vphysics.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dyanikoglu/source-sdk-bullet-physics/3249d9d701ca90942c013e770e83f968a6275dc4/src/vphysics.rc -------------------------------------------------------------------------------- /vphysics.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio Version 16 3 | VisualStudioVersion = 16.0.29519.87 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vphysics", "vphysics.vcxproj", "{D14B5456-0069-453D-A86A-D5B4CB35C6DD}" 6 | ProjectSection(ProjectDependencies) = postProject 7 | {3C3822B7-A147-38D2-ADE9-995D3E3A8FBE} = {3C3822B7-A147-38D2-ADE9-995D3E3A8FBE} 8 | {ABEAB0F1-CA53-33C0-A392-03985BB88C2A} = {ABEAB0F1-CA53-33C0-A392-03985BB88C2A} 9 | {065CC0D7-2215-3CD1-8002-0E82B6421DED} = {065CC0D7-2215-3CD1-8002-0E82B6421DED} 10 | {0174D81F-6A79-37F0-A5D3-9CDBFF2C8892} = {0174D81F-6A79-37F0-A5D3-9CDBFF2C8892} 11 | EndProjectSection 12 | EndProject 13 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Bullet", "Bullet", "{3112246C-4D66-4B81-9895-68B6868C8F9D}" 14 | EndProject 15 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BulletCollision", "thirdparty\bullet3\build_cmake\src\BulletCollision\BulletCollision.vcxproj", "{065CC0D7-2215-3CD1-8002-0E82B6421DED}" 16 | EndProject 17 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BulletDynamics", "thirdparty\bullet3\build_cmake\src\BulletDynamics\BulletDynamics.vcxproj", "{ABEAB0F1-CA53-33C0-A392-03985BB88C2A}" 18 | EndProject 19 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LinearMath", "thirdparty\bullet3\build_cmake\src\LinearMath\LinearMath.vcxproj", "{0174D81F-6A79-37F0-A5D3-9CDBFF2C8892}" 20 | EndProject 21 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BulletSoftBody", "thirdparty\bullet3\build_cmake\src\BulletSoftBody\BulletSoftBody.vcxproj", "{3C3822B7-A147-38D2-ADE9-995D3E3A8FBE}" 22 | EndProject 23 | Global 24 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 25 | Debug|Win32 = Debug|Win32 26 | Release|Win32 = Release|Win32 27 | EndGlobalSection 28 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 29 | {D14B5456-0069-453D-A86A-D5B4CB35C6DD}.Debug|Win32.ActiveCfg = Debug|Win32 30 | {D14B5456-0069-453D-A86A-D5B4CB35C6DD}.Debug|Win32.Build.0 = Debug|Win32 31 | {D14B5456-0069-453D-A86A-D5B4CB35C6DD}.Release|Win32.ActiveCfg = Release|Win32 32 | {D14B5456-0069-453D-A86A-D5B4CB35C6DD}.Release|Win32.Build.0 = Release|Win32 33 | {065CC0D7-2215-3CD1-8002-0E82B6421DED}.Debug|Win32.ActiveCfg = Debug|Win32 34 | {065CC0D7-2215-3CD1-8002-0E82B6421DED}.Debug|Win32.Build.0 = Debug|Win32 35 | {065CC0D7-2215-3CD1-8002-0E82B6421DED}.Release|Win32.ActiveCfg = Release|Win32 36 | {065CC0D7-2215-3CD1-8002-0E82B6421DED}.Release|Win32.Build.0 = Release|Win32 37 | {ABEAB0F1-CA53-33C0-A392-03985BB88C2A}.Debug|Win32.ActiveCfg = Debug|Win32 38 | {ABEAB0F1-CA53-33C0-A392-03985BB88C2A}.Debug|Win32.Build.0 = Debug|Win32 39 | {ABEAB0F1-CA53-33C0-A392-03985BB88C2A}.Release|Win32.ActiveCfg = Release|Win32 40 | {ABEAB0F1-CA53-33C0-A392-03985BB88C2A}.Release|Win32.Build.0 = Release|Win32 41 | {0174D81F-6A79-37F0-A5D3-9CDBFF2C8892}.Debug|Win32.ActiveCfg = Debug|Win32 42 | {0174D81F-6A79-37F0-A5D3-9CDBFF2C8892}.Debug|Win32.Build.0 = Debug|Win32 43 | {0174D81F-6A79-37F0-A5D3-9CDBFF2C8892}.Release|Win32.ActiveCfg = Release|Win32 44 | {0174D81F-6A79-37F0-A5D3-9CDBFF2C8892}.Release|Win32.Build.0 = Release|Win32 45 | {3C3822B7-A147-38D2-ADE9-995D3E3A8FBE}.Debug|Win32.ActiveCfg = Debug|Win32 46 | {3C3822B7-A147-38D2-ADE9-995D3E3A8FBE}.Debug|Win32.Build.0 = Debug|Win32 47 | {3C3822B7-A147-38D2-ADE9-995D3E3A8FBE}.Release|Win32.ActiveCfg = Release|Win32 48 | {3C3822B7-A147-38D2-ADE9-995D3E3A8FBE}.Release|Win32.Build.0 = Release|Win32 49 | EndGlobalSection 50 | GlobalSection(SolutionProperties) = preSolution 51 | HideSolutionNode = FALSE 52 | EndGlobalSection 53 | GlobalSection(NestedProjects) = preSolution 54 | {065CC0D7-2215-3CD1-8002-0E82B6421DED} = {3112246C-4D66-4B81-9895-68B6868C8F9D} 55 | {ABEAB0F1-CA53-33C0-A392-03985BB88C2A} = {3112246C-4D66-4B81-9895-68B6868C8F9D} 56 | {0174D81F-6A79-37F0-A5D3-9CDBFF2C8892} = {3112246C-4D66-4B81-9895-68B6868C8F9D} 57 | {3C3822B7-A147-38D2-ADE9-995D3E3A8FBE} = {3112246C-4D66-4B81-9895-68B6868C8F9D} 58 | EndGlobalSection 59 | GlobalSection(ExtensibilityGlobals) = postSolution 60 | SolutionGuid = {D59EAEFF-BE53-404D-9922-E8880BF89813} 61 | EndGlobalSection 62 | EndGlobal 63 | -------------------------------------------------------------------------------- /vphysics.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | $(VCTargetsPath11) 15 | 16 | 17 | {D14B5456-0069-453D-A86A-D5B4CB35C6DD} 18 | vphysics 19 | 10.0 20 | 21 | 22 | 23 | DynamicLibrary 24 | v120 25 | MultiByte 26 | true 27 | 28 | 29 | DynamicLibrary 30 | v120 31 | MultiByte 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | <_ProjectFileVersion>11.0.50214.1 45 | 46 | 47 | C:\Program Files (x86)\Steam\steamapps\common\Source SDK Base 2013 Singleplayer\bin\ 48 | $(SolutionDir)build\obj\$(Platform)\$(ProjectName)\$(Configuration)\ 49 | vphysics 50 | true 51 | 52 | 53 | C:\Program Files (x86)\Steam\steamapps\common\Source SDK Base 2013 Singleplayer\bin\ 54 | $(SolutionDir)build\obj\$(Platform)\$(ProjectName)\$(Configuration)\ 55 | vphysics 56 | false 57 | 58 | 59 | 60 | Disabled 61 | $(SolutionDir)thirdparty\bullet3\src;$(SolutionDir)include;$(SolutionDir)thirdparty\sourcesdk\sp\src\public;$(SolutionDir)thirdparty\sourcesdk\sp\src\public\tier0;$(SolutionDir)thirdparty\sourcesdk\sp\src\public\tier1;%(AdditionalIncludeDirectories) 62 | false 63 | EnableFastChecks 64 | MultiThreadedDebug 65 | Use 66 | Level4 67 | ProgramDatabase 68 | _WINDLL;_DEBUG;%(PreprocessorDefinitions) 69 | StreamingSIMDExtensions2 70 | Fast 71 | false 72 | true 73 | Disabled 74 | true 75 | 76 | 77 | tier0.lib;tier1.lib;tier2.lib;mathlib.lib;vstdlib.lib;BulletCollision_Debug.lib;BulletDynamics_Debug.lib;BulletSoftBody_Debug.lib;LinearMath_Debug.lib;tbb.lib;%(AdditionalDependencies) 78 | $(SolutionDir)thirdparty\bullet3\build_cmake\lib\Debug;$(SolutionDir)thirdparty\sourcesdk\sp\src\lib\public;$(SolutionDir)thirdparty\tbb\lib\ia32\vc14;%(AdditionalLibraryDirectories) 79 | LIBCMT;%(IgnoreSpecificDefaultLibraries) 80 | true 81 | NotSet 82 | MachineX86 83 | true 84 | $(IntDir)$(TargetName).map 85 | true 86 | false 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | if defined VPHYSICS_GAME_PATH ( 102 | if exist "%VPHYSICS_GAME_PATH%\bin\$(TargetFileName)" ( 103 | attrib -r "%VPHYSICS_GAME_PATH%\bin\$(TargetFileName)" 104 | del "%VPHYSICS_GAME_PATH%\bin\$(TargetFileName)" 105 | ) 106 | 107 | copy "$(TargetPath)" "%VPHYSICS_GAME_PATH%\bin\$(TargetFileName)" 108 | ) 109 | Copy vphysics. Make sure VPHYSICS_GAME_PATH points to the exe dir 110 | 111 | 112 | 113 | 114 | $(SolutionDir)thirdparty\bullet3\src;$(SolutionDir)include;$(SolutionDir)thirdparty\sourcesdk\sp\src\public;$(SolutionDir)thirdparty\sourcesdk\sp\src\public\tier0;$(SolutionDir)thirdparty\sourcesdk\sp\src\public\tier1;%(AdditionalIncludeDirectories) 115 | MultiThreaded 116 | Use 117 | Level4 118 | ProgramDatabase 119 | _WINDLL;_RELEASE;%(PreprocessorDefinitions) 120 | StreamingSIMDExtensions2 121 | Speed 122 | MaxSpeed 123 | Fast 124 | true 125 | true 126 | AnySuitable 127 | true 128 | true 129 | 130 | 131 | 132 | 133 | tier0.lib;tier1.lib;tier2.lib;mathlib.lib;vstdlib.lib;BulletCollision.lib;BulletDynamics.lib;BulletSoftBody.lib;LinearMath.lib;tbb.lib;%(AdditionalDependencies) 134 | $(SolutionDir)thirdparty\bullet3\build_cmake\lib\Release;$(SolutionDir)thirdparty\sourcesdk\sp\src\lib\public;$(SolutionDir)thirdparty\tbb\lib\ia32\vc14;%(AdditionalLibraryDirectories) 135 | true 136 | NotSet 137 | true 138 | true 139 | MachineX86 140 | true 141 | $(IntDir)$(TargetName).map 142 | true 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | if defined VPHYSICS_GAME_PATH ( 158 | if exist "%VPHYSICS_GAME_PATH%\bin\$(TargetFileName)" ( 159 | attrib -r "%VPHYSICS_GAME_PATH%\bin\$(TargetFileName)" 160 | del "%VPHYSICS_GAME_PATH%\bin\$(TargetFileName)" 161 | ) 162 | 163 | copy "$(TargetPath)" "%VPHYSICS_GAME_PATH%\bin\$(TargetFileName)" 164 | ) 165 | Copy vphysics. Make sure VPHYSICS_GAME_PATH points to the exe dir 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | Create 192 | Create 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | -------------------------------------------------------------------------------- /vphysics.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {3003d71b-49bc-4b75-b1e8-5d5ff5da87b7} 14 | 15 | 16 | 17 | 18 | Source Files 19 | 20 | 21 | Source Files 22 | 23 | 24 | Source Files 25 | 26 | 27 | Source Files 28 | 29 | 30 | Source Files 31 | 32 | 33 | Source Files 34 | 35 | 36 | Source Files 37 | 38 | 39 | Source Files 40 | 41 | 42 | Source Files 43 | 44 | 45 | Source Files 46 | 47 | 48 | Source Files 49 | 50 | 51 | Source Files 52 | 53 | 54 | Source Files 55 | 56 | 57 | Source Files 58 | 59 | 60 | Source Files 61 | 62 | 63 | Source Files 64 | 65 | 66 | Source Files 67 | 68 | 69 | Source Files 70 | 71 | 72 | Source Files 73 | 74 | 75 | Source Files 76 | 77 | 78 | Source Files 79 | 80 | 81 | Source Files 82 | 83 | 84 | 85 | 86 | Header Files 87 | 88 | 89 | Header Files 90 | 91 | 92 | Header Files 93 | 94 | 95 | Header Files\public 96 | 97 | 98 | Header Files 99 | 100 | 101 | Header Files 102 | 103 | 104 | Header Files 105 | 106 | 107 | Header Files 108 | 109 | 110 | Header Files 111 | 112 | 113 | Header Files 114 | 115 | 116 | Header Files 117 | 118 | 119 | Header Files 120 | 121 | 122 | Header Files 123 | 124 | 125 | Header Files 126 | 127 | 128 | Header Files 129 | 130 | 131 | Header Files 132 | 133 | 134 | Header Files 135 | 136 | 137 | Header Files 138 | 139 | 140 | Header Files 141 | 142 | 143 | Header Files 144 | 145 | 146 | Header Files 147 | 148 | 149 | Header Files 150 | 151 | 152 | Header Files\public 153 | 154 | 155 | Header Files 156 | 157 | 158 | Header Files 159 | 160 | 161 | Header Files 162 | 163 | 164 | Header Files 165 | 166 | 167 | Header Files 168 | 169 | 170 | Header Files\public 171 | 172 | 173 | Header Files\public 174 | 175 | 176 | 177 | 178 | 179 | --------------------------------------------------------------------------------