2015-12-21 21:12:35 +01:00
/**********************************************************************************************
*
2021-01-20 20:55:12 +01:00
* Physac v1 .1 - 2 D Physics library for videogames
2015-12-21 21:12:35 +01:00
*
2017-04-16 19:08:34 +02:00
* DESCRIPTION :
2017-02-16 00:50:02 +01:00
*
2017-04-16 19:08:34 +02:00
* Physac is a small 2 D physics engine written in pure C . The engine uses a fixed time - step thread loop
* to simluate physics . A physics step contains the following phases : get collision information ,
* apply dynamics , collision solving and position correction . It uses a very simple struct for physic
2017-02-16 00:50:02 +01:00
* bodies with a position vector to be used in any 3 D rendering API .
2017-04-16 19:08:34 +02:00
*
2016-06-09 20:01:59 +02:00
* CONFIGURATION :
2017-04-16 19:08:34 +02:00
*
2016-06-09 20:01:59 +02:00
* # define PHYSAC_IMPLEMENTATION
* Generates the implementation of the library into the included file .
2017-04-16 19:08:34 +02:00
* If not defined , the library is in header only mode and can be included in other headers
2016-06-09 20:01:59 +02:00
* or source files without problems . But only ONE file should hold the implementation .
*
2021-01-20 20:55:12 +01:00
* # define PHYSAC_DEBUG
* Show debug traces log messages about physic bodies creation / destruction , physic system errors ,
2021-08-15 12:52:12 +02:00
* some calculations results and NULL reference exceptions .
2016-06-09 20:01:59 +02:00
*
2021-01-20 20:55:12 +01:00
* # define PHYSAC_AVOID_TIMMING_SYSTEM
* Disables internal timming system , used by UpdatePhysics ( ) to launch timmed physic steps ,
* it allows just running UpdatePhysics ( ) automatically on a separate thread at a desired time step .
* In case physics steps update needs to be controlled by user with a custom timming mechanism ,
* just define this flag and the internal timming mechanism will be avoided , in that case ,
* timming libraries are neither required by the module .
2016-11-21 20:30:46 +01:00
*
2016-06-09 20:01:59 +02:00
* # define PHYSAC_MALLOC ( )
2021-01-20 20:55:12 +01:00
* # define PHYSAC_CALLOC ( )
2016-06-09 20:01:59 +02:00
* # define PHYSAC_FREE ( )
* You can define your own malloc / free implementation replacing stdlib . h malloc ( ) / free ( ) functions .
* Otherwise it will include stdlib . h and use the C standard library malloc ( ) / free ( ) function .
*
2021-01-20 20:55:12 +01:00
* COMPILATION :
2017-03-06 22:57:33 +01:00
*
2021-01-20 20:55:12 +01:00
* Use the following code to compile with GCC :
* gcc - o $ ( NAME_PART ) . exe $ ( FILE_NAME ) - s - static - lraylib - lopengl32 - lgdi32 - lwinmm - std = c99
2017-03-06 22:57:33 +01:00
*
2021-01-20 20:55:12 +01:00
* VERSIONS HISTORY :
* 1.1 ( 20 - Jan - 2021 ) @ raysan5 : Library general revision
* Removed threading system ( up to the user )
* Support MSVC C + + compilation using CLITERAL ( )
* Review DEBUG mechanism for TRACELOG ( ) and all TRACELOG ( ) messages
* Review internal variables / functions naming for consistency
* Allow option to avoid internal timming system , to allow app manage the steps
* 1.0 ( 12 - Jun - 2017 ) First release of the library
2017-02-16 00:50:02 +01:00
*
2016-06-09 20:01:59 +02:00
*
* LICENSE : zlib / libpng
*
2021-01-20 20:55:12 +01:00
* Copyright ( c ) 2016 - 2021 Victor Fisac ( @ victorfisac ) and Ramon Santamaria ( @ raysan5 )
2015-12-21 21:12:35 +01:00
*
* This software is provided " as-is " , without any express or implied warranty . In no event
* will the authors be held liable for any damages arising from the use of this software .
*
* Permission is granted to anyone to use this software for any purpose , including commercial
* applications , and to alter it and redistribute it freely , subject to the following restrictions :
*
* 1. The origin of this software must not be misrepresented ; you must not claim that you
* wrote the original software . If you use this software in a product , an acknowledgment
* in the product documentation would be appreciated but is not required .
*
* 2. Altered source versions must be plainly marked as such , and must not be misrepresented
* as being the original software .
*
* 3. This notice may not be removed or altered from any source distribution .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-11-21 20:30:46 +01:00
# if !defined(PHYSAC_H)
2015-12-30 13:42:59 +01:00
# define PHYSAC_H
2015-12-21 21:12:35 +01:00
2021-11-23 13:21:01 -08:00
// Function specifiers in case library is build/used as a shared library (Windows)
// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll
# if defined(_WIN32)
# if defined(BUILD_LIBTYPE_SHARED)
# define PHYSACDEF __declspec(dllexport) // We are building the library as a Win32 shared library (.dll)
# elif defined(USE_LIBTYPE_SHARED)
# define PHYSACDEF __declspec(dllimport) // We are using the library as a Win32 shared library (.dll)
# endif
# endif
2021-08-15 12:52:12 +02:00
# ifndef PHYSACDEF
# define PHYSACDEF // We are building or using physac as a static library
2016-06-09 20:01:59 +02:00
# endif
2020-02-10 10:56:39 +01:00
// Allow custom memory allocators
# ifndef PHYSAC_MALLOC
# define PHYSAC_MALLOC(size) malloc(size)
# endif
2021-01-20 20:55:12 +01:00
# ifndef PHYSAC_CALLOC
# define PHYSAC_CALLOC(size, n) calloc(size, n)
# endif
2020-02-10 10:56:39 +01:00
# ifndef PHYSAC_FREE
# define PHYSAC_FREE(ptr) free(ptr)
# endif
2015-12-21 21:12:35 +01:00
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
2021-01-20 20:55:12 +01:00
# define PHYSAC_MAX_BODIES 64 // Maximum number of physic bodies supported
# define PHYSAC_MAX_MANIFOLDS 4096 // Maximum number of physic bodies interactions (64x64)
# define PHYSAC_MAX_VERTICES 24 // Maximum number of vertex for polygons shapes
# define PHYSAC_DEFAULT_CIRCLE_VERTICES 24 // Default number of vertices for circle shapes
2016-11-21 20:30:46 +01:00
2020-01-29 12:09:56 +01:00
# define PHYSAC_COLLISION_ITERATIONS 100
# define PHYSAC_PENETRATION_ALLOWANCE 0.05f
# define PHYSAC_PENETRATION_CORRECTION 0.4f
2016-11-21 20:30:46 +01:00
2021-02-20 02:15:40 -08:00
# define PHYSAC_PI 3.14159265358979323846f
2020-01-29 12:09:56 +01:00
# define PHYSAC_DEG2RAD (PHYSAC_PI / 180.0f)
2016-11-21 20:30:46 +01:00
2021-01-13 01:12:14 +06:00
//----------------------------------------------------------------------------------
// Data Types Structure Definition
//----------------------------------------------------------------------------------
2021-01-20 20:55:12 +01:00
# if defined(__STDC__) && __STDC_VERSION__ >= 199901L
# include <stdbool.h>
# endif
2021-01-13 01:12:14 +06:00
2021-01-20 20:55:12 +01:00
typedef enum PhysicsShapeType { PHYSICS_CIRCLE = 0 , PHYSICS_POLYGON } PhysicsShapeType ;
2016-11-21 20:30:46 +01:00
// Previously defined to be used in PhysicsShape struct as circular dependencies
typedef struct PhysicsBodyData * PhysicsBody ;
2021-08-15 12:52:12 +02:00
# if !defined(RL_VECTOR2_TYPE)
2021-01-20 20:55:12 +01:00
// Vector2 type
typedef struct Vector2 {
float x ;
float y ;
} Vector2 ;
# endif
2021-01-13 01:12:14 +06:00
// Matrix2x2 type (used for polygon shape rotation matrix)
typedef struct Matrix2x2 {
float m00 ;
float m01 ;
float m10 ;
float m11 ;
} Matrix2x2 ;
2021-01-20 20:55:12 +01:00
typedef struct PhysicsVertexData {
unsigned int vertexCount ; // Vertex count (positions and normals)
Vector2 positions [ PHYSAC_MAX_VERTICES ] ; // Vertex positions vectors
Vector2 normals [ PHYSAC_MAX_VERTICES ] ; // Vertex normals vectors
} PhysicsVertexData ;
2021-01-13 01:12:14 +06:00
typedef struct PhysicsShape {
2021-01-20 20:55:12 +01:00
PhysicsShapeType type ; // Shape type (circle or polygon)
PhysicsBody body ; // Shape physics body data pointer
PhysicsVertexData vertexData ; // Shape vertices data (used for polygon shapes)
float radius ; // Shape radius (used for circle shapes)
2021-01-13 01:12:14 +06:00
Matrix2x2 transform ; // Vertices transform matrix 2x2
} PhysicsShape ;
typedef struct PhysicsBodyData {
2021-01-20 20:55:12 +01:00
unsigned int id ; // Unique identifier
2021-01-13 01:12:14 +06:00
bool enabled ; // Enabled dynamics state (collisions are calculated anyway)
Vector2 position ; // Physics body shape pivot
Vector2 velocity ; // Current linear velocity applied to position
Vector2 force ; // Current linear force (reset to 0 every step)
float angularVelocity ; // Current angular velocity applied to orient
float torque ; // Current angular force (reset to 0 every step)
float orient ; // Rotation in radians
float inertia ; // Moment of inertia
float inverseInertia ; // Inverse value of inertia
float mass ; // Physics body mass
float inverseMass ; // Inverse value of mass
float staticFriction ; // Friction when the body has not movement (0 to 1)
float dynamicFriction ; // Friction when the body has movement (0 to 1)
float restitution ; // Restitution coefficient of the body (0 to 1)
bool useGravity ; // Apply gravity force to dynamics
bool isGrounded ; // Physics grounded on other body state
bool freezeOrient ; // Physics rotation constraint
2021-01-20 20:55:12 +01:00
PhysicsShape shape ; // Physics body shape information (type, radius, vertices, transform)
2021-01-13 01:12:14 +06:00
} PhysicsBodyData ;
typedef struct PhysicsManifoldData {
2021-01-20 20:55:12 +01:00
unsigned int id ; // Unique identifier
2021-01-13 01:12:14 +06:00
PhysicsBody bodyA ; // Manifold first physics body reference
PhysicsBody bodyB ; // Manifold second physics body reference
float penetration ; // Depth of penetration from collision
Vector2 normal ; // Normal direction vector from 'a' to 'b'
Vector2 contacts [ 2 ] ; // Points of contact during collision
unsigned int contactsCount ; // Current collision number of contacts
float restitution ; // Mixed restitution during collision
float dynamicFriction ; // Mixed dynamic friction during collision
float staticFriction ; // Mixed static friction during collision
} PhysicsManifoldData , * PhysicsManifold ;
2015-12-21 21:12:35 +01:00
//----------------------------------------------------------------------------------
2016-03-05 17:05:02 +01:00
// Module Functions Declaration
2015-12-21 21:12:35 +01:00
//----------------------------------------------------------------------------------
2021-08-15 12:52:12 +02:00
# if defined(__cplusplus)
extern " C " { // Prevents name mangling of functions
# endif
2021-01-20 20:55:12 +01:00
// Physics system management
PHYSACDEF void InitPhysics ( void ) ; // Initializes physics system
PHYSACDEF void UpdatePhysics ( void ) ; // Update physics system
PHYSACDEF void ResetPhysics ( void ) ; // Reset physics system (global variables)
PHYSACDEF void ClosePhysics ( void ) ; // Close physics system and unload used memory
2018-09-23 13:55:39 +02:00
PHYSACDEF void SetPhysicsTimeStep ( double delta ) ; // Sets physics fixed time step in milliseconds. 1.666666 by default
2016-11-21 20:30:46 +01:00
PHYSACDEF void SetPhysicsGravity ( float x , float y ) ; // Sets physics global gravity force
2021-01-20 20:55:12 +01:00
// Physic body creation/destroy
2016-11-21 20:30:46 +01:00
PHYSACDEF PhysicsBody CreatePhysicsBodyCircle ( Vector2 pos , float radius , float density ) ; // Creates a new circle physics body with generic parameters
PHYSACDEF PhysicsBody CreatePhysicsBodyRectangle ( Vector2 pos , float width , float height , float density ) ; // Creates a new rectangle physics body with generic parameters
PHYSACDEF PhysicsBody CreatePhysicsBodyPolygon ( Vector2 pos , float radius , int sides , float density ) ; // Creates a new polygon physics body with generic parameters
2021-01-20 20:55:12 +01:00
PHYSACDEF void DestroyPhysicsBody ( PhysicsBody body ) ; // Destroy a physics body
// Physic body forces
2016-11-21 20:30:46 +01:00
PHYSACDEF void PhysicsAddForce ( PhysicsBody body , Vector2 force ) ; // Adds a force to a physics body
PHYSACDEF void PhysicsAddTorque ( PhysicsBody body , float amount ) ; // Adds an angular force to a physics body
PHYSACDEF void PhysicsShatter ( PhysicsBody body , Vector2 position , float force ) ; // Shatters a polygon shape physics body to little physics bodies with explosion force
2021-01-20 20:55:12 +01:00
PHYSACDEF void SetPhysicsBodyRotation ( PhysicsBody body , float radians ) ; // Sets physics body shape transform based on radians parameter
// Query physics info
2016-11-21 20:30:46 +01:00
PHYSACDEF PhysicsBody GetPhysicsBody ( int index ) ; // Returns a physics body of the bodies pool at a specific index
2021-01-20 20:55:12 +01:00
PHYSACDEF int GetPhysicsBodiesCount ( void ) ; // Returns the current amount of created physics bodies
2016-11-21 20:30:46 +01:00
PHYSACDEF int GetPhysicsShapeType ( int index ) ; // Returns the physics body shape type (PHYSICS_CIRCLE or PHYSICS_POLYGON)
PHYSACDEF int GetPhysicsShapeVerticesCount ( int index ) ; // Returns the amount of vertices of a physics body shape
PHYSACDEF Vector2 GetPhysicsShapeVertex ( PhysicsBody body , int vertex ) ; // Returns transformed position of a body shape (body position + vertex transformed position)
# if defined(__cplusplus)
}
# endif
2015-12-21 21:12:35 +01:00
2015-12-30 13:42:59 +01:00
# endif // PHYSAC_H
2016-06-09 20:01:59 +02:00
/***********************************************************************************
*
* PHYSAC IMPLEMENTATION
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# if defined(PHYSAC_IMPLEMENTATION)
2020-02-10 10:56:39 +01:00
// Support TRACELOG macros
2016-11-21 20:30:46 +01:00
# if defined(PHYSAC_DEBUG)
# include <stdio.h> // Required for: printf()
2020-02-10 10:56:39 +01:00
# define TRACELOG(...) printf(__VA_ARGS__)
# else
2021-01-20 20:55:12 +01:00
# define TRACELOG(...) (void)0;
2016-06-14 20:23:46 +02:00
# endif
2016-06-12 22:07:06 +02:00
2021-01-20 20:55:12 +01:00
# include <stdlib.h> // Required for: malloc(), calloc(), free()
2016-11-21 20:30:46 +01:00
# include <math.h> // Required for: cosf(), sinf(), fabs(), sqrtf()
2017-12-24 15:59:03 +01:00
2021-01-20 20:55:12 +01:00
# if !defined(PHYSAC_AVOID_TIMMING_SYSTEM)
// Time management functionality
2021-08-15 12:52:12 +02:00
# include <time.h> // Required for: time(), clock_gettime()
2021-01-20 20:55:12 +01:00
# if defined(_WIN32)
2021-08-15 12:52:12 +02:00
# if defined(__cplusplus)
extern " C " { // Prevents name mangling of functions
# endif
2021-01-20 20:55:12 +01:00
// Functions required to query time on Windows
int __stdcall QueryPerformanceCounter ( unsigned long long int * lpPerformanceCount ) ;
int __stdcall QueryPerformanceFrequency ( unsigned long long int * lpFrequency ) ;
2021-08-15 12:52:12 +02:00
# if defined(__cplusplus)
}
# endif
2021-03-02 12:45:23 +01:00
# endif
# if defined(__linux__) || defined(__FreeBSD__)
2021-01-20 20:55:12 +01:00
# if _POSIX_C_SOURCE < 199309L
# undef _POSIX_C_SOURCE
# define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext.
# endif
# include <sys/time.h> // Required for: timespec
2021-03-02 12:45:23 +01:00
# endif
# if defined(__APPLE__) // macOS also defines __MACH__
2021-01-20 20:55:12 +01:00
# include <mach/mach_time.h> // Required for: mach_absolute_time()
# endif
2017-12-24 15:59:03 +01:00
# endif
2016-11-21 20:30:46 +01:00
2021-01-20 20:55:12 +01:00
// NOTE: MSVC C++ compiler does not support compound literals (C99 feature)
// Plain structures in C++ (without constructors) can be initialized from { } initializers.
# if defined(__cplusplus)
# define CLITERAL(type) type
# else
# define CLITERAL(type) (type)
2017-12-24 15:59:03 +01:00
# endif
2017-05-16 15:23:01 +02:00
2016-06-09 20:01:59 +02:00
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
2021-01-20 20:55:12 +01:00
# define PHYSAC_MIN(a,b) (((a)<(b))?(a):(b))
# define PHYSAC_MAX(a,b) (((a)>(b))?(a):(b))
# define PHYSAC_FLT_MAX 3.402823466e+38f
# define PHYSAC_EPSILON 0.000001f
# define PHYSAC_K 1.0f / 3.0f
# define PHYSAC_VECTOR_ZERO CLITERAL(Vector2){ 0.0f, 0.0f }
2016-06-09 20:01:59 +02:00
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
2021-01-20 20:55:12 +01:00
static double deltaTime = 1.0 / 60.0 / 10.0 * 1000 ; // Delta time in milliseconds used for physics steps
# if !defined(PHYSAC_AVOID_TIMMING_SYSTEM)
// Time measure variables
static double baseClockTicks = 0.0 ; // Offset clock ticks for MONOTONIC clock
static unsigned long long int frequency = 0 ; // Hi-res clock frequency
2018-03-10 19:25:17 +01:00
static double startTime = 0.0 ; // Start time in milliseconds
static double currentTime = 0.0 ; // Current time in milliseconds
2021-01-20 20:55:12 +01:00
# endif
2017-12-24 15:59:03 +01:00
2021-01-20 20:55:12 +01:00
// Physics system configuration
2016-11-21 20:30:46 +01:00
static PhysicsBody bodies [ PHYSAC_MAX_BODIES ] ; // Physics bodies pointers array
static unsigned int physicsBodiesCount = 0 ; // Physics world current bodies counter
static PhysicsManifold contacts [ PHYSAC_MAX_MANIFOLDS ] ; // Physics bodies pointers array
static unsigned int physicsManifoldsCount = 0 ; // Physics world current manifolds counter
2016-06-09 20:01:59 +02:00
2021-01-20 20:55:12 +01:00
static Vector2 gravityForce = { 0.0f , 9.81f } ; // Physics world gravity force
// Utilities variables
static unsigned int usedMemory = 0 ; // Total allocated dynamic memory
2016-06-09 20:01:59 +02:00
//----------------------------------------------------------------------------------
2016-11-21 20:30:46 +01:00
// Module Internal Functions Declaration
2016-06-09 20:01:59 +02:00
//----------------------------------------------------------------------------------
2021-01-20 20:55:12 +01:00
# if !defined(PHYSAC_AVOID_TIMMING_SYSTEM)
// Timming measure functions
2021-06-17 12:26:33 +02:00
static void InitTimerHiRes ( void ) ; // Initializes hi-resolution MONOTONIC timer
2021-01-20 20:55:12 +01:00
static unsigned long long int GetClockTicks ( void ) ; // Get hi-res MONOTONIC time measure in mseconds
static double GetCurrentTime ( void ) ; // Get current time measure in milliseconds
# endif
static void UpdatePhysicsStep ( void ) ; // Update physics step (dynamics, collisions and position corrections)
2018-03-10 19:25:17 +01:00
static int FindAvailableBodyIndex ( ) ; // Finds a valid index for a new physics body initialization
static int FindAvailableManifoldIndex ( ) ; // Finds a valid index for a new manifold initialization
2021-01-20 20:55:12 +01:00
static PhysicsVertexData CreateDefaultPolygon ( float radius , int sides ) ; // Creates a random polygon shape with max vertex distance from polygon pivot
static PhysicsVertexData CreateRectanglePolygon ( Vector2 pos , Vector2 size ) ; // Creates a rectangle polygon shape based on a min and max positions
static void InitializePhysicsManifolds ( PhysicsManifold manifold ) ; // Initializes physics manifolds to solve collisions
2016-11-21 20:30:46 +01:00
static PhysicsManifold CreatePhysicsManifold ( PhysicsBody a , PhysicsBody b ) ; // Creates a new physics manifold to solve collision
static void DestroyPhysicsManifold ( PhysicsManifold manifold ) ; // Unitializes and destroys a physics manifold
2021-01-20 20:55:12 +01:00
2016-11-21 20:30:46 +01:00
static void SolvePhysicsManifold ( PhysicsManifold manifold ) ; // Solves a created physics manifold between two physics bodies
static void SolveCircleToCircle ( PhysicsManifold manifold ) ; // Solves collision between two circle shape physics bodies
static void SolveCircleToPolygon ( PhysicsManifold manifold ) ; // Solves collision between a circle to a polygon shape physics bodies
static void SolvePolygonToCircle ( PhysicsManifold manifold ) ; // Solves collision between a polygon to a circle shape physics bodies
static void SolvePolygonToPolygon ( PhysicsManifold manifold ) ; // Solves collision between two polygons shape physics bodies
static void IntegratePhysicsForces ( PhysicsBody body ) ; // Integrates physics forces into velocity
static void IntegratePhysicsVelocity ( PhysicsBody body ) ; // Integrates physics velocity into position and forces
2021-01-20 20:55:12 +01:00
static void IntegratePhysicsImpulses ( PhysicsManifold manifold ) ; // Integrates physics collisions impulses to solve collisions
2016-11-21 20:30:46 +01:00
static void CorrectPhysicsPositions ( PhysicsManifold manifold ) ; // Corrects physics bodies positions based on manifolds collision information
static void FindIncidentFace ( Vector2 * v0 , Vector2 * v1 , PhysicsShape ref , PhysicsShape inc , int index ) ; // Finds two polygon shapes incident face
2021-01-20 20:55:12 +01:00
static float FindAxisLeastPenetration ( int * faceIndex , PhysicsShape shapeA , PhysicsShape shapeB ) ; // Finds polygon shapes axis least penetration
2016-11-21 20:30:46 +01:00
2021-01-20 20:55:12 +01:00
// Math required functions
static Vector2 MathVector2Product ( Vector2 vector , float value ) ; // Returns the product of a vector and a value
static float MathVector2CrossProduct ( Vector2 v1 , Vector2 v2 ) ; // Returns the cross product of two vectors
static float MathVector2SqrLen ( Vector2 vector ) ; // Returns the len square root of a vector
static float MathVector2DotProduct ( Vector2 v1 , Vector2 v2 ) ; // Returns the dot product of two vectors
static inline float MathVector2SqrDistance ( Vector2 v1 , Vector2 v2 ) ; // Returns the square root of distance between two vectors
static void MathVector2Normalize ( Vector2 * vector ) ; // Returns the normalized values of a vector
static Vector2 MathVector2Add ( Vector2 v1 , Vector2 v2 ) ; // Returns the sum of two given vectors
static Vector2 MathVector2Subtract ( Vector2 v1 , Vector2 v2 ) ; // Returns the subtract of two given vectors
static Matrix2x2 MathMatFromRadians ( float radians ) ; // Returns a matrix 2x2 from a given radians value
static inline Matrix2x2 MathMatTranspose ( Matrix2x2 matrix ) ; // Returns the transpose of a given matrix 2x2
static inline Vector2 MathMatVector2Product ( Matrix2x2 matrix , Vector2 vector ) ; // Returns product between matrix 2x2 and vector
static int MathVector2Clip ( Vector2 normal , Vector2 * faceA , Vector2 * faceB , float clip ) ; // Returns clipping value based on a normal and two faces
static Vector2 MathTriangleBarycenter ( Vector2 v1 , Vector2 v2 , Vector2 v3 ) ; // Returns the barycenter of a triangle given by 3 points
2016-06-09 20:01:59 +02:00
//----------------------------------------------------------------------------------
// Module Functions Definition
//----------------------------------------------------------------------------------
2021-01-20 20:55:12 +01:00
2016-11-21 20:30:46 +01:00
// Initializes physics values, pointers and creates physics loop thread
2021-08-15 12:52:12 +02:00
void InitPhysics ( void )
2016-11-21 20:30:46 +01:00
{
2021-01-20 20:55:12 +01:00
# if !defined(PHYSAC_AVOID_TIMMING_SYSTEM)
2018-07-29 13:09:30 +02:00
// Initialize high resolution timer
2021-06-17 12:26:33 +02:00
InitTimerHiRes ( ) ;
2021-01-20 20:55:12 +01:00
# endif
2018-07-29 13:09:30 +02:00
2021-01-20 20:55:12 +01:00
TRACELOG ( " [PHYSAC] Physics module initialized successfully \n " ) ;
2016-11-21 20:30:46 +01:00
}
// Sets physics global gravity force
2021-08-15 12:52:12 +02:00
void SetPhysicsGravity ( float x , float y )
2016-11-21 20:30:46 +01:00
{
gravityForce . x = x ;
gravityForce . y = y ;
2016-06-14 20:38:49 +02:00
}
2016-11-21 20:30:46 +01:00
// Creates a new circle physics body with generic parameters
2021-08-15 12:52:12 +02:00
PhysicsBody CreatePhysicsBodyCircle ( Vector2 pos , float radius , float density )
2016-06-14 20:38:49 +02:00
{
2021-01-20 20:55:12 +01:00
PhysicsBody body = CreatePhysicsBodyPolygon ( pos , radius , PHYSAC_DEFAULT_CIRCLE_VERTICES , density ) ;
return body ;
2016-06-14 20:38:49 +02:00
}
2016-11-21 20:30:46 +01:00
// Creates a new rectangle physics body with generic parameters
2021-08-15 12:52:12 +02:00
PhysicsBody CreatePhysicsBodyRectangle ( Vector2 pos , float width , float height , float density )
2016-06-14 20:38:49 +02:00
{
2021-01-20 20:55:12 +01:00
// NOTE: Make sure body data is initialized to 0
PhysicsBody body = ( PhysicsBody ) PHYSAC_CALLOC ( sizeof ( PhysicsBodyData ) , 1 ) ;
2016-11-21 20:30:46 +01:00
usedMemory + = sizeof ( PhysicsBodyData ) ;
2021-01-20 20:55:12 +01:00
int id = FindAvailableBodyIndex ( ) ;
if ( id ! = - 1 )
2016-06-14 20:38:49 +02:00
{
2016-11-21 20:30:46 +01:00
// Initialize new body with generic values
2021-01-20 20:55:12 +01:00
body - > id = id ;
body - > enabled = true ;
body - > position = pos ;
body - > shape . type = PHYSICS_POLYGON ;
body - > shape . body = body ;
body - > shape . transform = MathMatFromRadians ( 0.0f ) ;
body - > shape . vertexData = CreateRectanglePolygon ( pos , CLITERAL ( Vector2 ) { width , height } ) ;
2016-11-21 20:30:46 +01:00
// Calculate centroid and moment of inertia
2018-03-10 19:25:17 +01:00
Vector2 center = { 0.0f , 0.0f } ;
float area = 0.0f ;
float inertia = 0.0f ;
2016-11-21 20:30:46 +01:00
2021-02-20 02:15:40 -08:00
for ( unsigned int i = 0 ; i < body - > shape . vertexData . vertexCount ; i + + )
2016-11-21 20:30:46 +01:00
{
// Triangle vertices, third vertex implied as (0, 0)
2021-01-20 20:55:12 +01:00
Vector2 p1 = body - > shape . vertexData . positions [ i ] ;
2021-02-20 02:15:40 -08:00
unsigned int nextIndex = ( ( ( i + 1 ) < body - > shape . vertexData . vertexCount ) ? ( i + 1 ) : 0 ) ;
2021-01-20 20:55:12 +01:00
Vector2 p2 = body - > shape . vertexData . positions [ nextIndex ] ;
2016-11-21 20:30:46 +01:00
2021-01-20 20:55:12 +01:00
float D = MathVector2CrossProduct ( p1 , p2 ) ;
2016-11-21 20:30:46 +01:00
float triangleArea = D / 2 ;
area + = triangleArea ;
// Use area to weight the centroid average, not just vertex position
2018-03-10 19:25:17 +01:00
center . x + = triangleArea * PHYSAC_K * ( p1 . x + p2 . x ) ;
center . y + = triangleArea * PHYSAC_K * ( p1 . y + p2 . y ) ;
2016-11-21 20:30:46 +01:00
float intx2 = p1 . x * p1 . x + p2 . x * p1 . x + p2 . x * p2 . x ;
float inty2 = p1 . y * p1 . y + p2 . y * p1 . y + p2 . y * p2 . y ;
2018-03-10 19:25:17 +01:00
inertia + = ( 0.25f * PHYSAC_K * D ) * ( intx2 + inty2 ) ;
2016-11-21 20:30:46 +01:00
}
center . x * = 1.0f / area ;
center . y * = 1.0f / area ;
// Translate vertices to centroid (make the centroid (0, 0) for the polygon in model space)
// Note: this is not really necessary
2021-02-20 02:15:40 -08:00
for ( unsigned int i = 0 ; i < body - > shape . vertexData . vertexCount ; i + + )
2016-06-14 20:38:49 +02:00
{
2021-01-20 20:55:12 +01:00
body - > shape . vertexData . positions [ i ] . x - = center . x ;
body - > shape . vertexData . positions [ i ] . y - = center . y ;
2016-06-14 20:38:49 +02:00
}
2016-11-21 20:30:46 +01:00
2021-01-20 20:55:12 +01:00
body - > mass = density * area ;
body - > inverseMass = ( ( body - > mass ! = 0.0f ) ? 1.0f / body - > mass : 0.0f ) ;
body - > inertia = density * inertia ;
body - > inverseInertia = ( ( body - > inertia ! = 0.0f ) ? 1.0f / body - > inertia : 0.0f ) ;
body - > staticFriction = 0.4f ;
body - > dynamicFriction = 0.2f ;
body - > restitution = 0.0f ;
body - > useGravity = true ;
body - > isGrounded = false ;
body - > freezeOrient = false ;
2016-11-21 20:30:46 +01:00
// Add new body to bodies pointers array and update bodies count
2021-01-20 20:55:12 +01:00
bodies [ physicsBodiesCount ] = body ;
2016-11-21 20:30:46 +01:00
physicsBodiesCount + + ;
2021-01-20 20:55:12 +01:00
TRACELOG ( " [PHYSAC] Physic body created successfully (id: %i) \n " , body - > id ) ;
2016-06-14 20:38:49 +02:00
}
2021-01-20 20:55:12 +01:00
else TRACELOG ( " [PHYSAC] Physic body could not be created, PHYSAC_MAX_BODIES reached \n " ) ;
2016-11-21 20:30:46 +01:00
2021-01-20 20:55:12 +01:00
return body ;
2016-06-14 20:38:49 +02:00
}
2016-11-21 20:30:46 +01:00
// Creates a new polygon physics body with generic parameters
2021-08-15 12:52:12 +02:00
PhysicsBody CreatePhysicsBodyPolygon ( Vector2 pos , float radius , int sides , float density )
2016-06-14 20:38:49 +02:00
{
2021-01-20 20:55:12 +01:00
PhysicsBody body = ( PhysicsBody ) PHYSAC_MALLOC ( sizeof ( PhysicsBodyData ) ) ;
2016-11-21 20:30:46 +01:00
usedMemory + = sizeof ( PhysicsBodyData ) ;
2021-01-20 20:55:12 +01:00
int id = FindAvailableBodyIndex ( ) ;
if ( id ! = - 1 )
2016-06-14 20:38:49 +02:00
{
2016-11-21 20:30:46 +01:00
// Initialize new body with generic values
2021-01-20 20:55:12 +01:00
body - > id = id ;
body - > enabled = true ;
body - > position = pos ;
body - > velocity = PHYSAC_VECTOR_ZERO ;
body - > force = PHYSAC_VECTOR_ZERO ;
body - > angularVelocity = 0.0f ;
body - > torque = 0.0f ;
body - > orient = 0.0f ;
body - > shape . type = PHYSICS_POLYGON ;
body - > shape . body = body ;
body - > shape . transform = MathMatFromRadians ( 0.0f ) ;
body - > shape . vertexData = CreateDefaultPolygon ( radius , sides ) ;
2016-11-21 20:30:46 +01:00
// Calculate centroid and moment of inertia
2018-03-10 19:25:17 +01:00
Vector2 center = { 0.0f , 0.0f } ;
float area = 0.0f ;
float inertia = 0.0f ;
2016-11-21 20:30:46 +01:00
2021-02-20 02:15:40 -08:00
for ( unsigned int i = 0 ; i < body - > shape . vertexData . vertexCount ; i + + )
2016-11-21 20:30:46 +01:00
{
// Triangle vertices, third vertex implied as (0, 0)
2021-01-20 20:55:12 +01:00
Vector2 position1 = body - > shape . vertexData . positions [ i ] ;
2021-02-20 02:15:40 -08:00
unsigned int nextIndex = ( ( ( i + 1 ) < body - > shape . vertexData . vertexCount ) ? ( i + 1 ) : 0 ) ;
2021-01-20 20:55:12 +01:00
Vector2 position2 = body - > shape . vertexData . positions [ nextIndex ] ;
2016-11-21 20:30:46 +01:00
2021-01-20 20:55:12 +01:00
float cross = MathVector2CrossProduct ( position1 , position2 ) ;
2016-11-21 20:30:46 +01:00
float triangleArea = cross / 2 ;
area + = triangleArea ;
// Use area to weight the centroid average, not just vertex position
2018-03-10 19:25:17 +01:00
center . x + = triangleArea * PHYSAC_K * ( position1 . x + position2 . x ) ;
center . y + = triangleArea * PHYSAC_K * ( position1 . y + position2 . y ) ;
2016-11-21 20:30:46 +01:00
float intx2 = position1 . x * position1 . x + position2 . x * position1 . x + position2 . x * position2 . x ;
float inty2 = position1 . y * position1 . y + position2 . y * position1 . y + position2 . y * position2 . y ;
2018-03-10 19:25:17 +01:00
inertia + = ( 0.25f * PHYSAC_K * cross ) * ( intx2 + inty2 ) ;
2016-11-21 20:30:46 +01:00
}
center . x * = 1.0f / area ;
center . y * = 1.0f / area ;
// Translate vertices to centroid (make the centroid (0, 0) for the polygon in model space)
// Note: this is not really necessary
2021-02-20 02:15:40 -08:00
for ( unsigned int i = 0 ; i < body - > shape . vertexData . vertexCount ; i + + )
2016-11-21 20:30:46 +01:00
{
2021-01-20 20:55:12 +01:00
body - > shape . vertexData . positions [ i ] . x - = center . x ;
body - > shape . vertexData . positions [ i ] . y - = center . y ;
2016-11-21 20:30:46 +01:00
}
2021-01-20 20:55:12 +01:00
body - > mass = density * area ;
body - > inverseMass = ( ( body - > mass ! = 0.0f ) ? 1.0f / body - > mass : 0.0f ) ;
body - > inertia = density * inertia ;
body - > inverseInertia = ( ( body - > inertia ! = 0.0f ) ? 1.0f / body - > inertia : 0.0f ) ;
body - > staticFriction = 0.4f ;
body - > dynamicFriction = 0.2f ;
body - > restitution = 0.0f ;
body - > useGravity = true ;
body - > isGrounded = false ;
body - > freezeOrient = false ;
2016-11-21 20:30:46 +01:00
// Add new body to bodies pointers array and update bodies count
2021-01-20 20:55:12 +01:00
bodies [ physicsBodiesCount ] = body ;
2016-11-21 20:30:46 +01:00
physicsBodiesCount + + ;
2021-01-20 20:55:12 +01:00
TRACELOG ( " [PHYSAC] Physic body created successfully (id: %i) \n " , body - > id ) ;
2016-06-14 20:38:49 +02:00
}
2021-01-20 20:55:12 +01:00
else TRACELOG ( " [PHYSAC] Physics body could not be created, PHYSAC_MAX_BODIES reached \n " ) ;
2016-11-21 20:30:46 +01:00
2021-01-20 20:55:12 +01:00
return body ;
2016-11-21 20:30:46 +01:00
}
// Adds a force to a physics body
2021-08-15 12:52:12 +02:00
void PhysicsAddForce ( PhysicsBody body , Vector2 force )
2016-11-21 20:30:46 +01:00
{
2021-01-20 20:55:12 +01:00
if ( body ! = NULL ) body - > force = MathVector2Add ( body - > force , force ) ;
2016-11-21 20:30:46 +01:00
}
// Adds an angular force to a physics body
2021-08-15 12:52:12 +02:00
void PhysicsAddTorque ( PhysicsBody body , float amount )
2016-11-21 20:30:46 +01:00
{
if ( body ! = NULL ) body - > torque + = amount ;
2016-06-14 20:38:49 +02:00
}
2016-11-21 20:30:46 +01:00
// Shatters a polygon shape physics body to little physics bodies with explosion force
2021-08-15 12:52:12 +02:00
void PhysicsShatter ( PhysicsBody body , Vector2 position , float force )
2016-06-14 20:38:49 +02:00
{
2016-11-21 20:30:46 +01:00
if ( body ! = NULL )
2016-06-14 20:38:49 +02:00
{
2016-11-21 20:30:46 +01:00
if ( body - > shape . type = = PHYSICS_POLYGON )
2016-06-14 20:38:49 +02:00
{
2021-01-20 20:55:12 +01:00
PhysicsVertexData vertexData = body - > shape . vertexData ;
2016-11-21 20:30:46 +01:00
bool collision = false ;
2016-06-14 20:38:49 +02:00
2021-02-20 02:15:40 -08:00
for ( unsigned int i = 0 ; i < vertexData . vertexCount ; i + + )
2016-06-14 20:38:49 +02:00
{
2016-11-21 20:30:46 +01:00
Vector2 positionA = body - > position ;
2021-01-20 20:55:12 +01:00
Vector2 positionB = MathMatVector2Product ( body - > shape . transform , MathVector2Add ( body - > position , vertexData . positions [ i ] ) ) ;
2021-02-20 02:15:40 -08:00
unsigned int nextIndex = ( ( ( i + 1 ) < vertexData . vertexCount ) ? ( i + 1 ) : 0 ) ;
2021-01-20 20:55:12 +01:00
Vector2 positionC = MathMatVector2Product ( body - > shape . transform , MathVector2Add ( body - > position , vertexData . positions [ nextIndex ] ) ) ;
2016-11-21 20:30:46 +01:00
// Check collision between each triangle
float alpha = ( ( positionB . y - positionC . y ) * ( position . x - positionC . x ) + ( positionC . x - positionB . x ) * ( position . y - positionC . y ) ) /
( ( positionB . y - positionC . y ) * ( positionA . x - positionC . x ) + ( positionC . x - positionB . x ) * ( positionA . y - positionC . y ) ) ;
float beta = ( ( positionC . y - positionA . y ) * ( position . x - positionC . x ) + ( positionA . x - positionC . x ) * ( position . y - positionC . y ) ) /
( ( positionB . y - positionC . y ) * ( positionA . x - positionC . x ) + ( positionC . x - positionB . x ) * ( positionA . y - positionC . y ) ) ;
float gamma = 1.0f - alpha - beta ;
2018-03-10 19:25:17 +01:00
if ( ( alpha > 0.0f ) & & ( beta > 0.0f ) & ( gamma > 0.0f ) )
2016-11-21 20:30:46 +01:00
{
collision = true ;
break ;
}
2016-06-14 20:38:49 +02:00
}
2016-11-21 20:30:46 +01:00
if ( collision )
2016-06-14 20:38:49 +02:00
{
2016-11-21 20:30:46 +01:00
int count = vertexData . vertexCount ;
Vector2 bodyPos = body - > position ;
2020-02-10 10:56:39 +01:00
Vector2 * vertices = ( Vector2 * ) PHYSAC_MALLOC ( sizeof ( Vector2 ) * count ) ;
2020-01-29 12:09:35 +01:00
Matrix2x2 trans = body - > shape . transform ;
2018-03-10 19:25:17 +01:00
for ( int i = 0 ; i < count ; i + + ) vertices [ i ] = vertexData . positions [ i ] ;
2016-11-21 20:30:46 +01:00
// Destroy shattered physics body
DestroyPhysicsBody ( body ) ;
for ( int i = 0 ; i < count ; i + + )
{
int nextIndex = ( ( ( i + 1 ) < count ) ? ( i + 1 ) : 0 ) ;
2021-01-20 20:55:12 +01:00
Vector2 center = MathTriangleBarycenter ( vertices [ i ] , vertices [ nextIndex ] , PHYSAC_VECTOR_ZERO ) ;
center = MathVector2Add ( bodyPos , center ) ;
Vector2 offset = MathVector2Subtract ( center , bodyPos ) ;
2016-11-21 20:30:46 +01:00
2021-01-20 20:55:12 +01:00
PhysicsBody body = CreatePhysicsBodyPolygon ( center , 10 , 3 , 10 ) ; // Create polygon physics body with relevant values
2016-11-21 20:30:46 +01:00
2021-01-20 20:55:12 +01:00
PhysicsVertexData vertexData = { 0 } ;
vertexData . vertexCount = 3 ;
2016-11-21 20:30:46 +01:00
2021-01-20 20:55:12 +01:00
vertexData . positions [ 0 ] = MathVector2Subtract ( vertices [ i ] , offset ) ;
vertexData . positions [ 1 ] = MathVector2Subtract ( vertices [ nextIndex ] , offset ) ;
vertexData . positions [ 2 ] = MathVector2Subtract ( position , center ) ;
2016-11-21 20:30:46 +01:00
// Separate vertices to avoid unnecessary physics collisions
2021-01-20 20:55:12 +01:00
vertexData . positions [ 0 ] . x * = 0.95f ;
vertexData . positions [ 0 ] . y * = 0.95f ;
vertexData . positions [ 1 ] . x * = 0.95f ;
vertexData . positions [ 1 ] . y * = 0.95f ;
vertexData . positions [ 2 ] . x * = 0.95f ;
vertexData . positions [ 2 ] . y * = 0.95f ;
2016-11-21 20:30:46 +01:00
// Calculate polygon faces normals
2021-02-20 02:15:40 -08:00
for ( unsigned int j = 0 ; j < vertexData . vertexCount ; j + + )
2016-11-21 20:30:46 +01:00
{
2021-02-20 02:15:40 -08:00
unsigned int nextVertex = ( ( ( j + 1 ) < vertexData . vertexCount ) ? ( j + 1 ) : 0 ) ;
2021-01-20 20:55:12 +01:00
Vector2 face = MathVector2Subtract ( vertexData . positions [ nextVertex ] , vertexData . positions [ j ] ) ;
2016-11-21 20:30:46 +01:00
2021-01-20 20:55:12 +01:00
vertexData . normals [ j ] = CLITERAL ( Vector2 ) { face . y , - face . x } ;
MathVector2Normalize ( & vertexData . normals [ j ] ) ;
2016-11-21 20:30:46 +01:00
}
// Apply computed vertex data to new physics body shape
2021-01-20 20:55:12 +01:00
body - > shape . vertexData = vertexData ;
body - > shape . transform = trans ;
2016-11-21 20:30:46 +01:00
// Calculate centroid and moment of inertia
2018-03-10 19:25:17 +01:00
center = PHYSAC_VECTOR_ZERO ;
float area = 0.0f ;
float inertia = 0.0f ;
2016-11-21 20:30:46 +01:00
2021-02-20 02:15:40 -08:00
for ( unsigned int j = 0 ; j < body - > shape . vertexData . vertexCount ; j + + )
2016-11-21 20:30:46 +01:00
{
// Triangle vertices, third vertex implied as (0, 0)
2021-01-20 20:55:12 +01:00
Vector2 p1 = body - > shape . vertexData . positions [ j ] ;
2021-02-20 02:15:40 -08:00
unsigned int nextVertex = ( ( ( j + 1 ) < body - > shape . vertexData . vertexCount ) ? ( j + 1 ) : 0 ) ;
2021-01-20 20:55:12 +01:00
Vector2 p2 = body - > shape . vertexData . positions [ nextVertex ] ;
2016-11-21 20:30:46 +01:00
2021-01-20 20:55:12 +01:00
float D = MathVector2CrossProduct ( p1 , p2 ) ;
2016-11-21 20:30:46 +01:00
float triangleArea = D / 2 ;
area + = triangleArea ;
// Use area to weight the centroid average, not just vertex position
2018-03-10 19:25:17 +01:00
center . x + = triangleArea * PHYSAC_K * ( p1 . x + p2 . x ) ;
center . y + = triangleArea * PHYSAC_K * ( p1 . y + p2 . y ) ;
2016-11-21 20:30:46 +01:00
float intx2 = p1 . x * p1 . x + p2 . x * p1 . x + p2 . x * p2 . x ;
float inty2 = p1 . y * p1 . y + p2 . y * p1 . y + p2 . y * p2 . y ;
2018-03-10 19:25:17 +01:00
inertia + = ( 0.25f * PHYSAC_K * D ) * ( intx2 + inty2 ) ;
2016-11-21 20:30:46 +01:00
}
center . x * = 1.0f / area ;
center . y * = 1.0f / area ;
2021-01-20 20:55:12 +01:00
body - > mass = area ;
body - > inverseMass = ( ( body - > mass ! = 0.0f ) ? 1.0f / body - > mass : 0.0f ) ;
body - > inertia = inertia ;
body - > inverseInertia = ( ( body - > inertia ! = 0.0f ) ? 1.0f / body - > inertia : 0.0f ) ;
2016-11-21 20:30:46 +01:00
// Calculate explosion force direction
2021-01-20 20:55:12 +01:00
Vector2 pointA = body - > position ;
Vector2 pointB = MathVector2Subtract ( vertexData . positions [ 1 ] , vertexData . positions [ 0 ] ) ;
2018-03-10 19:25:17 +01:00
pointB . x / = 2.0f ;
pointB . y / = 2.0f ;
2021-01-20 20:55:12 +01:00
Vector2 forceDirection = MathVector2Subtract ( MathVector2Add ( pointA , MathVector2Add ( vertexData . positions [ 0 ] , pointB ) ) , body - > position ) ;
MathVector2Normalize ( & forceDirection ) ;
2016-11-21 20:30:46 +01:00
forceDirection . x * = force ;
forceDirection . y * = force ;
// Apply force to new physics body
2021-01-20 20:55:12 +01:00
PhysicsAddForce ( body , forceDirection ) ;
2016-11-21 20:30:46 +01:00
}
2018-10-10 21:52:50 +02:00
2020-02-10 10:56:39 +01:00
PHYSAC_FREE ( vertices ) ;
2016-06-14 20:38:49 +02:00
}
}
}
2021-01-20 20:55:12 +01:00
else TRACELOG ( " [PHYSAC] WARNING: PhysicsShatter: NULL physic body \n " ) ;
2016-06-14 20:38:49 +02:00
}
2016-11-21 20:30:46 +01:00
// Returns the current amount of created physics bodies
2021-08-15 12:52:12 +02:00
int GetPhysicsBodiesCount ( void )
2016-06-14 20:38:49 +02:00
{
2016-11-21 20:30:46 +01:00
return physicsBodiesCount ;
2016-06-14 20:38:49 +02:00
}
2016-11-21 20:30:46 +01:00
// Returns a physics body of the bodies pool at a specific index
2021-08-15 12:52:12 +02:00
PhysicsBody GetPhysicsBody ( int index )
2016-06-14 20:38:49 +02:00
{
2017-04-16 19:08:34 +02:00
PhysicsBody body = NULL ;
2018-03-10 19:25:17 +01:00
2021-02-20 02:15:40 -08:00
if ( index < ( int ) physicsBodiesCount )
2016-06-14 20:38:49 +02:00
{
2017-04-16 19:08:34 +02:00
body = bodies [ index ] ;
2018-03-10 19:25:17 +01:00
2021-01-20 20:55:12 +01:00
if ( body = = NULL ) TRACELOG ( " [PHYSAC] WARNING: GetPhysicsBody: NULL physic body \n " ) ;
2016-06-14 20:38:49 +02:00
}
2021-01-20 20:55:12 +01:00
else TRACELOG ( " [PHYSAC] WARNING: Physic body index is out of bounds \n " ) ;
2018-03-10 19:25:17 +01:00
2017-04-16 19:08:34 +02:00
return body ;
2016-06-14 20:38:49 +02:00
}
2016-11-21 20:30:46 +01:00
// Returns the physics body shape type (PHYSICS_CIRCLE or PHYSICS_POLYGON)
2021-08-15 12:52:12 +02:00
int GetPhysicsShapeType ( int index )
2016-06-14 20:38:49 +02:00
{
2017-04-16 19:08:34 +02:00
int result = - 1 ;
2018-03-10 19:25:17 +01:00
2021-02-20 02:15:40 -08:00
if ( index < ( int ) physicsBodiesCount )
2016-06-14 20:38:49 +02:00
{
2016-11-21 20:30:46 +01:00
PhysicsBody body = bodies [ index ] ;
2018-03-10 19:25:17 +01:00
2017-04-16 19:08:34 +02:00
if ( body ! = NULL ) result = body - > shape . type ;
2021-01-20 20:55:12 +01:00
else TRACELOG ( " [PHYSAC] WARNING: GetPhysicsShapeType: NULL physic body \n " ) ;
2016-06-14 20:38:49 +02:00
}
2021-01-20 20:55:12 +01:00
else TRACELOG ( " [PHYSAC] WARNING: Physic body index is out of bounds \n " ) ;
2018-03-10 19:25:17 +01:00
2017-04-16 19:08:34 +02:00
return result ;
2016-06-14 20:38:49 +02:00
}
2016-11-21 20:30:46 +01:00
// Returns the amount of vertices of a physics body shape
2021-08-15 12:52:12 +02:00
int GetPhysicsShapeVerticesCount ( int index )
2016-06-14 20:38:49 +02:00
{
2017-04-16 19:08:34 +02:00
int result = 0 ;
2018-03-10 19:25:17 +01:00
2021-02-20 02:15:40 -08:00
if ( index < ( int ) physicsBodiesCount )
2016-11-21 20:30:46 +01:00
{
PhysicsBody body = bodies [ index ] ;
2018-03-10 19:25:17 +01:00
2016-11-21 20:30:46 +01:00
if ( body ! = NULL )
{
switch ( body - > shape . type )
{
2021-01-20 20:55:12 +01:00
case PHYSICS_CIRCLE : result = PHYSAC_DEFAULT_CIRCLE_VERTICES ; break ;
2017-04-16 19:08:34 +02:00
case PHYSICS_POLYGON : result = body - > shape . vertexData . vertexCount ; break ;
2016-11-21 20:30:46 +01:00
default : break ;
}
}
2021-01-20 20:55:12 +01:00
else TRACELOG ( " [PHYSAC] WARNING: GetPhysicsShapeVerticesCount: NULL physic body \n " ) ;
2016-11-21 20:30:46 +01:00
}
2021-01-20 20:55:12 +01:00
else TRACELOG ( " [PHYSAC] WARNING: Physic body index is out of bounds \n " ) ;
2018-03-10 19:25:17 +01:00
2017-04-16 19:08:34 +02:00
return result ;
2016-06-14 20:38:49 +02:00
}
2016-11-21 20:30:46 +01:00
// Returns transformed position of a body shape (body position + vertex transformed position)
2021-08-15 12:52:12 +02:00
Vector2 GetPhysicsShapeVertex ( PhysicsBody body , int vertex )
2016-06-14 20:38:49 +02:00
{
2018-03-10 19:25:17 +01:00
Vector2 position = { 0.0f , 0.0f } ;
2016-06-14 20:38:49 +02:00
2016-11-21 20:30:46 +01:00
if ( body ! = NULL )
{
switch ( body - > shape . type )
{
case PHYSICS_CIRCLE :
{
2021-01-20 20:55:12 +01:00
position . x = body - > position . x + cosf ( 360.0f / PHYSAC_DEFAULT_CIRCLE_VERTICES * vertex * PHYSAC_DEG2RAD ) * body - > shape . radius ;
position . y = body - > position . y + sinf ( 360.0f / PHYSAC_DEFAULT_CIRCLE_VERTICES * vertex * PHYSAC_DEG2RAD ) * body - > shape . radius ;
2016-11-21 20:30:46 +01:00
} break ;
case PHYSICS_POLYGON :
{
2021-01-20 20:55:12 +01:00
PhysicsVertexData vertexData = body - > shape . vertexData ;
position = MathVector2Add ( body - > position , MathMatVector2Product ( body - > shape . transform , vertexData . positions [ vertex ] ) ) ;
2016-11-21 20:30:46 +01:00
} break ;
default : break ;
}
}
2021-01-20 20:55:12 +01:00
else TRACELOG ( " [PHYSAC] WARNING: GetPhysicsShapeVertex: NULL physic body \n " ) ;
2016-06-14 20:38:49 +02:00
2016-11-21 20:30:46 +01:00
return position ;
2016-06-14 20:38:49 +02:00
}
2016-11-21 20:30:46 +01:00
// Sets physics body shape transform based on radians parameter
2021-08-15 12:52:12 +02:00
void SetPhysicsBodyRotation ( PhysicsBody body , float radians )
2016-06-14 20:38:49 +02:00
{
2016-11-21 20:30:46 +01:00
if ( body ! = NULL )
{
body - > orient = radians ;
2021-01-20 20:55:12 +01:00
if ( body - > shape . type = = PHYSICS_POLYGON ) body - > shape . transform = MathMatFromRadians ( radians ) ;
2016-11-21 20:30:46 +01:00
}
2016-06-14 20:38:49 +02:00
}
2016-11-21 20:30:46 +01:00
// Unitializes and destroys a physics body
2021-08-15 12:52:12 +02:00
void DestroyPhysicsBody ( PhysicsBody body )
2016-06-09 20:01:59 +02:00
{
2016-11-21 20:30:46 +01:00
if ( body ! = NULL )
2016-06-09 20:01:59 +02:00
{
2016-11-21 20:30:46 +01:00
int id = body - > id ;
int index = - 1 ;
2021-02-20 02:15:40 -08:00
for ( unsigned int i = 0 ; i < physicsBodiesCount ; i + + )
2016-06-09 20:01:59 +02:00
{
2016-11-21 20:30:46 +01:00
if ( bodies [ i ] - > id = = id )
2016-06-11 18:35:46 +02:00
{
2016-11-21 20:30:46 +01:00
index = i ;
break ;
2016-06-09 20:01:59 +02:00
}
}
2016-11-21 20:30:46 +01:00
2019-10-29 16:03:21 +01:00
if ( index = = - 1 )
{
2021-01-20 20:55:12 +01:00
TRACELOG ( " [PHYSAC] WARNING: Requested body (id: %i) can not be found \n " , id ) ;
2019-10-29 16:03:21 +01:00
return ; // Prevent access to index -1
}
2016-11-21 20:30:46 +01:00
// Free body allocated memory
2018-03-10 19:25:17 +01:00
PHYSAC_FREE ( body ) ;
2016-11-21 20:30:46 +01:00
usedMemory - = sizeof ( PhysicsBodyData ) ;
bodies [ index ] = NULL ;
// Reorder physics bodies pointers array and its catched index
2021-02-20 02:15:40 -08:00
for ( unsigned int i = index ; i < physicsBodiesCount ; i + + )
2016-11-21 20:30:46 +01:00
{
if ( ( i + 1 ) < physicsBodiesCount ) bodies [ i ] = bodies [ i + 1 ] ;
}
// Update physics bodies count
physicsBodiesCount - - ;
2021-01-20 20:55:12 +01:00
TRACELOG ( " [PHYSAC] Physic body destroyed successfully (id: %i) \n " , id ) ;
2016-11-21 20:30:46 +01:00
}
2021-01-20 20:55:12 +01:00
else TRACELOG ( " [PHYSAC] WARNING: DestroyPhysicsBody: NULL physic body \n " ) ;
2016-11-21 20:30:46 +01:00
}
// Destroys created physics bodies and manifolds and resets global values
2021-08-15 12:52:12 +02:00
void ResetPhysics ( void )
2016-11-21 20:30:46 +01:00
{
2021-02-20 02:15:40 -08:00
if ( physicsBodiesCount > 0 )
2016-11-21 20:30:46 +01:00
{
2021-02-20 02:15:40 -08:00
// Unitialize physics bodies dynamic memory allocations
2021-04-28 19:27:50 +02:00
for ( int i = physicsBodiesCount - 1 ; i > = 0 ; i - - )
2016-11-21 20:30:46 +01:00
{
2021-02-20 02:15:40 -08:00
PhysicsBody body = bodies [ i ] ;
if ( body ! = NULL )
{
PHYSAC_FREE ( body ) ;
bodies [ i ] = NULL ;
usedMemory - = sizeof ( PhysicsBodyData ) ;
}
2016-11-21 20:30:46 +01:00
}
2021-02-20 02:15:40 -08:00
physicsBodiesCount = 0 ;
}
2016-11-21 20:30:46 +01:00
2021-02-20 02:15:40 -08:00
if ( physicsManifoldsCount > 0 )
2016-11-21 20:30:46 +01:00
{
2021-02-20 02:15:40 -08:00
// Unitialize physics manifolds dynamic memory allocations
2021-04-28 19:27:50 +02:00
for ( int i = physicsManifoldsCount - 1 ; i > = 0 ; i - - )
2016-11-21 20:30:46 +01:00
{
2021-02-20 02:15:40 -08:00
PhysicsManifold manifold = contacts [ i ] ;
if ( manifold ! = NULL )
{
PHYSAC_FREE ( manifold ) ;
contacts [ i ] = NULL ;
usedMemory - = sizeof ( PhysicsManifoldData ) ;
}
2016-11-21 20:30:46 +01:00
}
2021-02-20 02:15:40 -08:00
physicsManifoldsCount = 0 ;
}
2016-11-21 20:30:46 +01:00
2021-01-20 20:55:12 +01:00
TRACELOG ( " [PHYSAC] Physics module reseted successfully \n " ) ;
2016-11-21 20:30:46 +01:00
}
// Unitializes physics pointers and exits physics loop thread
2021-08-15 12:52:12 +02:00
void ClosePhysics ( void )
2016-11-21 20:30:46 +01:00
{
2018-09-23 13:55:39 +02:00
// Unitialize physics manifolds dynamic memory allocations
2021-02-20 02:15:40 -08:00
if ( physicsManifoldsCount > 0 )
{
2021-07-04 20:29:20 +02:00
for ( int i = physicsManifoldsCount - 1 ; i > = 0 ; i - - ) DestroyPhysicsManifold ( contacts [ i ] ) ;
2021-02-20 02:15:40 -08:00
}
2018-09-23 13:55:39 +02:00
// Unitialize physics bodies dynamic memory allocations
2021-02-20 02:15:40 -08:00
if ( physicsBodiesCount > 0 )
{
2021-07-04 20:29:20 +02:00
for ( int i = physicsBodiesCount - 1 ; i > = 0 ; i - - ) DestroyPhysicsBody ( bodies [ i ] ) ;
2021-02-20 02:15:40 -08:00
}
2018-09-23 13:55:39 +02:00
2021-01-20 20:55:12 +01:00
// Trace log info
if ( ( physicsBodiesCount > 0 ) | | ( usedMemory ! = 0 ) )
{
TRACELOG ( " [PHYSAC] WARNING: Physics module closed with unallocated bodies (BODIES: %i, MEMORY: %i bytes) \n " , physicsBodiesCount , usedMemory ) ;
}
else if ( ( physicsManifoldsCount > 0 ) | | ( usedMemory ! = 0 ) )
{
TRACELOG ( " [PHYSAC] WARNING: Pysics module closed with unallocated manifolds (MANIFOLDS: %i, MEMORY: %i bytes) \n " , physicsManifoldsCount , usedMemory ) ;
}
else TRACELOG ( " [PHYSAC] Physics module closed successfully \n " ) ;
2016-11-21 20:30:46 +01:00
}
2021-08-15 12:52:12 +02:00
// Update physics system
// Physics steps are launched at a fixed time step if enabled
void UpdatePhysics ( void )
2018-03-10 19:25:17 +01:00
{
2021-08-15 12:52:12 +02:00
# if !defined(PHYSAC_AVOID_TIMMING_SYSTEM)
static double deltaTimeAccumulator = 0.0 ;
2018-03-10 19:25:17 +01:00
2021-08-15 12:52:12 +02:00
// Calculate current time (ms)
currentTime = GetCurrentTime ( ) ;
2018-03-10 19:25:17 +01:00
2021-08-15 12:52:12 +02:00
// Calculate current delta time (ms)
const double delta = currentTime - startTime ;
// Store the time elapsed since the last frame began
deltaTimeAccumulator + = delta ;
// Fixed time stepping loop
while ( deltaTimeAccumulator > = deltaTime )
{
UpdatePhysicsStep ( ) ;
deltaTimeAccumulator - = deltaTime ;
2018-03-10 19:25:17 +01:00
}
2021-08-15 12:52:12 +02:00
// Record the starting of this frame
startTime = currentTime ;
# else
UpdatePhysicsStep ( ) ;
# endif
2018-03-10 19:25:17 +01:00
}
2021-08-15 12:52:12 +02:00
void SetPhysicsTimeStep ( double delta )
2016-11-21 20:30:46 +01:00
{
2021-08-15 12:52:12 +02:00
deltaTime = delta ;
}
2016-11-21 20:30:46 +01:00
2021-08-15 12:52:12 +02:00
//----------------------------------------------------------------------------------
// Module Internal Functions Definition
//----------------------------------------------------------------------------------
# if !defined(PHYSAC_AVOID_TIMMING_SYSTEM)
// Initializes hi-resolution MONOTONIC timer
static void InitTimerHiRes ( void )
{
# if defined(_WIN32)
QueryPerformanceFrequency ( ( unsigned long long int * ) & frequency ) ;
# endif
2016-11-21 20:30:46 +01:00
2021-08-15 12:52:12 +02:00
# if defined(__EMSCRIPTEN__) || defined(__linux__)
struct timespec now ;
if ( clock_gettime ( CLOCK_MONOTONIC , & now ) = = 0 ) frequency = 1000000000 ;
# endif
2016-11-21 20:30:46 +01:00
2021-08-15 12:52:12 +02:00
# if defined(__APPLE__)
mach_timebase_info_data_t timebase ;
mach_timebase_info ( & timebase ) ;
frequency = ( timebase . denom * 1e9 ) / timebase . numer ;
# endif
2016-11-21 20:30:46 +01:00
2021-08-15 12:52:12 +02:00
baseClockTicks = ( double ) GetClockTicks ( ) ; // Get MONOTONIC clock time offset
startTime = GetCurrentTime ( ) ; // Get current time in milliseconds
2016-11-21 20:30:46 +01:00
}
2021-08-15 12:52:12 +02:00
// Get hi-res MONOTONIC time measure in clock ticks
static unsigned long long int GetClockTicks ( void )
2016-11-21 20:30:46 +01:00
{
2021-08-15 12:52:12 +02:00
unsigned long long int value = 0 ;
2016-11-21 20:30:46 +01:00
2021-08-15 12:52:12 +02:00
# if defined(_WIN32)
QueryPerformanceCounter ( ( unsigned long long int * ) & value ) ;
# endif
2016-11-21 20:30:46 +01:00
2021-08-15 12:52:12 +02:00
# if defined(__linux__)
struct timespec now ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
value = ( unsigned long long int ) now . tv_sec * ( unsigned long long int ) 1000000000 + ( unsigned long long int ) now . tv_nsec ;
# endif
2016-11-21 20:30:46 +01:00
2021-08-15 12:52:12 +02:00
# if defined(__APPLE__)
value = mach_absolute_time ( ) ;
# endif
2016-11-21 20:30:46 +01:00
2021-08-15 12:52:12 +02:00
return value ;
2016-11-21 20:30:46 +01:00
}
2021-08-15 12:52:12 +02:00
// Get current time in milliseconds
static double GetCurrentTime ( void )
{
return ( double ) ( GetClockTicks ( ) - baseClockTicks ) / frequency * 1000 ;
}
# endif // !PHYSAC_AVOID_TIMMING_SYSTEM
2021-01-20 20:55:12 +01:00
// Update physics step (dynamics, collisions and position corrections)
2021-08-15 12:52:12 +02:00
static void UpdatePhysicsStep ( void )
2016-11-21 20:30:46 +01:00
{
// Clear previous generated collisions information
2021-02-20 02:15:40 -08:00
for ( int i = ( int ) physicsManifoldsCount - 1 ; i > = 0 ; i - - )
2016-11-21 20:30:46 +01:00
{
PhysicsManifold manifold = contacts [ i ] ;
if ( manifold ! = NULL ) DestroyPhysicsManifold ( manifold ) ;
}
2017-04-16 19:08:34 +02:00
2017-03-06 09:58:28 +01:00
// Reset physics bodies grounded state
2021-02-20 02:15:40 -08:00
for ( unsigned int i = 0 ; i < physicsBodiesCount ; i + + )
2017-03-06 09:58:28 +01:00
{
PhysicsBody body = bodies [ i ] ;
body - > isGrounded = false ;
}
2021-02-20 02:15:40 -08:00
2016-11-21 20:30:46 +01:00
// Generate new collision information
2021-02-20 02:15:40 -08:00
for ( unsigned int i = 0 ; i < physicsBodiesCount ; i + + )
2016-11-21 20:30:46 +01:00
{
PhysicsBody bodyA = bodies [ i ] ;
if ( bodyA ! = NULL )
{
2021-02-20 02:15:40 -08:00
for ( unsigned int j = i + 1 ; j < physicsBodiesCount ; j + + )
2016-11-21 20:30:46 +01:00
{
PhysicsBody bodyB = bodies [ j ] ;
if ( bodyB ! = NULL )
{
if ( ( bodyA - > inverseMass = = 0 ) & & ( bodyB - > inverseMass = = 0 ) ) continue ;
2018-03-10 19:25:17 +01:00
PhysicsManifold manifold = CreatePhysicsManifold ( bodyA , bodyB ) ;
2016-11-21 20:30:46 +01:00
SolvePhysicsManifold ( manifold ) ;
if ( manifold - > contactsCount > 0 )
{
// Create a new manifold with same information as previously solved manifold and add it to the manifolds pool last slot
2021-01-20 20:55:12 +01:00
PhysicsManifold manifold = CreatePhysicsManifold ( bodyA , bodyB ) ;
manifold - > penetration = manifold - > penetration ;
manifold - > normal = manifold - > normal ;
manifold - > contacts [ 0 ] = manifold - > contacts [ 0 ] ;
manifold - > contacts [ 1 ] = manifold - > contacts [ 1 ] ;
manifold - > contactsCount = manifold - > contactsCount ;
manifold - > restitution = manifold - > restitution ;
manifold - > dynamicFriction = manifold - > dynamicFriction ;
manifold - > staticFriction = manifold - > staticFriction ;
2016-11-21 20:30:46 +01:00
}
}
}
}
}
// Integrate forces to physics bodies
2021-02-20 02:15:40 -08:00
for ( unsigned int i = 0 ; i < physicsBodiesCount ; i + + )
2016-11-21 20:30:46 +01:00
{
PhysicsBody body = bodies [ i ] ;
if ( body ! = NULL ) IntegratePhysicsForces ( body ) ;
}
// Initialize physics manifolds to solve collisions
2021-02-20 02:15:40 -08:00
for ( unsigned int i = 0 ; i < physicsManifoldsCount ; i + + )
2016-11-21 20:30:46 +01:00
{
PhysicsManifold manifold = contacts [ i ] ;
if ( manifold ! = NULL ) InitializePhysicsManifolds ( manifold ) ;
}
// Integrate physics collisions impulses to solve collisions
2021-02-20 02:15:40 -08:00
for ( unsigned int i = 0 ; i < PHYSAC_COLLISION_ITERATIONS ; i + + )
2016-11-21 20:30:46 +01:00
{
2021-02-20 02:15:40 -08:00
for ( unsigned int j = 0 ; j < physicsManifoldsCount ; j + + )
2016-11-21 20:30:46 +01:00
{
PhysicsManifold manifold = contacts [ i ] ;
if ( manifold ! = NULL ) IntegratePhysicsImpulses ( manifold ) ;
}
}
// Integrate velocity to physics bodies
2021-02-20 02:15:40 -08:00
for ( unsigned int i = 0 ; i < physicsBodiesCount ; i + + )
2016-11-21 20:30:46 +01:00
{
PhysicsBody body = bodies [ i ] ;
if ( body ! = NULL ) IntegratePhysicsVelocity ( body ) ;
}
// Correct physics bodies positions based on manifolds collision information
2021-02-20 02:15:40 -08:00
for ( unsigned int i = 0 ; i < physicsManifoldsCount ; i + + )
2016-11-21 20:30:46 +01:00
{
PhysicsManifold manifold = contacts [ i ] ;
if ( manifold ! = NULL ) CorrectPhysicsPositions ( manifold ) ;
}
// Clear physics bodies forces
2021-02-20 02:15:40 -08:00
for ( unsigned int i = 0 ; i < physicsBodiesCount ; i + + )
2016-11-21 20:30:46 +01:00
{
PhysicsBody body = bodies [ i ] ;
if ( body ! = NULL )
{
2018-03-10 19:25:17 +01:00
body - > force = PHYSAC_VECTOR_ZERO ;
body - > torque = 0.0f ;
2016-11-21 20:30:46 +01:00
}
}
}
2021-08-15 12:52:12 +02:00
// Finds a valid index for a new physics body initialization
static int FindAvailableBodyIndex ( )
2018-07-29 13:09:30 +02:00
{
2021-08-15 12:52:12 +02:00
int index = - 1 ;
for ( int i = 0 ; i < PHYSAC_MAX_BODIES ; i + + )
{
int currentId = i ;
2021-01-20 20:55:12 +01:00
2021-08-15 12:52:12 +02:00
// Check if current id already exist in other physics body
for ( unsigned int k = 0 ; k < physicsBodiesCount ; k + + )
{
if ( bodies [ k ] - > id = = currentId )
{
currentId + + ;
break ;
}
}
2018-07-29 13:09:30 +02:00
2021-08-15 12:52:12 +02:00
// If it is not used, use it as new physics body id
if ( currentId = = ( int ) i )
{
index = ( int ) i ;
break ;
}
}
2018-07-29 13:09:30 +02:00
2021-08-15 12:52:12 +02:00
return index ;
}
2018-07-29 13:09:30 +02:00
2021-08-15 12:52:12 +02:00
// Creates a default polygon shape with max vertex distance from polygon pivot
static PhysicsVertexData CreateDefaultPolygon ( float radius , int sides )
{
PhysicsVertexData data = { 0 } ;
data . vertexCount = sides ;
// Calculate polygon vertices positions
for ( unsigned int i = 0 ; i < data . vertexCount ; i + + )
2018-07-29 13:09:30 +02:00
{
2021-08-15 12:52:12 +02:00
data . positions [ i ] . x = ( float ) cosf ( 360.0f / sides * i * PHYSAC_DEG2RAD ) * radius ;
data . positions [ i ] . y = ( float ) sinf ( 360.0f / sides * i * PHYSAC_DEG2RAD ) * radius ;
2018-07-29 13:09:30 +02:00
}
2021-08-15 12:52:12 +02:00
// Calculate polygon faces normals
for ( int i = 0 ; i < ( int ) data . vertexCount ; i + + )
{
int nextIndex = ( ( ( i + 1 ) < sides ) ? ( i + 1 ) : 0 ) ;
Vector2 face = MathVector2Subtract ( data . positions [ nextIndex ] , data . positions [ i ] ) ;
data . normals [ i ] = CLITERAL ( Vector2 ) { face . y , - face . x } ;
MathVector2Normalize ( & data . normals [ i ] ) ;
}
return data ;
2018-07-29 13:09:30 +02:00
}
2021-08-15 12:52:12 +02:00
// Creates a rectangle polygon shape based on a min and max positions
static PhysicsVertexData CreateRectanglePolygon ( Vector2 pos , Vector2 size )
2018-09-23 13:55:39 +02:00
{
2021-08-15 12:52:12 +02:00
PhysicsVertexData data = { 0 } ;
data . vertexCount = 4 ;
// Calculate polygon vertices positions
data . positions [ 0 ] = CLITERAL ( Vector2 ) { pos . x + size . x / 2 , pos . y - size . y / 2 } ;
data . positions [ 1 ] = CLITERAL ( Vector2 ) { pos . x + size . x / 2 , pos . y + size . y / 2 } ;
data . positions [ 2 ] = CLITERAL ( Vector2 ) { pos . x - size . x / 2 , pos . y + size . y / 2 } ;
data . positions [ 3 ] = CLITERAL ( Vector2 ) { pos . x - size . x / 2 , pos . y - size . y / 2 } ;
// Calculate polygon faces normals
for ( unsigned int i = 0 ; i < data . vertexCount ; i + + )
{
int nextIndex = ( ( ( i + 1 ) < data . vertexCount ) ? ( i + 1 ) : 0 ) ;
Vector2 face = MathVector2Subtract ( data . positions [ nextIndex ] , data . positions [ i ] ) ;
data . normals [ i ] = CLITERAL ( Vector2 ) { face . y , - face . x } ;
MathVector2Normalize ( & data . normals [ i ] ) ;
}
return data ;
2018-09-23 13:55:39 +02:00
}
2018-03-10 19:25:17 +01:00
// Finds a valid index for a new manifold initialization
static int FindAvailableManifoldIndex ( )
2016-11-21 20:30:46 +01:00
{
2018-03-10 19:25:17 +01:00
int index = - 1 ;
2016-11-21 20:30:46 +01:00
for ( int i = 0 ; i < PHYSAC_MAX_MANIFOLDS ; i + + )
{
int currentId = i ;
// Check if current id already exist in other physics body
2021-02-20 02:15:40 -08:00
for ( unsigned int k = 0 ; k < physicsManifoldsCount ; k + + )
2016-11-21 20:30:46 +01:00
{
if ( contacts [ k ] - > id = = currentId )
{
currentId + + ;
break ;
}
}
// If it is not used, use it as new physics body id
if ( currentId = = i )
{
2018-03-10 19:25:17 +01:00
index = i ;
2016-11-21 20:30:46 +01:00
break ;
}
}
2018-03-10 19:25:17 +01:00
return index ;
}
// Creates a new physics manifold to solve collision
static PhysicsManifold CreatePhysicsManifold ( PhysicsBody a , PhysicsBody b )
{
2021-01-20 20:55:12 +01:00
PhysicsManifold manifold = ( PhysicsManifold ) PHYSAC_MALLOC ( sizeof ( PhysicsManifoldData ) ) ;
2018-03-10 19:25:17 +01:00
usedMemory + = sizeof ( PhysicsManifoldData ) ;
2021-01-20 20:55:12 +01:00
int id = FindAvailableManifoldIndex ( ) ;
if ( id ! = - 1 )
2017-04-16 19:08:34 +02:00
{
2016-11-21 20:30:46 +01:00
// Initialize new manifold with generic values
2021-01-20 20:55:12 +01:00
manifold - > id = id ;
manifold - > bodyA = a ;
manifold - > bodyB = b ;
manifold - > penetration = 0 ;
manifold - > normal = PHYSAC_VECTOR_ZERO ;
manifold - > contacts [ 0 ] = PHYSAC_VECTOR_ZERO ;
manifold - > contacts [ 1 ] = PHYSAC_VECTOR_ZERO ;
manifold - > contactsCount = 0 ;
manifold - > restitution = 0.0f ;
manifold - > dynamicFriction = 0.0f ;
manifold - > staticFriction = 0.0f ;
2016-11-21 20:30:46 +01:00
// Add new body to bodies pointers array and update bodies count
2021-01-20 20:55:12 +01:00
contacts [ physicsManifoldsCount ] = manifold ;
2016-11-21 20:30:46 +01:00
physicsManifoldsCount + + ;
}
2021-01-20 20:55:12 +01:00
else TRACELOG ( " [PHYSAC] Physic manifold could not be created, PHYSAC_MAX_MANIFOLDS reached \n " ) ;
2016-11-21 20:30:46 +01:00
2021-01-20 20:55:12 +01:00
return manifold ;
2016-11-21 20:30:46 +01:00
}
// Unitializes and destroys a physics manifold
static void DestroyPhysicsManifold ( PhysicsManifold manifold )
{
if ( manifold ! = NULL )
{
int id = manifold - > id ;
int index = - 1 ;
2021-02-20 02:15:40 -08:00
for ( unsigned int i = 0 ; i < physicsManifoldsCount ; i + + )
2016-11-21 20:30:46 +01:00
{
if ( contacts [ i ] - > id = = id )
{
index = i ;
break ;
}
}
2021-01-20 20:55:12 +01:00
if ( index = = - 1 ) return ; // Prevent access to index -1
2016-11-21 20:30:46 +01:00
// Free manifold allocated memory
2018-03-10 19:25:17 +01:00
PHYSAC_FREE ( manifold ) ;
2016-11-21 20:30:46 +01:00
usedMemory - = sizeof ( PhysicsManifoldData ) ;
contacts [ index ] = NULL ;
// Reorder physics manifolds pointers array and its catched index
2021-02-20 02:15:40 -08:00
for ( unsigned int i = index ; i < physicsManifoldsCount ; i + + )
2016-11-21 20:30:46 +01:00
{
if ( ( i + 1 ) < physicsManifoldsCount ) contacts [ i ] = contacts [ i + 1 ] ;
}
// Update physics manifolds count
physicsManifoldsCount - - ;
}
2021-01-20 20:55:12 +01:00
else TRACELOG ( " [PHYSAC] WARNING: DestroyPhysicsManifold: NULL physic manifold \n " ) ;
2016-11-21 20:30:46 +01:00
}
// Solves a created physics manifold between two physics bodies
static void SolvePhysicsManifold ( PhysicsManifold manifold )
{
switch ( manifold - > bodyA - > shape . type )
{
case PHYSICS_CIRCLE :
{
switch ( manifold - > bodyB - > shape . type )
{
case PHYSICS_CIRCLE : SolveCircleToCircle ( manifold ) ; break ;
case PHYSICS_POLYGON : SolveCircleToPolygon ( manifold ) ; break ;
default : break ;
}
} break ;
case PHYSICS_POLYGON :
{
switch ( manifold - > bodyB - > shape . type )
{
case PHYSICS_CIRCLE : SolvePolygonToCircle ( manifold ) ; break ;
case PHYSICS_POLYGON : SolvePolygonToPolygon ( manifold ) ; break ;
default : break ;
}
} break ;
default : break ;
}
2017-04-16 19:08:34 +02:00
2017-03-06 09:58:28 +01:00
// Update physics body grounded state if normal direction is down and grounded state is not set yet in previous manifolds
if ( ! manifold - > bodyB - > isGrounded ) manifold - > bodyB - > isGrounded = ( manifold - > normal . y < 0 ) ;
2016-11-21 20:30:46 +01:00
}
// Solves collision between two circle shape physics bodies
static void SolveCircleToCircle ( PhysicsManifold manifold )
{
PhysicsBody bodyA = manifold - > bodyA ;
PhysicsBody bodyB = manifold - > bodyB ;
2018-03-10 19:25:17 +01:00
if ( ( bodyA = = NULL ) | | ( bodyB = = NULL ) ) return ;
2016-11-21 20:30:46 +01:00
// Calculate translational vector, which is normal
2021-01-20 20:55:12 +01:00
Vector2 normal = MathVector2Subtract ( bodyB - > position , bodyA - > position ) ;
2016-11-21 20:30:46 +01:00
2021-01-20 20:55:12 +01:00
float distSqr = MathVector2SqrLen ( normal ) ;
2016-11-21 20:30:46 +01:00
float radius = bodyA - > shape . radius + bodyB - > shape . radius ;
// Check if circles are not in contact
if ( distSqr > = radius * radius )
{
manifold - > contactsCount = 0 ;
return ;
}
float distance = sqrtf ( distSqr ) ;
manifold - > contactsCount = 1 ;
2018-03-10 19:25:17 +01:00
if ( distance = = 0.0f )
2016-11-21 20:30:46 +01:00
{
manifold - > penetration = bodyA - > shape . radius ;
2021-01-20 20:55:12 +01:00
manifold - > normal = CLITERAL ( Vector2 ) { 1.0f , 0.0f } ;
2016-11-21 20:30:46 +01:00
manifold - > contacts [ 0 ] = bodyA - > position ;
}
else
{
manifold - > penetration = radius - distance ;
2021-01-20 20:55:12 +01:00
manifold - > normal = CLITERAL ( Vector2 ) { normal . x / distance , normal . y / distance } ; // Faster than using MathVector2Normalize() due to sqrt is already performed
manifold - > contacts [ 0 ] = CLITERAL ( Vector2 ) { manifold - > normal . x * bodyA - > shape . radius + bodyA - > position . x , manifold - > normal . y * bodyA - > shape . radius + bodyA - > position . y } ;
2016-11-21 20:30:46 +01:00
}
// Update physics body grounded state if normal direction is down
2017-03-06 09:58:28 +01:00
if ( ! bodyA - > isGrounded ) bodyA - > isGrounded = ( manifold - > normal . y < 0 ) ;
2016-11-21 20:30:46 +01:00
}
// Solves collision between a circle to a polygon shape physics bodies
static void SolveCircleToPolygon ( PhysicsManifold manifold )
{
PhysicsBody bodyA = manifold - > bodyA ;
PhysicsBody bodyB = manifold - > bodyB ;
2018-03-10 19:25:17 +01:00
if ( ( bodyA = = NULL ) | | ( bodyB = = NULL ) ) return ;
2016-11-21 20:30:46 +01:00
manifold - > contactsCount = 0 ;
// Transform circle center to polygon transform space
Vector2 center = bodyA - > position ;
2021-01-20 20:55:12 +01:00
center = MathMatVector2Product ( MathMatTranspose ( bodyB - > shape . transform ) , MathVector2Subtract ( center , bodyB - > position ) ) ;
2016-11-21 20:30:46 +01:00
// Find edge with minimum penetration
// It is the same concept as using support points in SolvePolygonToPolygon
float separation = - PHYSAC_FLT_MAX ;
int faceNormal = 0 ;
2021-01-20 20:55:12 +01:00
PhysicsVertexData vertexData = bodyB - > shape . vertexData ;
2016-11-21 20:30:46 +01:00
2021-02-20 02:15:40 -08:00
for ( unsigned int i = 0 ; i < vertexData . vertexCount ; i + + )
2016-11-21 20:30:46 +01:00
{
2021-01-20 20:55:12 +01:00
float currentSeparation = MathVector2DotProduct ( vertexData . normals [ i ] , MathVector2Subtract ( center , vertexData . positions [ i ] ) ) ;
2016-11-21 20:30:46 +01:00
if ( currentSeparation > bodyA - > shape . radius ) return ;
if ( currentSeparation > separation )
{
separation = currentSeparation ;
faceNormal = i ;
}
}
// Grab face's vertices
2018-03-10 19:25:17 +01:00
Vector2 v1 = vertexData . positions [ faceNormal ] ;
2021-02-20 02:15:40 -08:00
int nextIndex = ( ( ( faceNormal + 1 ) < ( int ) vertexData . vertexCount ) ? ( faceNormal + 1 ) : 0 ) ;
2018-03-10 19:25:17 +01:00
Vector2 v2 = vertexData . positions [ nextIndex ] ;
2016-11-21 20:30:46 +01:00
// Check to see if center is within polygon
if ( separation < PHYSAC_EPSILON )
{
manifold - > contactsCount = 1 ;
2021-01-20 20:55:12 +01:00
Vector2 normal = MathMatVector2Product ( bodyB - > shape . transform , vertexData . normals [ faceNormal ] ) ;
manifold - > normal = CLITERAL ( Vector2 ) { - normal . x , - normal . y } ;
manifold - > contacts [ 0 ] = CLITERAL ( Vector2 ) { manifold - > normal . x * bodyA - > shape . radius + bodyA - > position . x , manifold - > normal . y * bodyA - > shape . radius + bodyA - > position . y } ;
2016-11-21 20:30:46 +01:00
manifold - > penetration = bodyA - > shape . radius ;
return ;
}
// Determine which voronoi region of the edge center of circle lies within
2021-01-20 20:55:12 +01:00
float dot1 = MathVector2DotProduct ( MathVector2Subtract ( center , v1 ) , MathVector2Subtract ( v2 , v1 ) ) ;
float dot2 = MathVector2DotProduct ( MathVector2Subtract ( center , v2 ) , MathVector2Subtract ( v1 , v2 ) ) ;
2016-11-21 20:30:46 +01:00
manifold - > penetration = bodyA - > shape . radius - separation ;
2018-03-10 19:25:17 +01:00
if ( dot1 < = 0.0f ) // Closest to v1
2017-04-16 19:08:34 +02:00
{
2021-01-20 20:55:12 +01:00
if ( MathVector2SqrDistance ( center , v1 ) > bodyA - > shape . radius * bodyA - > shape . radius ) return ;
2016-11-21 20:30:46 +01:00
manifold - > contactsCount = 1 ;
2021-01-20 20:55:12 +01:00
Vector2 normal = MathVector2Subtract ( v1 , center ) ;
normal = MathMatVector2Product ( bodyB - > shape . transform , normal ) ;
MathVector2Normalize ( & normal ) ;
2016-11-21 20:30:46 +01:00
manifold - > normal = normal ;
2021-01-20 20:55:12 +01:00
v1 = MathMatVector2Product ( bodyB - > shape . transform , v1 ) ;
v1 = MathVector2Add ( v1 , bodyB - > position ) ;
2016-11-21 20:30:46 +01:00
manifold - > contacts [ 0 ] = v1 ;
}
2018-03-10 19:25:17 +01:00
else if ( dot2 < = 0.0f ) // Closest to v2
2016-11-21 20:30:46 +01:00
{
2021-01-20 20:55:12 +01:00
if ( MathVector2SqrDistance ( center , v2 ) > bodyA - > shape . radius * bodyA - > shape . radius ) return ;
2016-11-21 20:30:46 +01:00
manifold - > contactsCount = 1 ;
2021-01-20 20:55:12 +01:00
Vector2 normal = MathVector2Subtract ( v2 , center ) ;
v2 = MathMatVector2Product ( bodyB - > shape . transform , v2 ) ;
v2 = MathVector2Add ( v2 , bodyB - > position ) ;
2016-11-21 20:30:46 +01:00
manifold - > contacts [ 0 ] = v2 ;
2021-01-20 20:55:12 +01:00
normal = MathMatVector2Product ( bodyB - > shape . transform , normal ) ;
MathVector2Normalize ( & normal ) ;
2016-11-21 20:30:46 +01:00
manifold - > normal = normal ;
}
else // Closest to face
{
Vector2 normal = vertexData . normals [ faceNormal ] ;
2021-01-20 20:55:12 +01:00
if ( MathVector2DotProduct ( MathVector2Subtract ( center , v1 ) , normal ) > bodyA - > shape . radius ) return ;
2016-11-21 20:30:46 +01:00
2021-01-20 20:55:12 +01:00
normal = MathMatVector2Product ( bodyB - > shape . transform , normal ) ;
manifold - > normal = CLITERAL ( Vector2 ) { - normal . x , - normal . y } ;
manifold - > contacts [ 0 ] = CLITERAL ( Vector2 ) { manifold - > normal . x * bodyA - > shape . radius + bodyA - > position . x , manifold - > normal . y * bodyA - > shape . radius + bodyA - > position . y } ;
2016-11-21 20:30:46 +01:00
manifold - > contactsCount = 1 ;
}
}
// Solves collision between a polygon to a circle shape physics bodies
static void SolvePolygonToCircle ( PhysicsManifold manifold )
{
PhysicsBody bodyA = manifold - > bodyA ;
PhysicsBody bodyB = manifold - > bodyB ;
2018-03-10 19:25:17 +01:00
if ( ( bodyA = = NULL ) | | ( bodyB = = NULL ) ) return ;
2016-11-21 20:30:46 +01:00
manifold - > bodyA = bodyB ;
manifold - > bodyB = bodyA ;
SolveCircleToPolygon ( manifold ) ;
2018-03-10 19:25:17 +01:00
manifold - > normal . x * = - 1.0f ;
manifold - > normal . y * = - 1.0f ;
2016-11-21 20:30:46 +01:00
}
// Solves collision between two polygons shape physics bodies
static void SolvePolygonToPolygon ( PhysicsManifold manifold )
{
2018-03-10 19:25:17 +01:00
if ( ( manifold - > bodyA = = NULL ) | | ( manifold - > bodyB = = NULL ) ) return ;
2016-11-21 20:30:46 +01:00
PhysicsShape bodyA = manifold - > bodyA - > shape ;
PhysicsShape bodyB = manifold - > bodyB - > shape ;
manifold - > contactsCount = 0 ;
// Check for separating axis with A shape's face planes
int faceA = 0 ;
float penetrationA = FindAxisLeastPenetration ( & faceA , bodyA , bodyB ) ;
2018-03-10 19:25:17 +01:00
if ( penetrationA > = 0.0f ) return ;
2016-11-21 20:30:46 +01:00
// Check for separating axis with B shape's face planes
int faceB = 0 ;
float penetrationB = FindAxisLeastPenetration ( & faceB , bodyB , bodyA ) ;
2018-03-10 19:25:17 +01:00
if ( penetrationB > = 0.0f ) return ;
2016-11-21 20:30:46 +01:00
int referenceIndex = 0 ;
bool flip = false ; // Always point from A shape to B shape
PhysicsShape refPoly ; // Reference
PhysicsShape incPoly ; // Incident
// Determine which shape contains reference face
2021-01-20 20:55:12 +01:00
// Checking bias range for penetration
if ( penetrationA > = ( penetrationB * 0.95f + penetrationA * 0.01f ) )
2016-11-21 20:30:46 +01:00
{
refPoly = bodyA ;
incPoly = bodyB ;
referenceIndex = faceA ;
}
else
{
refPoly = bodyB ;
incPoly = bodyA ;
referenceIndex = faceB ;
flip = true ;
}
// World space incident face
Vector2 incidentFace [ 2 ] ;
FindIncidentFace ( & incidentFace [ 0 ] , & incidentFace [ 1 ] , refPoly , incPoly , referenceIndex ) ;
// Setup reference face vertices
2021-01-20 20:55:12 +01:00
PhysicsVertexData refData = refPoly . vertexData ;
2018-03-10 19:25:17 +01:00
Vector2 v1 = refData . positions [ referenceIndex ] ;
2021-02-20 02:15:40 -08:00
referenceIndex = ( ( ( referenceIndex + 1 ) < ( int ) refData . vertexCount ) ? ( referenceIndex + 1 ) : 0 ) ;
2018-03-10 19:25:17 +01:00
Vector2 v2 = refData . positions [ referenceIndex ] ;
2016-11-21 20:30:46 +01:00
// Transform vertices to world space
2021-01-20 20:55:12 +01:00
v1 = MathMatVector2Product ( refPoly . transform , v1 ) ;
v1 = MathVector2Add ( v1 , refPoly . body - > position ) ;
v2 = MathMatVector2Product ( refPoly . transform , v2 ) ;
v2 = MathVector2Add ( v2 , refPoly . body - > position ) ;
2016-11-21 20:30:46 +01:00
// Calculate reference face side normal in world space
2021-01-20 20:55:12 +01:00
Vector2 sidePlaneNormal = MathVector2Subtract ( v2 , v1 ) ;
MathVector2Normalize ( & sidePlaneNormal ) ;
2016-11-21 20:30:46 +01:00
// Orthogonalize
Vector2 refFaceNormal = { sidePlaneNormal . y , - sidePlaneNormal . x } ;
2021-01-20 20:55:12 +01:00
float refC = MathVector2DotProduct ( refFaceNormal , v1 ) ;
float negSide = MathVector2DotProduct ( sidePlaneNormal , v1 ) * - 1 ;
float posSide = MathVector2DotProduct ( sidePlaneNormal , v2 ) ;
2016-11-21 20:30:46 +01:00
2021-01-20 20:55:12 +01:00
// MathVector2Clip incident face to reference face side planes (due to floating point error, possible to not have required points
if ( MathVector2Clip ( CLITERAL ( Vector2 ) { - sidePlaneNormal . x , - sidePlaneNormal . y } , & incidentFace [ 0 ] , & incidentFace [ 1 ] , negSide ) < 2 ) return ;
if ( MathVector2Clip ( sidePlaneNormal , & incidentFace [ 0 ] , & incidentFace [ 1 ] , posSide ) < 2 ) return ;
2016-11-21 20:30:46 +01:00
// Flip normal if required
2021-01-20 20:55:12 +01:00
manifold - > normal = ( flip ? CLITERAL ( Vector2 ) { - refFaceNormal . x , - refFaceNormal . y } : refFaceNormal ) ;
2016-11-21 20:30:46 +01:00
// Keep points behind reference face
2021-01-20 20:55:12 +01:00
int currentPoint = 0 ; // MathVector2Clipped points behind reference face
float separation = MathVector2DotProduct ( refFaceNormal , incidentFace [ 0 ] ) - refC ;
2018-03-10 19:25:17 +01:00
if ( separation < = 0.0f )
2016-11-21 20:30:46 +01:00
{
manifold - > contacts [ currentPoint ] = incidentFace [ 0 ] ;
manifold - > penetration = - separation ;
currentPoint + + ;
}
2018-03-10 19:25:17 +01:00
else manifold - > penetration = 0.0f ;
2016-11-21 20:30:46 +01:00
2021-01-20 20:55:12 +01:00
separation = MathVector2DotProduct ( refFaceNormal , incidentFace [ 1 ] ) - refC ;
2016-11-21 20:30:46 +01:00
2018-03-10 19:25:17 +01:00
if ( separation < = 0.0f )
2016-11-21 20:30:46 +01:00
{
manifold - > contacts [ currentPoint ] = incidentFace [ 1 ] ;
manifold - > penetration + = - separation ;
currentPoint + + ;
// Calculate total penetration average
manifold - > penetration / = currentPoint ;
}
manifold - > contactsCount = currentPoint ;
}
// Integrates physics forces into velocity
static void IntegratePhysicsForces ( PhysicsBody body )
{
2018-03-10 19:25:17 +01:00
if ( ( body = = NULL ) | | ( body - > inverseMass = = 0.0f ) | | ! body - > enabled ) return ;
2016-11-21 20:30:46 +01:00
2021-02-20 02:15:40 -08:00
body - > velocity . x + = ( float ) ( ( body - > force . x * body - > inverseMass ) * ( deltaTime / 2.0 ) ) ;
body - > velocity . y + = ( float ) ( ( body - > force . y * body - > inverseMass ) * ( deltaTime / 2.0 ) ) ;
2016-11-21 20:30:46 +01:00
if ( body - > useGravity )
{
2021-02-20 02:15:40 -08:00
body - > velocity . x + = ( float ) ( gravityForce . x * ( deltaTime / 1000 / 2.0 ) ) ;
body - > velocity . y + = ( float ) ( gravityForce . y * ( deltaTime / 1000 / 2.0 ) ) ;
2016-11-21 20:30:46 +01:00
}
2021-02-20 02:15:40 -08:00
if ( ! body - > freezeOrient ) body - > angularVelocity + = ( float ) ( body - > torque * body - > inverseInertia * ( deltaTime / 2.0 ) ) ;
2016-11-21 20:30:46 +01:00
}
// Initializes physics manifolds to solve collisions
static void InitializePhysicsManifolds ( PhysicsManifold manifold )
{
PhysicsBody bodyA = manifold - > bodyA ;
PhysicsBody bodyB = manifold - > bodyB ;
2018-03-10 19:25:17 +01:00
if ( ( bodyA = = NULL ) | | ( bodyB = = NULL ) ) return ;
2016-11-21 20:30:46 +01:00
// Calculate average restitution, static and dynamic friction
manifold - > restitution = sqrtf ( bodyA - > restitution * bodyB - > restitution ) ;
manifold - > staticFriction = sqrtf ( bodyA - > staticFriction * bodyB - > staticFriction ) ;
manifold - > dynamicFriction = sqrtf ( bodyA - > dynamicFriction * bodyB - > dynamicFriction ) ;
2021-02-20 02:15:40 -08:00
for ( unsigned int i = 0 ; i < manifold - > contactsCount ; i + + )
2016-11-21 20:30:46 +01:00
{
// Caculate radius from center of mass to contact
2021-01-20 20:55:12 +01:00
Vector2 radiusA = MathVector2Subtract ( manifold - > contacts [ i ] , bodyA - > position ) ;
Vector2 radiusB = MathVector2Subtract ( manifold - > contacts [ i ] , bodyB - > position ) ;
2016-11-21 20:30:46 +01:00
2021-01-20 20:55:12 +01:00
Vector2 crossA = MathVector2Product ( radiusA , bodyA - > angularVelocity ) ;
Vector2 crossB = MathVector2Product ( radiusB , bodyB - > angularVelocity ) ;
2016-11-21 20:30:46 +01:00
2018-03-10 19:25:17 +01:00
Vector2 radiusV = { 0.0f , 0.0f } ;
2016-11-21 20:30:46 +01:00
radiusV . x = bodyB - > velocity . x + crossB . x - bodyA - > velocity . x - crossA . x ;
radiusV . y = bodyB - > velocity . y + crossB . y - bodyA - > velocity . y - crossA . y ;
// Determine if we should perform a resting collision or not;
// The idea is if the only thing moving this object is gravity, then the collision should be performed without any restitution
2021-02-20 02:15:40 -08:00
if ( MathVector2SqrLen ( radiusV ) < ( MathVector2SqrLen ( CLITERAL ( Vector2 ) { ( float ) ( gravityForce . x * deltaTime / 1000 ) , ( float ) ( gravityForce . y * deltaTime / 1000 ) } ) + PHYSAC_EPSILON ) ) manifold - > restitution = 0 ;
2016-11-21 20:30:46 +01:00
}
}
// Integrates physics collisions impulses to solve collisions
static void IntegratePhysicsImpulses ( PhysicsManifold manifold )
{
PhysicsBody bodyA = manifold - > bodyA ;
PhysicsBody bodyB = manifold - > bodyB ;
2018-03-10 19:25:17 +01:00
if ( ( bodyA = = NULL ) | | ( bodyB = = NULL ) ) return ;
2016-11-21 20:30:46 +01:00
// Early out and positional correct if both objects have infinite mass
if ( fabs ( bodyA - > inverseMass + bodyB - > inverseMass ) < = PHYSAC_EPSILON )
{
2018-03-10 19:25:17 +01:00
bodyA - > velocity = PHYSAC_VECTOR_ZERO ;
bodyB - > velocity = PHYSAC_VECTOR_ZERO ;
2016-11-21 20:30:46 +01:00
return ;
}
2021-02-20 02:15:40 -08:00
for ( unsigned int i = 0 ; i < manifold - > contactsCount ; i + + )
2016-11-21 20:30:46 +01:00
{
// Calculate radius from center of mass to contact
2021-01-20 20:55:12 +01:00
Vector2 radiusA = MathVector2Subtract ( manifold - > contacts [ i ] , bodyA - > position ) ;
Vector2 radiusB = MathVector2Subtract ( manifold - > contacts [ i ] , bodyB - > position ) ;
2016-11-21 20:30:46 +01:00
// Calculate relative velocity
2018-03-10 19:25:17 +01:00
Vector2 radiusV = { 0.0f , 0.0f } ;
2021-01-20 20:55:12 +01:00
radiusV . x = bodyB - > velocity . x + MathVector2Product ( radiusB , bodyB - > angularVelocity ) . x - bodyA - > velocity . x - MathVector2Product ( radiusA , bodyA - > angularVelocity ) . x ;
radiusV . y = bodyB - > velocity . y + MathVector2Product ( radiusB , bodyB - > angularVelocity ) . y - bodyA - > velocity . y - MathVector2Product ( radiusA , bodyA - > angularVelocity ) . y ;
2016-11-21 20:30:46 +01:00
// Relative velocity along the normal
2021-01-20 20:55:12 +01:00
float contactVelocity = MathVector2DotProduct ( radiusV , manifold - > normal ) ;
2016-11-21 20:30:46 +01:00
// Do not resolve if velocities are separating
2018-03-10 19:25:17 +01:00
if ( contactVelocity > 0.0f ) return ;
2016-11-21 20:30:46 +01:00
2021-01-20 20:55:12 +01:00
float raCrossN = MathVector2CrossProduct ( radiusA , manifold - > normal ) ;
float rbCrossN = MathVector2CrossProduct ( radiusB , manifold - > normal ) ;
2016-11-21 20:30:46 +01:00
float inverseMassSum = bodyA - > inverseMass + bodyB - > inverseMass + ( raCrossN * raCrossN ) * bodyA - > inverseInertia + ( rbCrossN * rbCrossN ) * bodyB - > inverseInertia ;
// Calculate impulse scalar value
float impulse = - ( 1.0f + manifold - > restitution ) * contactVelocity ;
2017-04-16 19:08:34 +02:00
impulse / = inverseMassSum ;
2016-11-21 20:30:46 +01:00
impulse / = ( float ) manifold - > contactsCount ;
// Apply impulse to each physics body
Vector2 impulseV = { manifold - > normal . x * impulse , manifold - > normal . y * impulse } ;
if ( bodyA - > enabled )
{
bodyA - > velocity . x + = bodyA - > inverseMass * ( - impulseV . x ) ;
bodyA - > velocity . y + = bodyA - > inverseMass * ( - impulseV . y ) ;
2021-01-20 20:55:12 +01:00
if ( ! bodyA - > freezeOrient ) bodyA - > angularVelocity + = bodyA - > inverseInertia * MathVector2CrossProduct ( radiusA , CLITERAL ( Vector2 ) { - impulseV . x , - impulseV . y } ) ;
2016-11-21 20:30:46 +01:00
}
if ( bodyB - > enabled )
{
bodyB - > velocity . x + = bodyB - > inverseMass * ( impulseV . x ) ;
bodyB - > velocity . y + = bodyB - > inverseMass * ( impulseV . y ) ;
2021-01-20 20:55:12 +01:00
if ( ! bodyB - > freezeOrient ) bodyB - > angularVelocity + = bodyB - > inverseInertia * MathVector2CrossProduct ( radiusB , impulseV ) ;
2016-11-21 20:30:46 +01:00
}
// Apply friction impulse to each physics body
2021-01-20 20:55:12 +01:00
radiusV . x = bodyB - > velocity . x + MathVector2Product ( radiusB , bodyB - > angularVelocity ) . x - bodyA - > velocity . x - MathVector2Product ( radiusA , bodyA - > angularVelocity ) . x ;
radiusV . y = bodyB - > velocity . y + MathVector2Product ( radiusB , bodyB - > angularVelocity ) . y - bodyA - > velocity . y - MathVector2Product ( radiusA , bodyA - > angularVelocity ) . y ;
2016-11-21 20:30:46 +01:00
2021-01-20 20:55:12 +01:00
Vector2 tangent = { radiusV . x - ( manifold - > normal . x * MathVector2DotProduct ( radiusV , manifold - > normal ) ) , radiusV . y - ( manifold - > normal . y * MathVector2DotProduct ( radiusV , manifold - > normal ) ) } ;
MathVector2Normalize ( & tangent ) ;
2016-11-21 20:30:46 +01:00
// Calculate impulse tangent magnitude
2021-01-20 20:55:12 +01:00
float impulseTangent = - MathVector2DotProduct ( radiusV , tangent ) ;
2016-11-21 20:30:46 +01:00
impulseTangent / = inverseMassSum ;
impulseTangent / = ( float ) manifold - > contactsCount ;
2021-02-20 02:15:40 -08:00
float absImpulseTangent = ( float ) fabs ( impulseTangent ) ;
2016-11-21 20:30:46 +01:00
// Don't apply tiny friction impulses
if ( absImpulseTangent < = PHYSAC_EPSILON ) return ;
// Apply coulumb's law
2018-03-10 19:25:17 +01:00
Vector2 tangentImpulse = { 0.0f , 0.0f } ;
2021-01-20 20:55:12 +01:00
if ( absImpulseTangent < impulse * manifold - > staticFriction ) tangentImpulse = CLITERAL ( Vector2 ) { tangent . x * impulseTangent , tangent . y * impulseTangent } ;
else tangentImpulse = CLITERAL ( Vector2 ) { tangent . x * - impulse * manifold - > dynamicFriction , tangent . y * - impulse * manifold - > dynamicFriction } ;
2016-11-21 20:30:46 +01:00
// Apply friction impulse
if ( bodyA - > enabled )
{
bodyA - > velocity . x + = bodyA - > inverseMass * ( - tangentImpulse . x ) ;
bodyA - > velocity . y + = bodyA - > inverseMass * ( - tangentImpulse . y ) ;
2021-01-20 20:55:12 +01:00
if ( ! bodyA - > freezeOrient ) bodyA - > angularVelocity + = bodyA - > inverseInertia * MathVector2CrossProduct ( radiusA , CLITERAL ( Vector2 ) { - tangentImpulse . x , - tangentImpulse . y } ) ;
2016-11-21 20:30:46 +01:00
}
if ( bodyB - > enabled )
{
bodyB - > velocity . x + = bodyB - > inverseMass * ( tangentImpulse . x ) ;
bodyB - > velocity . y + = bodyB - > inverseMass * ( tangentImpulse . y ) ;
2021-01-20 20:55:12 +01:00
if ( ! bodyB - > freezeOrient ) bodyB - > angularVelocity + = bodyB - > inverseInertia * MathVector2CrossProduct ( radiusB , tangentImpulse ) ;
2016-11-21 20:30:46 +01:00
}
}
}
// Integrates physics velocity into position and forces
static void IntegratePhysicsVelocity ( PhysicsBody body )
{
2018-03-10 19:25:17 +01:00
if ( ( body = = NULL ) | | ! body - > enabled ) return ;
2016-11-21 20:30:46 +01:00
2021-02-20 02:15:40 -08:00
body - > position . x + = ( float ) ( body - > velocity . x * deltaTime ) ;
body - > position . y + = ( float ) ( body - > velocity . y * deltaTime ) ;
2016-11-21 20:30:46 +01:00
2021-02-20 02:15:40 -08:00
if ( ! body - > freezeOrient ) body - > orient + = ( float ) ( body - > angularVelocity * deltaTime ) ;
2021-01-20 20:55:12 +01:00
body - > shape . transform = MathMatFromRadians ( body - > orient ) ;
2016-11-21 20:30:46 +01:00
IntegratePhysicsForces ( body ) ;
}
// Corrects physics bodies positions based on manifolds collision information
static void CorrectPhysicsPositions ( PhysicsManifold manifold )
{
PhysicsBody bodyA = manifold - > bodyA ;
PhysicsBody bodyB = manifold - > bodyB ;
2018-03-10 19:25:17 +01:00
if ( ( bodyA = = NULL ) | | ( bodyB = = NULL ) ) return ;
Vector2 correction = { 0.0f , 0.0f } ;
2021-01-20 20:55:12 +01:00
correction . x = ( PHYSAC_MAX ( manifold - > penetration - PHYSAC_PENETRATION_ALLOWANCE , 0.0f ) / ( bodyA - > inverseMass + bodyB - > inverseMass ) ) * manifold - > normal . x * PHYSAC_PENETRATION_CORRECTION ;
correction . y = ( PHYSAC_MAX ( manifold - > penetration - PHYSAC_PENETRATION_ALLOWANCE , 0.0f ) / ( bodyA - > inverseMass + bodyB - > inverseMass ) ) * manifold - > normal . y * PHYSAC_PENETRATION_CORRECTION ;
2016-11-21 20:30:46 +01:00
if ( bodyA - > enabled )
{
bodyA - > position . x - = correction . x * bodyA - > inverseMass ;
bodyA - > position . y - = correction . y * bodyA - > inverseMass ;
}
if ( bodyB - > enabled )
{
bodyB - > position . x + = correction . x * bodyB - > inverseMass ;
bodyB - > position . y + = correction . y * bodyB - > inverseMass ;
}
}
// Returns the extreme point along a direction within a polygon
static Vector2 GetSupport ( PhysicsShape shape , Vector2 dir )
{
float bestProjection = - PHYSAC_FLT_MAX ;
2018-03-10 19:25:17 +01:00
Vector2 bestVertex = { 0.0f , 0.0f } ;
2021-01-20 20:55:12 +01:00
PhysicsVertexData data = shape . vertexData ;
2016-11-21 20:30:46 +01:00
2021-02-20 02:15:40 -08:00
for ( unsigned int i = 0 ; i < data . vertexCount ; i + + )
2016-11-21 20:30:46 +01:00
{
2018-03-10 19:25:17 +01:00
Vector2 vertex = data . positions [ i ] ;
2021-01-20 20:55:12 +01:00
float projection = MathVector2DotProduct ( vertex , dir ) ;
2016-11-21 20:30:46 +01:00
if ( projection > bestProjection )
{
bestVertex = vertex ;
bestProjection = projection ;
}
}
return bestVertex ;
}
// Finds polygon shapes axis least penetration
static float FindAxisLeastPenetration ( int * faceIndex , PhysicsShape shapeA , PhysicsShape shapeB )
{
float bestDistance = - PHYSAC_FLT_MAX ;
int bestIndex = 0 ;
2021-01-20 20:55:12 +01:00
PhysicsVertexData dataA = shapeA . vertexData ;
//PhysicsVertexData dataB = shapeB.vertexData;
2016-11-21 20:30:46 +01:00
2021-02-20 02:15:40 -08:00
for ( unsigned int i = 0 ; i < dataA . vertexCount ; i + + )
2016-11-21 20:30:46 +01:00
{
// Retrieve a face normal from A shape
Vector2 normal = dataA . normals [ i ] ;
2021-01-20 20:55:12 +01:00
Vector2 transNormal = MathMatVector2Product ( shapeA . transform , normal ) ;
2016-11-21 20:30:46 +01:00
// Transform face normal into B shape's model space
2021-01-20 20:55:12 +01:00
Matrix2x2 buT = MathMatTranspose ( shapeB . transform ) ;
normal = MathMatVector2Product ( buT , transNormal ) ;
2016-11-21 20:30:46 +01:00
// Retrieve support point from B shape along -n
2021-01-20 20:55:12 +01:00
Vector2 support = GetSupport ( shapeB , CLITERAL ( Vector2 ) { - normal . x , - normal . y } ) ;
2016-11-21 20:30:46 +01:00
// Retrieve vertex on face from A shape, transform into B shape's model space
2018-03-10 19:25:17 +01:00
Vector2 vertex = dataA . positions [ i ] ;
2021-01-20 20:55:12 +01:00
vertex = MathMatVector2Product ( shapeA . transform , vertex ) ;
vertex = MathVector2Add ( vertex , shapeA . body - > position ) ;
vertex = MathVector2Subtract ( vertex , shapeB . body - > position ) ;
vertex = MathMatVector2Product ( buT , vertex ) ;
2016-11-21 20:30:46 +01:00
// Compute penetration distance in B shape's model space
2021-01-20 20:55:12 +01:00
float distance = MathVector2DotProduct ( normal , MathVector2Subtract ( support , vertex ) ) ;
2016-11-21 20:30:46 +01:00
// Store greatest distance
if ( distance > bestDistance )
{
bestDistance = distance ;
bestIndex = i ;
}
}
* faceIndex = bestIndex ;
return bestDistance ;
}
// Finds two polygon shapes incident face
static void FindIncidentFace ( Vector2 * v0 , Vector2 * v1 , PhysicsShape ref , PhysicsShape inc , int index )
{
2021-01-20 20:55:12 +01:00
PhysicsVertexData refData = ref . vertexData ;
PhysicsVertexData incData = inc . vertexData ;
2016-11-21 20:30:46 +01:00
Vector2 referenceNormal = refData . normals [ index ] ;
// Calculate normal in incident's frame of reference
2021-01-20 20:55:12 +01:00
referenceNormal = MathMatVector2Product ( ref . transform , referenceNormal ) ; // To world space
referenceNormal = MathMatVector2Product ( MathMatTranspose ( inc . transform ) , referenceNormal ) ; // To incident's model space
2016-11-21 20:30:46 +01:00
// Find most anti-normal face on polygon
int incidentFace = 0 ;
float minDot = PHYSAC_FLT_MAX ;
2021-02-20 02:15:40 -08:00
for ( unsigned int i = 0 ; i < incData . vertexCount ; i + + )
2016-11-21 20:30:46 +01:00
{
2021-01-20 20:55:12 +01:00
float dot = MathVector2DotProduct ( referenceNormal , incData . normals [ i ] ) ;
2016-11-21 20:30:46 +01:00
if ( dot < minDot )
{
minDot = dot ;
incidentFace = i ;
}
}
// Assign face vertices for incident face
2021-01-20 20:55:12 +01:00
* v0 = MathMatVector2Product ( inc . transform , incData . positions [ incidentFace ] ) ;
* v0 = MathVector2Add ( * v0 , inc . body - > position ) ;
2021-02-20 02:15:40 -08:00
incidentFace = ( ( ( incidentFace + 1 ) < ( int ) incData . vertexCount ) ? ( incidentFace + 1 ) : 0 ) ;
2021-01-20 20:55:12 +01:00
* v1 = MathMatVector2Product ( inc . transform , incData . positions [ incidentFace ] ) ;
* v1 = MathVector2Add ( * v1 , inc . body - > position ) ;
2016-11-21 20:30:46 +01:00
}
2021-01-20 20:55:12 +01:00
// Returns clipping value based on a normal and two faces
static int MathVector2Clip ( Vector2 normal , Vector2 * faceA , Vector2 * faceB , float clip )
2016-11-21 20:30:46 +01:00
{
int sp = 0 ;
Vector2 out [ 2 ] = { * faceA , * faceB } ;
// Retrieve distances from each endpoint to the line
2021-01-20 20:55:12 +01:00
float distanceA = MathVector2DotProduct ( normal , * faceA ) - clip ;
float distanceB = MathVector2DotProduct ( normal , * faceB ) - clip ;
2016-11-21 20:30:46 +01:00
// If negative (behind plane)
2018-03-10 19:25:17 +01:00
if ( distanceA < = 0.0f ) out [ sp + + ] = * faceA ;
if ( distanceB < = 0.0f ) out [ sp + + ] = * faceB ;
2016-11-21 20:30:46 +01:00
// If the points are on different sides of the plane
2018-03-10 19:25:17 +01:00
if ( ( distanceA * distanceB ) < 0.0f )
2016-11-21 20:30:46 +01:00
{
// Push intersection point
float alpha = distanceA / ( distanceA - distanceB ) ;
out [ sp ] = * faceA ;
2021-01-20 20:55:12 +01:00
Vector2 delta = MathVector2Subtract ( * faceB , * faceA ) ;
2016-11-21 20:30:46 +01:00
delta . x * = alpha ;
delta . y * = alpha ;
2021-01-20 20:55:12 +01:00
out [ sp ] = MathVector2Add ( out [ sp ] , delta ) ;
2016-11-21 20:30:46 +01:00
sp + + ;
}
// Assign the new converted values
* faceA = out [ 0 ] ;
* faceB = out [ 1 ] ;
return sp ;
}
// Returns the barycenter of a triangle given by 3 points
2021-01-20 20:55:12 +01:00
static Vector2 MathTriangleBarycenter ( Vector2 v1 , Vector2 v2 , Vector2 v3 )
2016-11-21 20:30:46 +01:00
{
2018-03-10 19:25:17 +01:00
Vector2 result = { 0.0f , 0.0f } ;
2016-11-21 20:30:46 +01:00
result . x = ( v1 . x + v2 . x + v3 . x ) / 3 ;
result . y = ( v1 . y + v2 . y + v3 . y ) / 3 ;
return result ;
}
// Returns the cross product of a vector and a value
2021-01-20 20:55:12 +01:00
static inline Vector2 MathVector2Product ( Vector2 vector , float value )
2016-11-21 20:30:46 +01:00
{
2021-01-20 20:55:12 +01:00
Vector2 result = { - value * vector . y , value * vector . x } ;
return result ;
2016-11-21 20:30:46 +01:00
}
// Returns the cross product of two vectors
2021-01-20 20:55:12 +01:00
static inline float MathVector2CrossProduct ( Vector2 v1 , Vector2 v2 )
2016-11-21 20:30:46 +01:00
{
return ( v1 . x * v2 . y - v1 . y * v2 . x ) ;
}
// Returns the len square root of a vector
2021-01-20 20:55:12 +01:00
static inline float MathVector2SqrLen ( Vector2 vector )
2016-11-21 20:30:46 +01:00
{
return ( vector . x * vector . x + vector . y * vector . y ) ;
}
// Returns the dot product of two vectors
2021-01-20 20:55:12 +01:00
static inline float MathVector2DotProduct ( Vector2 v1 , Vector2 v2 )
2016-11-21 20:30:46 +01:00
{
return ( v1 . x * v2 . x + v1 . y * v2 . y ) ;
}
// Returns the square root of distance between two vectors
2021-01-20 20:55:12 +01:00
static inline float MathVector2SqrDistance ( Vector2 v1 , Vector2 v2 )
2016-11-21 20:30:46 +01:00
{
2021-01-20 20:55:12 +01:00
Vector2 dir = MathVector2Subtract ( v1 , v2 ) ;
return MathVector2DotProduct ( dir , dir ) ;
2016-11-21 20:30:46 +01:00
}
// Returns the normalized values of a vector
2021-01-20 20:55:12 +01:00
static void MathVector2Normalize ( Vector2 * vector )
2016-11-21 20:30:46 +01:00
{
float length , ilength ;
Vector2 aux = * vector ;
length = sqrtf ( aux . x * aux . x + aux . y * aux . y ) ;
if ( length = = 0 ) length = 1.0f ;
ilength = 1.0f / length ;
vector - > x * = ilength ;
vector - > y * = ilength ;
}
// Returns the sum of two given vectors
2021-01-20 20:55:12 +01:00
static inline Vector2 MathVector2Add ( Vector2 v1 , Vector2 v2 )
2016-11-21 20:30:46 +01:00
{
2021-01-20 20:55:12 +01:00
Vector2 result = { v1 . x + v2 . x , v1 . y + v2 . y } ;
return result ;
2016-11-21 20:30:46 +01:00
}
// Returns the subtract of two given vectors
2021-01-20 20:55:12 +01:00
static inline Vector2 MathVector2Subtract ( Vector2 v1 , Vector2 v2 )
2016-11-21 20:30:46 +01:00
{
2021-01-20 20:55:12 +01:00
Vector2 result = { v1 . x - v2 . x , v1 . y - v2 . y } ;
return result ;
2017-12-24 15:59:03 +01:00
}
2016-11-21 20:30:46 +01:00
// Creates a matrix 2x2 from a given radians value
2021-01-20 20:55:12 +01:00
static Matrix2x2 MathMatFromRadians ( float radians )
2016-11-21 20:30:46 +01:00
{
float cos = cosf ( radians ) ;
float sin = sinf ( radians ) ;
2021-01-20 20:55:12 +01:00
Matrix2x2 result = { cos , - sin , sin , cos } ;
return result ;
2016-11-21 20:30:46 +01:00
}
// Returns the transpose of a given matrix 2x2
2021-01-20 20:55:12 +01:00
static inline Matrix2x2 MathMatTranspose ( Matrix2x2 matrix )
2016-11-21 20:30:46 +01:00
{
2021-01-20 20:55:12 +01:00
Matrix2x2 result = { matrix . m00 , matrix . m10 , matrix . m01 , matrix . m11 } ;
return result ;
2016-11-21 20:30:46 +01:00
}
// Multiplies a vector by a matrix 2x2
2021-01-20 20:55:12 +01:00
static inline Vector2 MathMatVector2Product ( Matrix2x2 matrix , Vector2 vector )
2016-11-21 20:30:46 +01:00
{
2021-01-20 20:55:12 +01:00
Vector2 result = { matrix . m00 * vector . x + matrix . m01 * vector . y , matrix . m10 * vector . x + matrix . m11 * vector . y } ;
return result ;
2016-06-09 20:01:59 +02:00
}
2018-07-29 13:09:30 +02:00
# endif // PHYSAC_IMPLEMENTATION