2015-12-21 21:12:35 +01:00
/**********************************************************************************************
*
2017-02-16 00:50:02 +01:00
* Physac v1 .0 - 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 .
*
* # define PHYSAC_STATIC ( defined by default )
2017-04-16 19:08:34 +02:00
* The generated implementation will stay private inside implementation file and all
2016-06-09 20:01:59 +02:00
* internal symbols and functions will only be visible inside that file .
*
2016-06-14 20:54:20 +02:00
* # define PHYSAC_NO_THREADS
* The generated implementation won ' t include pthread library and user must create a secondary thread to call PhysicsThread ( ) .
* It is so important that the thread where PhysicsThread ( ) is called must not have v - sync or any other CPU limitation .
*
2016-06-09 20:01:59 +02:00
* # define PHYSAC_STANDALONE
* Avoid raylib . h header inclusion in this file . Data types defined on raylib are defined
* internally in the library and input management and drawing functions must be provided by
* the user ( check library implementation for further details ) .
*
2016-11-21 20:30:46 +01:00
* # define PHYSAC_DEBUG
2017-04-16 19:08:34 +02:00
* Traces log messages when creating and destroying physics bodies and detects errors in physics
2016-11-21 20:30:46 +01:00
* calculations and reference exceptions ; it is useful for debug purposes
*
2016-06-09 20:01:59 +02:00
* # define PHYSAC_MALLOC ( )
* # 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 .
*
2017-03-06 22:57:33 +01:00
*
2017-04-16 19:08:34 +02:00
* NOTE 1 : Physac requires multi - threading , when InitPhysics ( ) a second thread is created to manage physics calculations .
* NOTE 2 : Physac requires static C library linkage to avoid dependency on MinGW DLL ( - static - lpthread )
2017-03-06 22:57:33 +01:00
*
2017-04-16 19:08:34 +02:00
* Use the following code to compile :
2019-05-10 20:51:48 +02:00
* gcc - o $ ( NAME_PART ) . exe $ ( FILE_NAME ) - s - static - lraylib - lpthread - lopengl32 - lgdi32 - lwinmm - std = c99
2017-03-06 22:57:33 +01:00
*
2016-11-21 20:30:46 +01:00
* VERY THANKS TO :
2017-12-24 15:59:03 +01:00
* Ramon Santamaria ( github : @ raysan5 )
2017-02-16 00:50:02 +01:00
*
2016-06-09 20:01:59 +02:00
*
* LICENSE : zlib / libpng
*
2018-03-10 19:25:17 +01:00
* Copyright ( c ) 2016 - 2018 Victor Fisac ( github : @ victorfisac )
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
2017-04-16 19:08:34 +02:00
// #define PHYSAC_STATIC
2016-11-21 20:30:46 +01:00
// #define PHYSAC_NO_THREADS
// #define PHYSAC_STANDALONE
// #define PHYSAC_DEBUG
# if defined(PHYSAC_STATIC)
2016-06-09 20:01:59 +02:00
# define PHYSACDEF static // Functions just visible to module including this file
# else
2016-11-21 20:30:46 +01:00
# if defined(__cplusplus)
2016-06-09 20:01:59 +02:00
# define PHYSACDEF extern "C" // Functions visible from other files (no name mangling of functions in C++)
# else
# define PHYSACDEF extern // Functions visible from other files
# endif
# endif
2015-12-21 21:12:35 +01:00
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
2016-11-21 20:30:46 +01:00
# define PHYSAC_MAX_BODIES 64
# define PHYSAC_MAX_MANIFOLDS 4096
# define PHYSAC_MAX_VERTICES 24
# define PHYSAC_CIRCLE_VERTICES 24
# define PHYSAC_COLLISION_ITERATIONS 100
# define PHYSAC_PENETRATION_ALLOWANCE 0.05f
# define PHYSAC_PENETRATION_CORRECTION 0.4f
# define PHYSAC_PI 3.14159265358979323846
# define PHYSAC_DEG2RAD (PHYSAC_PI / 180.0f)
# define PHYSAC_MALLOC(size) malloc(size)
# define PHYSAC_FREE(ptr) free(ptr)
2015-12-21 21:12:35 +01:00
//----------------------------------------------------------------------------------
// Types and Structures Definition
2016-03-05 17:05:02 +01:00
// NOTE: Below types are required for PHYSAC_STANDALONE usage
2015-12-21 21:12:35 +01:00
//----------------------------------------------------------------------------------
2016-06-09 20:01:59 +02:00
# if defined(PHYSAC_STANDALONE)
// Vector2 type
typedef struct Vector2 {
float x ;
float y ;
} Vector2 ;
2016-11-21 20:30:46 +01:00
// Boolean type
# if !defined(_STDBOOL_H)
typedef enum { false , true } bool ;
# define _STDBOOL_H
# endif
# endif
typedef enum PhysicsShapeType { PHYSICS_CIRCLE , PHYSICS_POLYGON } PhysicsShapeType ;
// Previously defined to be used in PhysicsShape struct as circular dependencies
typedef struct PhysicsBodyData * PhysicsBody ;
// Mat2 type (used for polygon shape rotation matrix)
2018-03-10 19:25:17 +01:00
typedef struct Mat2 {
2016-11-21 20:30:46 +01:00
float m00 ;
float m01 ;
float m10 ;
float m11 ;
} Mat2 ;
typedef struct PolygonData {
unsigned int vertexCount ; // Current used vertex and normals count
2018-03-10 19:25:17 +01:00
Vector2 positions [ PHYSAC_MAX_VERTICES ] ; // Polygon vertex positions vectors
2016-11-21 20:30:46 +01:00
Vector2 normals [ PHYSAC_MAX_VERTICES ] ; // Polygon vertex normals vectors
} PolygonData ;
typedef struct PhysicsShape {
PhysicsShapeType type ; // Physics shape type (circle or polygon)
PhysicsBody body ; // Shape physics body reference
float radius ; // Circle shape radius (used for circle shapes)
2018-03-10 19:25:17 +01:00
Mat2 transform ; // Vertices transform matrix 2x2
2016-11-21 20:30:46 +01:00
PolygonData vertexData ; // Polygon shape vertices position and normals data (just used for polygon shapes)
} PhysicsShape ;
typedef struct PhysicsBodyData {
unsigned int id ; // Reference unique identifier
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
PhysicsShape shape ; // Physics body shape information (type, radius, vertices, normals)
} PhysicsBodyData ;
typedef struct PhysicsManifoldData {
unsigned int id ; // Reference unique identifier
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 ;
# if defined(__cplusplus)
extern " C " { // Prevents name mangling of functions
2016-06-09 20:01:59 +02:00
# endif
2016-03-05 17:05:02 +01:00
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
//----------------------------------------------------------------------------------
2016-11-21 20:30:46 +01:00
PHYSACDEF void InitPhysics ( void ) ; // Initializes physics values, pointers and creates physics loop thread
2018-07-29 13:09:30 +02:00
PHYSACDEF void RunPhysicsStep ( void ) ; // Run physics step, to be used if PHYSICS_NO_THREADS is set in your main loop
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 bool IsPhysicsEnabled ( void ) ; // Returns true if physics thread is currently enabled
PHYSACDEF void SetPhysicsGravity ( float x , float y ) ; // Sets physics global gravity force
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
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
PHYSACDEF int GetPhysicsBodiesCount ( void ) ; // Returns the current amount of created physics bodies
PHYSACDEF PhysicsBody GetPhysicsBody ( int index ) ; // Returns a physics body of the bodies pool at a specific index
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)
PHYSACDEF void SetPhysicsBodyRotation ( PhysicsBody body , float radians ) ; // Sets physics body shape transform based on radians parameter
PHYSACDEF void DestroyPhysicsBody ( PhysicsBody body ) ; // Unitializes and destroy a physics body
PHYSACDEF void ResetPhysics ( void ) ; // Destroys created physics bodies and manifolds and resets global values
PHYSACDEF void ClosePhysics ( void ) ; // Unitializes physics pointers and closes physics loop thread
2015-12-21 21:12:35 +01:00
2016-11-21 20:30:46 +01:00
# 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)
2016-11-21 20:30:46 +01:00
# if !defined(PHYSAC_NO_THREADS)
# include <pthread.h> // Required for: pthread_t, pthread_create()
2016-06-09 20:01:59 +02:00
# endif
2016-11-21 20:30:46 +01:00
# if defined(PHYSAC_DEBUG)
# include <stdio.h> // Required for: printf()
2016-06-14 20:23:46 +02:00
# endif
2016-06-12 22:07:06 +02:00
2016-11-21 20:30:46 +01:00
# include <stdlib.h> // Required for: malloc(), free(), srand(), rand()
# include <math.h> // Required for: cosf(), sinf(), fabs(), sqrtf()
2017-12-24 15:59:03 +01:00
# include <stdint.h> // Required for: uint64_t
# if !defined(PHYSAC_STANDALONE)
# include "raymath.h" // Required for: Vector2Add(), Vector2Subtract()
# endif
2016-11-21 20:30:46 +01:00
2017-12-24 15:59:03 +01:00
// Time management functionality
2018-07-29 13:09:30 +02:00
# include <time.h> // Required for: time(), clock_gettime()
2017-12-24 15:59:03 +01:00
# if defined(_WIN32)
// Functions required to query time on Windows
int __stdcall QueryPerformanceCounter ( unsigned long long int * lpPerformanceCount ) ;
int __stdcall QueryPerformanceFrequency ( unsigned long long int * lpFrequency ) ;
# elif defined(__linux__)
# 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
2018-07-29 13:09:30 +02:00
# elif defined(__APPLE__) // macOS also defines __MACH__
2017-12-24 15:59:03 +01:00
# include <mach/mach_time.h> // Required for: mach_absolute_time()
# endif
2017-05-16 15:23:01 +02:00
2016-06-09 20:01:59 +02:00
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
2016-11-21 20:30:46 +01:00
# define min(a,b) (((a)<(b))?(a):(b))
# define max(a,b) (((a)>(b))?(a):(b))
# define PHYSAC_FLT_MAX 3.402823466e+38f
# define PHYSAC_EPSILON 0.000001f
2018-03-10 19:25:17 +01:00
# define PHYSAC_K 1.0f / 3.0f
# define PHYSAC_VECTOR_ZERO (Vector2){ 0.0f, 0.0f }
2016-06-09 20:01:59 +02:00
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
2016-11-21 20:30:46 +01:00
# if !defined(PHYSAC_NO_THREADS)
2017-05-11 17:22:25 +02:00
static pthread_t physicsThreadId ; // Physics thread id
2016-11-21 20:30:46 +01:00
# endif
static unsigned int usedMemory = 0 ; // Total allocated dynamic memory
static bool physicsThreadEnabled = false ; // Physics thread enabled state
2018-03-10 19:25:17 +01:00
static double baseTime = 0.0 ; // Offset time for MONOTONIC clock
static double startTime = 0.0 ; // Start time in milliseconds
2018-09-23 13:55:39 +02:00
static double deltaTime = 1.0 / 60.0 / 10.0 * 1000 ; // Delta time used for physics steps, in milliseconds
2018-03-10 19:25:17 +01:00
static double currentTime = 0.0 ; // Current time in milliseconds
static uint64_t frequency = 0 ; // Hi-res clock frequency
2017-12-24 15:59:03 +01:00
2018-03-10 19:25:17 +01:00
static double accumulator = 0.0 ; // Physics time step delta time accumulator
2016-11-21 20:30:46 +01:00
static unsigned int stepsCount = 0 ; // Total physics steps processed
2018-09-23 13:55:39 +02:00
static Vector2 gravityForce = { 0.0f , 9.81f } ; // Physics world gravity force
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
//----------------------------------------------------------------------------------
2016-11-21 20:30:46 +01:00
// Module Internal Functions Declaration
2016-06-09 20:01:59 +02:00
//----------------------------------------------------------------------------------
2018-03-10 19:25:17 +01:00
static int FindAvailableBodyIndex ( ) ; // Finds a valid index for a new physics body initialization
2016-11-21 20:30:46 +01:00
static PolygonData CreateRandomPolygon ( float radius , int sides ) ; // Creates a random polygon shape with max vertex distance from polygon pivot
static PolygonData CreateRectanglePolygon ( Vector2 pos , Vector2 size ) ; // Creates a rectangle polygon shape based on a min and max positions
static void * PhysicsLoop ( void * arg ) ; // Physics loop thread function
static void PhysicsStep ( void ) ; // Physics steps calculations (dynamics, collisions and position corrections)
2018-03-10 19:25:17 +01:00
static int FindAvailableManifoldIndex ( ) ; // Finds a valid index for a new manifold initialization
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
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 InitializePhysicsManifolds ( PhysicsManifold manifold ) ; // Initializes physics manifolds to solve collisions
static void IntegratePhysicsImpulses ( PhysicsManifold manifold ) ; // Integrates physics collisions impulses to solve collisions
static void IntegratePhysicsVelocity ( PhysicsBody body ) ; // Integrates physics velocity into position and forces
static void CorrectPhysicsPositions ( PhysicsManifold manifold ) ; // Corrects physics bodies positions based on manifolds collision information
static float FindAxisLeastPenetration ( int * faceIndex , PhysicsShape shapeA , PhysicsShape shapeB ) ; // Finds polygon shapes axis least penetration
static void FindIncidentFace ( Vector2 * v0 , Vector2 * v1 , PhysicsShape ref , PhysicsShape inc , int index ) ; // Finds two polygon shapes incident face
static int Clip ( Vector2 normal , float clip , Vector2 * faceA , Vector2 * faceB ) ; // Calculates clipping based on a normal and two faces
static bool BiasGreaterThan ( float valueA , float valueB ) ; // Check if values are between bias range
static Vector2 TriangleBarycenter ( Vector2 v1 , Vector2 v2 , Vector2 v3 ) ; // Returns the barycenter of a triangle given by 3 points
2017-05-11 17:22:25 +02:00
2017-12-24 15:59:03 +01:00
static void InitTimer ( void ) ; // Initializes hi-resolution MONOTONIC timer
2018-09-23 13:55:39 +02:00
static uint64_t GetTimeCount ( void ) ; // Get hi-res MONOTONIC time measure in mseconds
static double GetCurrentTime ( void ) ; // Get current time measure in milliseconds
2017-12-24 15:59:03 +01:00
2017-05-11 17:22:25 +02:00
// Math functions
2016-11-21 20:30:46 +01:00
static Vector2 MathCross ( float value , Vector2 vector ) ; // Returns the cross product of a vector and a value
static float MathCrossVector2 ( Vector2 v1 , Vector2 v2 ) ; // Returns the cross product of two vectors
static float MathLenSqr ( Vector2 vector ) ; // Returns the len square root of a vector
static float MathDot ( Vector2 v1 , Vector2 v2 ) ; // Returns the dot product of two vectors
static inline float DistSqr ( Vector2 v1 , Vector2 v2 ) ; // Returns the square root of distance between two vectors
static void MathNormalize ( Vector2 * vector ) ; // Returns the normalized values of a vector
2017-05-11 17:22:25 +02:00
# if defined(PHYSAC_STANDALONE)
2016-11-21 20:30:46 +01:00
static Vector2 Vector2Add ( Vector2 v1 , Vector2 v2 ) ; // Returns the sum of two given vectors
static Vector2 Vector2Subtract ( Vector2 v1 , Vector2 v2 ) ; // Returns the subtract of two given vectors
2017-05-11 17:22:25 +02:00
# endif
2016-11-21 20:30:46 +01:00
2018-03-10 19:25:17 +01:00
static Mat2 Mat2Radians ( float radians ) ; // Creates a matrix 2x2 from a given radians value
2016-11-21 20:30:46 +01:00
static void Mat2Set ( Mat2 * matrix , float radians ) ; // Set values from radians to a created matrix 2x2
2017-12-24 15:59:03 +01:00
static inline Mat2 Mat2Transpose ( Mat2 matrix ) ; // Returns the transpose of a given matrix 2x2
static inline Vector2 Mat2MultiplyVector2 ( Mat2 matrix , Vector2 vector ) ; // Multiplies a vector by a matrix 2x2
2016-06-09 20:01:59 +02:00
//----------------------------------------------------------------------------------
// Module Functions Definition
//----------------------------------------------------------------------------------
2016-11-21 20:30:46 +01:00
// Initializes physics values, pointers and creates physics loop thread
PHYSACDEF void InitPhysics ( void )
{
# if !defined(PHYSAC_NO_THREADS)
// NOTE: if defined, user will need to create a thread for PhysicsThread function manually
// Create physics thread using POSIXS thread libraries
pthread_create ( & physicsThreadId , NULL , & PhysicsLoop , NULL ) ;
2016-06-14 20:23:46 +02:00
# endif
2018-07-29 13:09:30 +02:00
// Initialize high resolution timer
InitTimer ( ) ;
2017-12-24 15:59:03 +01:00
# if defined(PHYSAC_DEBUG)
printf ( " [PHYSAC] physics module initialized successfully \n " ) ;
# endif
2018-09-23 13:55:39 +02:00
accumulator = 0.0 ;
2016-06-09 20:01:59 +02:00
}
2016-11-21 20:30:46 +01:00
// Returns true if physics thread is currently enabled
PHYSACDEF bool IsPhysicsEnabled ( void )
2016-06-14 20:38:49 +02:00
{
2016-11-21 20:30:46 +01:00
return physicsThreadEnabled ;
}
// Sets physics global gravity force
PHYSACDEF void SetPhysicsGravity ( float x , float y )
{
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
PHYSACDEF PhysicsBody CreatePhysicsBodyCircle ( Vector2 pos , float radius , float density )
2016-06-14 20:38:49 +02:00
{
2016-11-21 20:30:46 +01:00
PhysicsBody newBody = CreatePhysicsBodyPolygon ( pos , radius , PHYSAC_CIRCLE_VERTICES , density ) ;
return newBody ;
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
PHYSACDEF PhysicsBody CreatePhysicsBodyRectangle ( Vector2 pos , float width , float height , float density )
2016-06-14 20:38:49 +02:00
{
2016-11-21 20:30:46 +01:00
PhysicsBody newBody = ( PhysicsBody ) PHYSAC_MALLOC ( sizeof ( PhysicsBodyData ) ) ;
usedMemory + = sizeof ( PhysicsBodyData ) ;
2018-03-10 19:25:17 +01:00
int newId = FindAvailableBodyIndex ( ) ;
2016-11-21 20:30:46 +01:00
if ( newId ! = - 1 )
2016-06-14 20:38:49 +02:00
{
2016-11-21 20:30:46 +01:00
// Initialize new body with generic values
newBody - > id = newId ;
newBody - > enabled = true ;
2017-04-16 19:08:34 +02:00
newBody - > position = pos ;
2018-03-10 19:25:17 +01:00
newBody - > velocity = ( Vector2 ) { 0.0f } ;
newBody - > force = ( Vector2 ) { 0.0f } ;
newBody - > angularVelocity = 0.0f ;
newBody - > torque = 0.0f ;
newBody - > orient = 0.0f ;
2016-11-21 20:30:46 +01:00
newBody - > shape . type = PHYSICS_POLYGON ;
newBody - > shape . body = newBody ;
2018-03-10 19:25:17 +01:00
newBody - > shape . radius = 0.0f ;
newBody - > shape . transform = Mat2Radians ( 0.0f ) ;
2016-11-21 20:30:46 +01:00
newBody - > shape . vertexData = CreateRectanglePolygon ( pos , ( Vector2 ) { width , height } ) ;
// 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
for ( int i = 0 ; i < newBody - > shape . vertexData . vertexCount ; i + + )
{
// Triangle vertices, third vertex implied as (0, 0)
2018-03-10 19:25:17 +01:00
Vector2 p1 = newBody - > shape . vertexData . positions [ i ] ;
2016-11-21 20:30:46 +01:00
int nextIndex = ( ( ( i + 1 ) < newBody - > shape . vertexData . vertexCount ) ? ( i + 1 ) : 0 ) ;
2018-03-10 19:25:17 +01:00
Vector2 p2 = newBody - > shape . vertexData . positions [ nextIndex ] ;
2016-11-21 20:30:46 +01:00
float D = MathCrossVector2 ( p1 , p2 ) ;
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
for ( int i = 0 ; i < newBody - > shape . vertexData . vertexCount ; i + + )
2016-06-14 20:38:49 +02:00
{
2018-03-10 19:25:17 +01:00
newBody - > shape . vertexData . positions [ i ] . x - = center . x ;
newBody - > shape . vertexData . positions [ i ] . y - = center . y ;
2016-06-14 20:38:49 +02:00
}
2016-11-21 20:30:46 +01:00
newBody - > mass = density * area ;
newBody - > inverseMass = ( ( newBody - > mass ! = 0.0f ) ? 1.0f / newBody - > mass : 0.0f ) ;
newBody - > inertia = density * inertia ;
newBody - > inverseInertia = ( ( newBody - > inertia ! = 0.0f ) ? 1.0f / newBody - > inertia : 0.0f ) ;
newBody - > staticFriction = 0.4f ;
newBody - > dynamicFriction = 0.2f ;
2018-03-10 19:25:17 +01:00
newBody - > restitution = 0.0f ;
2016-11-21 20:30:46 +01:00
newBody - > useGravity = true ;
newBody - > isGrounded = false ;
newBody - > freezeOrient = false ;
// Add new body to bodies pointers array and update bodies count
bodies [ physicsBodiesCount ] = newBody ;
physicsBodiesCount + + ;
# if defined(PHYSAC_DEBUG)
printf ( " [PHYSAC] created polygon physics body id %i \n " , newBody - > id ) ;
# endif
2016-06-14 20:38:49 +02:00
}
2016-11-21 20:30:46 +01:00
# if defined(PHYSAC_DEBUG)
else printf ( " [PHYSAC] new physics body creation failed because there is any available id to use \n " ) ;
# endif
return newBody ;
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
PHYSACDEF PhysicsBody CreatePhysicsBodyPolygon ( Vector2 pos , float radius , int sides , float density )
2016-06-14 20:38:49 +02:00
{
2016-11-21 20:30:46 +01:00
PhysicsBody newBody = ( PhysicsBody ) PHYSAC_MALLOC ( sizeof ( PhysicsBodyData ) ) ;
usedMemory + = sizeof ( PhysicsBodyData ) ;
2018-03-10 19:25:17 +01:00
int newId = FindAvailableBodyIndex ( ) ;
2016-11-21 20:30:46 +01:00
if ( newId ! = - 1 )
2016-06-14 20:38:49 +02:00
{
2016-11-21 20:30:46 +01:00
// Initialize new body with generic values
newBody - > id = newId ;
newBody - > enabled = true ;
2017-04-16 19:08:34 +02:00
newBody - > position = pos ;
2018-03-10 19:25:17 +01:00
newBody - > velocity = PHYSAC_VECTOR_ZERO ;
newBody - > force = PHYSAC_VECTOR_ZERO ;
newBody - > angularVelocity = 0.0f ;
newBody - > torque = 0.0f ;
newBody - > orient = 0.0f ;
2016-11-21 20:30:46 +01:00
newBody - > shape . type = PHYSICS_POLYGON ;
newBody - > shape . body = newBody ;
2018-03-10 19:25:17 +01:00
newBody - > shape . transform = Mat2Radians ( 0.0f ) ;
2016-11-21 20:30:46 +01:00
newBody - > shape . vertexData = CreateRandomPolygon ( radius , sides ) ;
// 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
for ( int i = 0 ; i < newBody - > shape . vertexData . vertexCount ; i + + )
{
// Triangle vertices, third vertex implied as (0, 0)
2018-03-10 19:25:17 +01:00
Vector2 position1 = newBody - > shape . vertexData . positions [ i ] ;
2016-11-21 20:30:46 +01:00
int nextIndex = ( ( ( i + 1 ) < newBody - > shape . vertexData . vertexCount ) ? ( i + 1 ) : 0 ) ;
2018-03-10 19:25:17 +01:00
Vector2 position2 = newBody - > shape . vertexData . positions [ nextIndex ] ;
2016-11-21 20:30:46 +01:00
float cross = MathCrossVector2 ( position1 , position2 ) ;
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
for ( int i = 0 ; i < newBody - > shape . vertexData . vertexCount ; i + + )
{
2018-03-10 19:25:17 +01:00
newBody - > shape . vertexData . positions [ i ] . x - = center . x ;
newBody - > shape . vertexData . positions [ i ] . y - = center . y ;
2016-11-21 20:30:46 +01:00
}
newBody - > mass = density * area ;
newBody - > inverseMass = ( ( newBody - > mass ! = 0.0f ) ? 1.0f / newBody - > mass : 0.0f ) ;
newBody - > inertia = density * inertia ;
newBody - > inverseInertia = ( ( newBody - > inertia ! = 0.0f ) ? 1.0f / newBody - > inertia : 0.0f ) ;
newBody - > staticFriction = 0.4f ;
newBody - > dynamicFriction = 0.2f ;
2018-03-10 19:25:17 +01:00
newBody - > restitution = 0.0f ;
2016-11-21 20:30:46 +01:00
newBody - > useGravity = true ;
newBody - > isGrounded = false ;
newBody - > freezeOrient = false ;
// Add new body to bodies pointers array and update bodies count
bodies [ physicsBodiesCount ] = newBody ;
physicsBodiesCount + + ;
# if defined(PHYSAC_DEBUG)
printf ( " [PHYSAC] created polygon physics body id %i \n " , newBody - > id ) ;
# endif
2016-06-14 20:38:49 +02:00
}
2016-11-21 20:30:46 +01:00
# if defined(PHYSAC_DEBUG)
else printf ( " [PHYSAC] new physics body creation failed because there is any available id to use \n " ) ;
# endif
return newBody ;
}
// Adds a force to a physics body
PHYSACDEF void PhysicsAddForce ( PhysicsBody body , Vector2 force )
{
if ( body ! = NULL ) body - > force = Vector2Add ( body - > force , force ) ;
}
// Adds an angular force to a physics body
PHYSACDEF void PhysicsAddTorque ( PhysicsBody body , float amount )
{
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
PHYSACDEF 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
{
2016-11-21 20:30:46 +01:00
PolygonData vertexData = body - > shape . vertexData ;
bool collision = false ;
2016-06-14 20:38:49 +02:00
2016-11-21 20:30:46 +01:00
for ( 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 ;
2018-03-10 19:25:17 +01:00
Vector2 positionB = Mat2MultiplyVector2 ( body - > shape . transform , Vector2Add ( body - > position , vertexData . positions [ i ] ) ) ;
2016-11-21 20:30:46 +01:00
int nextIndex = ( ( ( i + 1 ) < vertexData . vertexCount ) ? ( i + 1 ) : 0 ) ;
2018-03-10 19:25:17 +01:00
Vector2 positionC = Mat2MultiplyVector2 ( body - > shape . transform , Vector2Add ( 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 ;
2018-10-10 21:52:50 +02:00
Vector2 * vertices = ( Vector2 * ) malloc ( sizeof ( Vector2 ) * count ) ;
2018-03-10 19:25:17 +01:00
Mat2 trans = body - > shape . transform ;
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 ) ;
2018-03-10 19:25:17 +01:00
Vector2 center = TriangleBarycenter ( vertices [ i ] , vertices [ nextIndex ] , PHYSAC_VECTOR_ZERO ) ;
2016-11-21 20:30:46 +01:00
center = Vector2Add ( bodyPos , center ) ;
Vector2 offset = Vector2Subtract ( center , bodyPos ) ;
PhysicsBody newBody = CreatePhysicsBodyPolygon ( center , 10 , 3 , 10 ) ; // Create polygon physics body with relevant values
PolygonData newData = { 0 } ;
newData . vertexCount = 3 ;
2018-03-10 19:25:17 +01:00
newData . positions [ 0 ] = Vector2Subtract ( vertices [ i ] , offset ) ;
newData . positions [ 1 ] = Vector2Subtract ( vertices [ nextIndex ] , offset ) ;
newData . positions [ 2 ] = Vector2Subtract ( position , center ) ;
2016-11-21 20:30:46 +01:00
// Separate vertices to avoid unnecessary physics collisions
2018-03-10 19:25:17 +01:00
newData . positions [ 0 ] . x * = 0.95f ;
newData . positions [ 0 ] . y * = 0.95f ;
newData . positions [ 1 ] . x * = 0.95f ;
newData . positions [ 1 ] . y * = 0.95f ;
newData . positions [ 2 ] . x * = 0.95f ;
newData . positions [ 2 ] . y * = 0.95f ;
2016-11-21 20:30:46 +01:00
// Calculate polygon faces normals
for ( int j = 0 ; j < newData . vertexCount ; j + + )
{
int nextVertex = ( ( ( j + 1 ) < newData . vertexCount ) ? ( j + 1 ) : 0 ) ;
2018-03-10 19:25:17 +01:00
Vector2 face = Vector2Subtract ( newData . positions [ nextVertex ] , newData . positions [ j ] ) ;
2016-11-21 20:30:46 +01:00
newData . normals [ j ] = ( Vector2 ) { face . y , - face . x } ;
MathNormalize ( & newData . normals [ j ] ) ;
}
// Apply computed vertex data to new physics body shape
newBody - > shape . vertexData = newData ;
2018-03-10 19:25:17 +01:00
newBody - > 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
for ( int j = 0 ; j < newBody - > shape . vertexData . vertexCount ; j + + )
{
// Triangle vertices, third vertex implied as (0, 0)
2018-03-10 19:25:17 +01:00
Vector2 p1 = newBody - > shape . vertexData . positions [ j ] ;
2016-11-21 20:30:46 +01:00
int nextVertex = ( ( ( j + 1 ) < newBody - > shape . vertexData . vertexCount ) ? ( j + 1 ) : 0 ) ;
2018-03-10 19:25:17 +01:00
Vector2 p2 = newBody - > shape . vertexData . positions [ nextVertex ] ;
2016-11-21 20:30:46 +01:00
float D = MathCrossVector2 ( p1 , p2 ) ;
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 ;
newBody - > mass = area ;
newBody - > inverseMass = ( ( newBody - > mass ! = 0.0f ) ? 1.0f / newBody - > mass : 0.0f ) ;
newBody - > inertia = inertia ;
newBody - > inverseInertia = ( ( newBody - > inertia ! = 0.0f ) ? 1.0f / newBody - > inertia : 0.0f ) ;
// Calculate explosion force direction
Vector2 pointA = newBody - > position ;
2018-03-10 19:25:17 +01:00
Vector2 pointB = Vector2Subtract ( newData . positions [ 1 ] , newData . positions [ 0 ] ) ;
pointB . x / = 2.0f ;
pointB . y / = 2.0f ;
Vector2 forceDirection = Vector2Subtract ( Vector2Add ( pointA , Vector2Add ( newData . positions [ 0 ] , pointB ) ) , newBody - > position ) ;
2016-11-21 20:30:46 +01:00
MathNormalize ( & forceDirection ) ;
forceDirection . x * = force ;
forceDirection . y * = force ;
// Apply force to new physics body
PhysicsAddForce ( newBody , forceDirection ) ;
}
2018-10-10 21:52:50 +02:00
free ( vertices ) ;
2016-06-14 20:38:49 +02:00
}
}
}
2016-11-21 20:30:46 +01:00
# if defined(PHYSAC_DEBUG)
else printf ( " [PHYSAC] error when trying to shatter a null reference physics body " ) ;
# endif
2016-06-14 20:38:49 +02:00
}
2016-11-21 20:30:46 +01:00
// Returns the current amount of created physics bodies
PHYSACDEF 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
PHYSACDEF 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
2016-11-21 20:30:46 +01:00
if ( index < 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
2017-04-16 19:08:34 +02:00
if ( body = = NULL )
2016-11-21 20:30:46 +01:00
{
# if defined(PHYSAC_DEBUG)
printf ( " [PHYSAC] error when trying to get a null reference physics body " ) ;
# endif
}
2016-06-14 20:38:49 +02:00
}
2016-11-21 20:30:46 +01:00
# if defined(PHYSAC_DEBUG)
2017-04-16 19:08:34 +02:00
else printf ( " [PHYSAC] physics body index is out of bounds " ) ;
2016-11-21 20:30:46 +01:00
# endif
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)
PHYSACDEF 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
2016-11-21 20:30:46 +01:00
if ( index < 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 ;
2016-11-21 20:30:46 +01:00
# if defined(PHYSAC_DEBUG)
2017-04-16 19:08:34 +02:00
else printf ( " [PHYSAC] error when trying to get a null reference physics body " ) ;
2016-11-21 20:30:46 +01:00
# endif
2016-06-14 20:38:49 +02:00
}
2016-11-21 20:30:46 +01:00
# if defined(PHYSAC_DEBUG)
2017-04-16 19:08:34 +02:00
else printf ( " [PHYSAC] physics body index is out of bounds " ) ;
2016-11-21 20:30:46 +01:00
# endif
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
PHYSACDEF 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
2016-11-21 20:30:46 +01:00
if ( index < physicsBodiesCount )
{
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 )
{
2017-04-16 19:08:34 +02:00
case PHYSICS_CIRCLE : result = PHYSAC_CIRCLE_VERTICES ; break ;
case PHYSICS_POLYGON : result = body - > shape . vertexData . vertexCount ; break ;
2016-11-21 20:30:46 +01:00
default : break ;
}
}
# if defined(PHYSAC_DEBUG)
2017-04-16 19:08:34 +02:00
else printf ( " [PHYSAC] error when trying to get a null reference physics body " ) ;
2016-11-21 20:30:46 +01:00
# endif
}
# if defined(PHYSAC_DEBUG)
2017-04-16 19:08:34 +02:00
else printf ( " [PHYSAC] physics body index is out of bounds " ) ;
2016-11-21 20:30:46 +01:00
# endif
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)
PHYSACDEF 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 :
{
2018-03-10 19:25:17 +01:00
position . x = body - > position . x + cosf ( 360.0f / PHYSAC_CIRCLE_VERTICES * vertex * PHYSAC_DEG2RAD ) * body - > shape . radius ;
position . y = body - > position . y + sinf ( 360.0f / PHYSAC_CIRCLE_VERTICES * vertex * PHYSAC_DEG2RAD ) * body - > shape . radius ;
2016-11-21 20:30:46 +01:00
} break ;
case PHYSICS_POLYGON :
{
PolygonData vertexData = body - > shape . vertexData ;
2018-03-10 19:25:17 +01:00
position = Vector2Add ( body - > position , Mat2MultiplyVector2 ( body - > shape . transform , vertexData . positions [ vertex ] ) ) ;
2016-11-21 20:30:46 +01:00
} break ;
default : break ;
}
}
# if defined(PHYSAC_DEBUG)
else printf ( " [PHYSAC] error when trying to get a null reference physics body " ) ;
# endif
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
PHYSACDEF 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 ;
2018-03-10 19:25:17 +01:00
if ( body - > shape . type = = PHYSICS_POLYGON ) body - > shape . transform = Mat2Radians ( 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
PHYSACDEF 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 ;
for ( 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 )
{
# if defined(PHYSAC_DEBUG)
printf ( " [PHYSAC] Not possible to find body id %i in pointers array \n " , id ) ;
# endif
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
for ( int i = index ; i < physicsBodiesCount ; i + + )
{
if ( ( i + 1 ) < physicsBodiesCount ) bodies [ i ] = bodies [ i + 1 ] ;
}
// Update physics bodies count
physicsBodiesCount - - ;
# if defined(PHYSAC_DEBUG)
printf ( " [PHYSAC] destroyed physics body id %i \n " , id ) ;
# endif
}
# if defined(PHYSAC_DEBUG)
else printf ( " [PHYSAC] error trying to destroy a null referenced body \n " ) ;
# endif
}
// Destroys created physics bodies and manifolds and resets global values
PHYSACDEF void ResetPhysics ( void )
{
// Unitialize physics bodies dynamic memory allocations
for ( int i = physicsBodiesCount - 1 ; i > = 0 ; i - - )
{
PhysicsBody body = bodies [ i ] ;
if ( body ! = NULL )
{
PHYSAC_FREE ( body ) ;
2018-03-10 19:25:17 +01:00
bodies [ i ] = NULL ;
2016-11-21 20:30:46 +01:00
usedMemory - = sizeof ( PhysicsBodyData ) ;
}
}
physicsBodiesCount = 0 ;
// Unitialize physics manifolds dynamic memory allocations
for ( int i = physicsManifoldsCount - 1 ; i > = 0 ; i - - )
{
PhysicsManifold manifold = contacts [ i ] ;
if ( manifold ! = NULL )
{
PHYSAC_FREE ( manifold ) ;
2018-03-10 19:25:17 +01:00
contacts [ i ] = NULL ;
2016-11-21 20:30:46 +01:00
usedMemory - = sizeof ( PhysicsManifoldData ) ;
}
2016-06-09 20:01:59 +02:00
}
2016-11-21 20:30:46 +01:00
physicsManifoldsCount = 0 ;
# if defined(PHYSAC_DEBUG)
printf ( " [PHYSAC] physics module reset successfully \n " ) ;
# endif
}
// Unitializes physics pointers and exits physics loop thread
PHYSACDEF void ClosePhysics ( void )
{
// Exit physics loop thread
physicsThreadEnabled = false ;
# if !defined(PHYSAC_NO_THREADS)
pthread_join ( physicsThreadId , NULL ) ;
# endif
2018-09-23 13:55:39 +02:00
// Unitialize physics manifolds dynamic memory allocations
for ( int i = physicsManifoldsCount - 1 ; i > = 0 ; i - - ) DestroyPhysicsManifold ( contacts [ i ] ) ;
// Unitialize physics bodies dynamic memory allocations
for ( int i = physicsBodiesCount - 1 ; i > = 0 ; i - - ) DestroyPhysicsBody ( bodies [ i ] ) ;
# if defined(PHYSAC_DEBUG)
if ( physicsBodiesCount > 0 | | usedMemory ! = 0 ) printf ( " [PHYSAC] physics module closed with %i still allocated bodies [MEMORY: %i bytes] \n " , physicsBodiesCount , usedMemory ) ;
else if ( physicsManifoldsCount > 0 | | usedMemory ! = 0 ) printf ( " [PHYSAC] physics module closed with %i still allocated manifolds [MEMORY: %i bytes] \n " , physicsManifoldsCount , usedMemory ) ;
else printf ( " [PHYSAC] physics module closed successfully \n " ) ;
# endif
2016-11-21 20:30:46 +01:00
}
//----------------------------------------------------------------------------------
// Module Internal Functions Definition
//----------------------------------------------------------------------------------
2018-03-10 19:25:17 +01:00
// Finds a valid index for a new physics body initialization
static int FindAvailableBodyIndex ( )
{
int index = - 1 ;
for ( int i = 0 ; i < PHYSAC_MAX_BODIES ; i + + )
{
int currentId = i ;
// Check if current id already exist in other physics body
for ( int k = 0 ; k < physicsBodiesCount ; k + + )
{
if ( bodies [ k ] - > id = = currentId )
{
currentId + + ;
break ;
}
}
// If it is not used, use it as new physics body id
if ( currentId = = i )
{
index = i ;
break ;
}
}
return index ;
}
2016-11-21 20:30:46 +01:00
// Creates a random polygon shape with max vertex distance from polygon pivot
static PolygonData CreateRandomPolygon ( float radius , int sides )
{
PolygonData data = { 0 } ;
data . vertexCount = sides ;
// Calculate polygon vertices positions
for ( int i = 0 ; i < data . vertexCount ; i + + )
{
2018-03-10 19:25:17 +01:00
data . positions [ i ] . x = cosf ( 360.0f / sides * i * PHYSAC_DEG2RAD ) * radius ;
data . positions [ i ] . y = sinf ( 360.0f / sides * i * PHYSAC_DEG2RAD ) * radius ;
2016-11-21 20:30:46 +01:00
}
// Calculate polygon faces normals
for ( int i = 0 ; i < data . vertexCount ; i + + )
{
int nextIndex = ( ( ( i + 1 ) < sides ) ? ( i + 1 ) : 0 ) ;
2018-03-10 19:25:17 +01:00
Vector2 face = Vector2Subtract ( data . positions [ nextIndex ] , data . positions [ i ] ) ;
2016-11-21 20:30:46 +01:00
data . normals [ i ] = ( Vector2 ) { face . y , - face . x } ;
MathNormalize ( & data . normals [ i ] ) ;
}
return data ;
}
// Creates a rectangle polygon shape based on a min and max positions
static PolygonData CreateRectanglePolygon ( Vector2 pos , Vector2 size )
{
PolygonData data = { 0 } ;
data . vertexCount = 4 ;
// Calculate polygon vertices positions
2018-03-10 19:25:17 +01:00
data . positions [ 0 ] = ( Vector2 ) { pos . x + size . x / 2 , pos . y - size . y / 2 } ;
data . positions [ 1 ] = ( Vector2 ) { pos . x + size . x / 2 , pos . y + size . y / 2 } ;
data . positions [ 2 ] = ( Vector2 ) { pos . x - size . x / 2 , pos . y + size . y / 2 } ;
data . positions [ 3 ] = ( Vector2 ) { pos . x - size . x / 2 , pos . y - size . y / 2 } ;
2016-11-21 20:30:46 +01:00
// Calculate polygon faces normals
for ( int i = 0 ; i < data . vertexCount ; i + + )
{
int nextIndex = ( ( ( i + 1 ) < data . vertexCount ) ? ( i + 1 ) : 0 ) ;
2018-03-10 19:25:17 +01:00
Vector2 face = Vector2Subtract ( data . positions [ nextIndex ] , data . positions [ i ] ) ;
2016-11-21 20:30:46 +01:00
data . normals [ i ] = ( Vector2 ) { face . y , - face . x } ;
MathNormalize ( & data . normals [ i ] ) ;
}
return data ;
}
// Physics loop thread function
static void * PhysicsLoop ( void * arg )
{
# if defined(PHYSAC_DEBUG)
2017-12-24 15:59:03 +01:00
printf ( " [PHYSAC] physics thread created successfully \n " ) ;
2016-11-21 20:30:46 +01:00
# endif
// Initialize physics loop thread values
physicsThreadEnabled = true ;
// Physics update loop
while ( physicsThreadEnabled )
{
2018-07-29 13:09:30 +02:00
RunPhysicsStep ( ) ;
2016-11-21 20:30:46 +01:00
}
return NULL ;
}
// Physics steps calculations (dynamics, collisions and position corrections)
static void PhysicsStep ( void )
{
2017-03-06 09:58:28 +01:00
// Update current steps count
2016-11-21 20:30:46 +01:00
stepsCount + + ;
// Clear previous generated collisions information
for ( int i = physicsManifoldsCount - 1 ; i > = 0 ; i - - )
{
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
for ( int i = 0 ; i < physicsBodiesCount ; i + + )
{
PhysicsBody body = bodies [ i ] ;
body - > isGrounded = false ;
}
2016-11-21 20:30:46 +01:00
// Generate new collision information
for ( int i = 0 ; i < physicsBodiesCount ; i + + )
{
PhysicsBody bodyA = bodies [ i ] ;
if ( bodyA ! = NULL )
{
for ( int j = i + 1 ; j < physicsBodiesCount ; j + + )
{
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
PhysicsManifold newManifold = CreatePhysicsManifold ( bodyA , bodyB ) ;
newManifold - > penetration = manifold - > penetration ;
newManifold - > normal = manifold - > normal ;
newManifold - > contacts [ 0 ] = manifold - > contacts [ 0 ] ;
newManifold - > contacts [ 1 ] = manifold - > contacts [ 1 ] ;
newManifold - > contactsCount = manifold - > contactsCount ;
newManifold - > restitution = manifold - > restitution ;
newManifold - > dynamicFriction = manifold - > dynamicFriction ;
newManifold - > staticFriction = manifold - > staticFriction ;
}
}
}
}
}
// Integrate forces to physics bodies
for ( int i = 0 ; i < physicsBodiesCount ; i + + )
{
PhysicsBody body = bodies [ i ] ;
if ( body ! = NULL ) IntegratePhysicsForces ( body ) ;
}
// Initialize physics manifolds to solve collisions
for ( int i = 0 ; i < physicsManifoldsCount ; i + + )
{
PhysicsManifold manifold = contacts [ i ] ;
if ( manifold ! = NULL ) InitializePhysicsManifolds ( manifold ) ;
}
// Integrate physics collisions impulses to solve collisions
for ( int i = 0 ; i < PHYSAC_COLLISION_ITERATIONS ; i + + )
{
for ( int j = 0 ; j < physicsManifoldsCount ; j + + )
{
PhysicsManifold manifold = contacts [ i ] ;
if ( manifold ! = NULL ) IntegratePhysicsImpulses ( manifold ) ;
}
}
// Integrate velocity to physics bodies
for ( int i = 0 ; i < physicsBodiesCount ; i + + )
{
PhysicsBody body = bodies [ i ] ;
if ( body ! = NULL ) IntegratePhysicsVelocity ( body ) ;
}
// Correct physics bodies positions based on manifolds collision information
for ( int i = 0 ; i < physicsManifoldsCount ; i + + )
{
PhysicsManifold manifold = contacts [ i ] ;
if ( manifold ! = NULL ) CorrectPhysicsPositions ( manifold ) ;
}
// Clear physics bodies forces
for ( int i = 0 ; i < physicsBodiesCount ; i + + )
{
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
}
}
}
2018-07-29 13:09:30 +02:00
// Wrapper to ensure PhysicsStep is run with at a fixed time step
PHYSACDEF void RunPhysicsStep ( void )
{
// Calculate current time
currentTime = GetCurrentTime ( ) ;
// Calculate current delta time
2018-09-23 13:55:39 +02:00
const double delta = currentTime - startTime ;
2018-07-29 13:09:30 +02:00
// Store the time elapsed since the last frame began
2018-09-23 13:55:39 +02:00
accumulator + = delta ;
2018-07-29 13:09:30 +02:00
// Fixed time stepping loop
2018-09-23 13:55:39 +02:00
while ( accumulator > = deltaTime )
2018-07-29 13:09:30 +02:00
{
2018-09-23 13:55:39 +02:00
# ifdef PHYSAC_DEBUG
//printf("currentTime %f, startTime %f, accumulator-pre %f, accumulator-post %f, delta %f, deltaTime %f\n",
// currentTime, startTime, accumulator, accumulator-deltaTime, delta, deltaTime);
# endif
2018-07-29 13:09:30 +02:00
PhysicsStep ( ) ;
accumulator - = deltaTime ;
}
// Record the starting of this frame
startTime = currentTime ;
}
2018-09-23 13:55:39 +02:00
PHYSACDEF void SetPhysicsTimeStep ( double delta )
{
deltaTime = delta ;
}
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
for ( int k = 0 ; k < physicsManifoldsCount ; k + + )
{
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 )
{
PhysicsManifold newManifold = ( PhysicsManifold ) PHYSAC_MALLOC ( sizeof ( PhysicsManifoldData ) ) ;
usedMemory + = sizeof ( PhysicsManifoldData ) ;
int newId = FindAvailableManifoldIndex ( ) ;
2016-11-21 20:30:46 +01:00
if ( newId ! = - 1 )
2017-04-16 19:08:34 +02:00
{
2016-11-21 20:30:46 +01:00
// Initialize new manifold with generic values
newManifold - > id = newId ;
newManifold - > bodyA = a ;
newManifold - > bodyB = b ;
newManifold - > penetration = 0 ;
2018-03-10 19:25:17 +01:00
newManifold - > normal = PHYSAC_VECTOR_ZERO ;
newManifold - > contacts [ 0 ] = PHYSAC_VECTOR_ZERO ;
newManifold - > contacts [ 1 ] = PHYSAC_VECTOR_ZERO ;
2016-11-21 20:30:46 +01:00
newManifold - > contactsCount = 0 ;
2018-03-10 19:25:17 +01:00
newManifold - > restitution = 0.0f ;
newManifold - > dynamicFriction = 0.0f ;
newManifold - > staticFriction = 0.0f ;
2016-11-21 20:30:46 +01:00
// Add new body to bodies pointers array and update bodies count
contacts [ physicsManifoldsCount ] = newManifold ;
physicsManifoldsCount + + ;
}
# if defined(PHYSAC_DEBUG)
else printf ( " [PHYSAC] new physics manifold creation failed because there is any available id to use \n " ) ;
# endif
return newManifold ;
}
// Unitializes and destroys a physics manifold
static void DestroyPhysicsManifold ( PhysicsManifold manifold )
{
if ( manifold ! = NULL )
{
int id = manifold - > id ;
int index = - 1 ;
for ( int i = 0 ; i < physicsManifoldsCount ; i + + )
{
if ( contacts [ i ] - > id = = id )
{
index = i ;
break ;
}
}
2019-10-29 16:03:21 +01:00
if ( index = = - 1 )
{
# if defined(PHYSAC_DEBUG)
printf ( " [PHYSAC] Not possible to manifold id %i in pointers array \n " , id ) ;
# endif
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
for ( int i = index ; i < physicsManifoldsCount ; i + + )
{
if ( ( i + 1 ) < physicsManifoldsCount ) contacts [ i ] = contacts [ i + 1 ] ;
}
// Update physics manifolds count
physicsManifoldsCount - - ;
}
# if defined(PHYSAC_DEBUG)
else printf ( " [PHYSAC] error trying to destroy a null referenced manifold \n " ) ;
# endif
}
// 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
Vector2 normal = Vector2Subtract ( bodyB - > position , bodyA - > position ) ;
float distSqr = MathLenSqr ( normal ) ;
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 ;
2018-03-10 19:25:17 +01:00
manifold - > normal = ( Vector2 ) { 1.0f , 0.0f } ;
2016-11-21 20:30:46 +01:00
manifold - > contacts [ 0 ] = bodyA - > position ;
}
else
{
manifold - > penetration = radius - distance ;
manifold - > normal = ( Vector2 ) { normal . x / distance , normal . y / distance } ; // Faster than using MathNormalize() due to sqrt is already performed
manifold - > contacts [ 0 ] = ( Vector2 ) { manifold - > normal . x * bodyA - > shape . radius + bodyA - > position . x , manifold - > normal . y * bodyA - > shape . radius + bodyA - > position . y } ;
}
// 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 ;
2018-03-10 19:25:17 +01:00
center = Mat2MultiplyVector2 ( Mat2Transpose ( bodyB - > shape . transform ) , Vector2Subtract ( 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 ;
PolygonData vertexData = bodyB - > shape . vertexData ;
for ( int i = 0 ; i < vertexData . vertexCount ; i + + )
{
2018-03-10 19:25:17 +01:00
float currentSeparation = MathDot ( vertexData . normals [ i ] , Vector2Subtract ( 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 ] ;
2016-11-21 20:30:46 +01:00
int nextIndex = ( ( ( faceNormal + 1 ) < 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 ;
2018-03-10 19:25:17 +01:00
Vector2 normal = Mat2MultiplyVector2 ( bodyB - > shape . transform , vertexData . normals [ faceNormal ] ) ;
2016-11-21 20:30:46 +01:00
manifold - > normal = ( Vector2 ) { - normal . x , - normal . y } ;
manifold - > contacts [ 0 ] = ( Vector2 ) { manifold - > normal . x * bodyA - > shape . radius + bodyA - > position . x , manifold - > normal . y * bodyA - > shape . radius + bodyA - > position . y } ;
manifold - > penetration = bodyA - > shape . radius ;
return ;
}
// Determine which voronoi region of the edge center of circle lies within
float dot1 = MathDot ( Vector2Subtract ( center , v1 ) , Vector2Subtract ( v2 , v1 ) ) ;
float dot2 = MathDot ( Vector2Subtract ( center , v2 ) , Vector2Subtract ( v1 , v2 ) ) ;
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
{
2016-11-21 20:30:46 +01:00
if ( DistSqr ( center , v1 ) > bodyA - > shape . radius * bodyA - > shape . radius ) return ;
manifold - > contactsCount = 1 ;
Vector2 normal = Vector2Subtract ( v1 , center ) ;
2018-03-10 19:25:17 +01:00
normal = Mat2MultiplyVector2 ( bodyB - > shape . transform , normal ) ;
2016-11-21 20:30:46 +01:00
MathNormalize ( & normal ) ;
manifold - > normal = normal ;
2018-03-10 19:25:17 +01:00
v1 = Mat2MultiplyVector2 ( bodyB - > shape . transform , v1 ) ;
2016-11-21 20:30:46 +01:00
v1 = Vector2Add ( v1 , bodyB - > position ) ;
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
{
if ( DistSqr ( center , v2 ) > bodyA - > shape . radius * bodyA - > shape . radius ) return ;
manifold - > contactsCount = 1 ;
Vector2 normal = Vector2Subtract ( v2 , center ) ;
2018-03-10 19:25:17 +01:00
v2 = Mat2MultiplyVector2 ( bodyB - > shape . transform , v2 ) ;
2016-11-21 20:30:46 +01:00
v2 = Vector2Add ( v2 , bodyB - > position ) ;
manifold - > contacts [ 0 ] = v2 ;
2018-03-10 19:25:17 +01:00
normal = Mat2MultiplyVector2 ( bodyB - > shape . transform , normal ) ;
2016-11-21 20:30:46 +01:00
MathNormalize ( & normal ) ;
manifold - > normal = normal ;
}
else // Closest to face
{
Vector2 normal = vertexData . normals [ faceNormal ] ;
if ( MathDot ( Vector2Subtract ( center , v1 ) , normal ) > bodyA - > shape . radius ) return ;
2018-03-10 19:25:17 +01:00
normal = Mat2MultiplyVector2 ( bodyB - > shape . transform , normal ) ;
2016-11-21 20:30:46 +01:00
manifold - > normal = ( Vector2 ) { - normal . x , - normal . y } ;
manifold - > contacts [ 0 ] = ( Vector2 ) { manifold - > normal . x * bodyA - > shape . radius + bodyA - > position . x , manifold - > normal . y * bodyA - > shape . radius + bodyA - > position . y } ;
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
if ( BiasGreaterThan ( penetrationA , penetrationB ) )
{
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
PolygonData refData = refPoly . vertexData ;
2018-03-10 19:25:17 +01:00
Vector2 v1 = refData . positions [ referenceIndex ] ;
2016-11-21 20:30:46 +01:00
referenceIndex = ( ( ( referenceIndex + 1 ) < 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
2018-03-10 19:25:17 +01:00
v1 = Mat2MultiplyVector2 ( refPoly . transform , v1 ) ;
2016-11-21 20:30:46 +01:00
v1 = Vector2Add ( v1 , refPoly . body - > position ) ;
2018-03-10 19:25:17 +01:00
v2 = Mat2MultiplyVector2 ( refPoly . transform , v2 ) ;
2016-11-21 20:30:46 +01:00
v2 = Vector2Add ( v2 , refPoly . body - > position ) ;
// Calculate reference face side normal in world space
Vector2 sidePlaneNormal = Vector2Subtract ( v2 , v1 ) ;
MathNormalize ( & sidePlaneNormal ) ;
// Orthogonalize
Vector2 refFaceNormal = { sidePlaneNormal . y , - sidePlaneNormal . x } ;
float refC = MathDot ( refFaceNormal , v1 ) ;
float negSide = MathDot ( sidePlaneNormal , v1 ) * - 1 ;
float posSide = MathDot ( sidePlaneNormal , v2 ) ;
// Clip incident face to reference face side planes (due to floating point error, possible to not have required points
if ( Clip ( ( Vector2 ) { - sidePlaneNormal . x , - sidePlaneNormal . y } , negSide , & incidentFace [ 0 ] , & incidentFace [ 1 ] ) < 2 ) return ;
if ( Clip ( sidePlaneNormal , posSide , & incidentFace [ 0 ] , & incidentFace [ 1 ] ) < 2 ) return ;
// Flip normal if required
manifold - > normal = ( flip ? ( Vector2 ) { - refFaceNormal . x , - refFaceNormal . y } : refFaceNormal ) ;
// Keep points behind reference face
int currentPoint = 0 ; // Clipped points behind reference face
float separation = MathDot ( 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
separation = MathDot ( refFaceNormal , incidentFace [ 1 ] ) - 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 [ 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
2018-03-10 19:25:17 +01:00
body - > velocity . x + = ( body - > force . x * body - > inverseMass ) * ( deltaTime / 2.0 ) ;
body - > velocity . y + = ( body - > force . y * body - > inverseMass ) * ( deltaTime / 2.0 ) ;
2016-11-21 20:30:46 +01:00
if ( body - > useGravity )
{
2018-09-23 13:55:39 +02:00
body - > velocity . x + = gravityForce . x * ( deltaTime / 1000 / 2.0 ) ;
body - > velocity . y + = gravityForce . y * ( deltaTime / 1000 / 2.0 ) ;
2016-11-21 20:30:46 +01:00
}
2018-03-10 19:25:17 +01:00
if ( ! body - > freezeOrient ) body - > angularVelocity + = 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 ) ;
2018-03-10 19:25:17 +01:00
for ( int i = 0 ; i < manifold - > contactsCount ; i + + )
2016-11-21 20:30:46 +01:00
{
// Caculate radius from center of mass to contact
Vector2 radiusA = Vector2Subtract ( manifold - > contacts [ i ] , bodyA - > position ) ;
Vector2 radiusB = Vector2Subtract ( manifold - > contacts [ i ] , bodyB - > position ) ;
Vector2 crossA = MathCross ( bodyA - > angularVelocity , radiusA ) ;
Vector2 crossB = MathCross ( bodyB - > angularVelocity , radiusB ) ;
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
2018-09-23 13:55:39 +02:00
if ( MathLenSqr ( radiusV ) < ( MathLenSqr ( ( Vector2 ) { gravityForce . x * deltaTime / 1000 , 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 ;
}
for ( int i = 0 ; i < manifold - > contactsCount ; i + + )
{
// Calculate radius from center of mass to contact
Vector2 radiusA = Vector2Subtract ( manifold - > contacts [ i ] , bodyA - > position ) ;
Vector2 radiusB = Vector2Subtract ( manifold - > contacts [ i ] , bodyB - > position ) ;
// Calculate relative velocity
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 + MathCross ( bodyB - > angularVelocity , radiusB ) . x - bodyA - > velocity . x - MathCross ( bodyA - > angularVelocity , radiusA ) . x ;
radiusV . y = bodyB - > velocity . y + MathCross ( bodyB - > angularVelocity , radiusB ) . y - bodyA - > velocity . y - MathCross ( bodyA - > angularVelocity , radiusA ) . y ;
// Relative velocity along the normal
float contactVelocity = MathDot ( radiusV , manifold - > normal ) ;
// 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
float raCrossN = MathCrossVector2 ( radiusA , manifold - > normal ) ;
float rbCrossN = MathCrossVector2 ( radiusB , manifold - > normal ) ;
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 ) ;
if ( ! bodyA - > freezeOrient ) bodyA - > angularVelocity + = bodyA - > inverseInertia * MathCrossVector2 ( radiusA , ( Vector2 ) { - impulseV . x , - impulseV . y } ) ;
}
if ( bodyB - > enabled )
{
bodyB - > velocity . x + = bodyB - > inverseMass * ( impulseV . x ) ;
bodyB - > velocity . y + = bodyB - > inverseMass * ( impulseV . y ) ;
if ( ! bodyB - > freezeOrient ) bodyB - > angularVelocity + = bodyB - > inverseInertia * MathCrossVector2 ( radiusB , impulseV ) ;
}
// Apply friction impulse to each physics body
radiusV . x = bodyB - > velocity . x + MathCross ( bodyB - > angularVelocity , radiusB ) . x - bodyA - > velocity . x - MathCross ( bodyA - > angularVelocity , radiusA ) . x ;
radiusV . y = bodyB - > velocity . y + MathCross ( bodyB - > angularVelocity , radiusB ) . y - bodyA - > velocity . y - MathCross ( bodyA - > angularVelocity , radiusA ) . y ;
Vector2 tangent = { radiusV . x - ( manifold - > normal . x * MathDot ( radiusV , manifold - > normal ) ) , radiusV . y - ( manifold - > normal . y * MathDot ( radiusV , manifold - > normal ) ) } ;
MathNormalize ( & tangent ) ;
// Calculate impulse tangent magnitude
float impulseTangent = - MathDot ( radiusV , tangent ) ;
impulseTangent / = inverseMassSum ;
impulseTangent / = ( float ) manifold - > contactsCount ;
float absImpulseTangent = fabs ( impulseTangent ) ;
// 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 } ;
2016-11-21 20:30:46 +01:00
if ( absImpulseTangent < impulse * manifold - > staticFriction ) tangentImpulse = ( Vector2 ) { tangent . x * impulseTangent , tangent . y * impulseTangent } ;
else tangentImpulse = ( Vector2 ) { tangent . x * - impulse * manifold - > dynamicFriction , tangent . y * - impulse * manifold - > dynamicFriction } ;
// Apply friction impulse
if ( bodyA - > enabled )
{
bodyA - > velocity . x + = bodyA - > inverseMass * ( - tangentImpulse . x ) ;
bodyA - > velocity . y + = bodyA - > inverseMass * ( - tangentImpulse . y ) ;
if ( ! bodyA - > freezeOrient ) bodyA - > angularVelocity + = bodyA - > inverseInertia * MathCrossVector2 ( radiusA , ( Vector2 ) { - tangentImpulse . x , - tangentImpulse . y } ) ;
}
if ( bodyB - > enabled )
{
bodyB - > velocity . x + = bodyB - > inverseMass * ( tangentImpulse . x ) ;
bodyB - > velocity . y + = bodyB - > inverseMass * ( tangentImpulse . y ) ;
if ( ! bodyB - > freezeOrient ) bodyB - > angularVelocity + = bodyB - > inverseInertia * MathCrossVector2 ( radiusB , tangentImpulse ) ;
}
}
}
// 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
body - > position . x + = body - > velocity . x * deltaTime ;
body - > position . y + = body - > velocity . y * deltaTime ;
if ( ! body - > freezeOrient ) body - > orient + = body - > angularVelocity * deltaTime ;
2018-03-10 19:25:17 +01:00
Mat2Set ( & body - > shape . transform , 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 } ;
correction . x = ( max ( manifold - > penetration - PHYSAC_PENETRATION_ALLOWANCE , 0.0f ) / ( bodyA - > inverseMass + bodyB - > inverseMass ) ) * manifold - > normal . x * PHYSAC_PENETRATION_CORRECTION ;
correction . y = ( 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 } ;
2016-11-21 20:30:46 +01:00
PolygonData data = shape . vertexData ;
for ( int i = 0 ; i < data . vertexCount ; i + + )
{
2018-03-10 19:25:17 +01:00
Vector2 vertex = data . positions [ i ] ;
2016-11-21 20:30:46 +01:00
float projection = MathDot ( vertex , dir ) ;
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 ;
PolygonData dataA = shapeA . vertexData ;
2019-05-20 16:37:44 +02:00
//PolygonData dataB = shapeB.vertexData;
2016-11-21 20:30:46 +01:00
for ( int i = 0 ; i < dataA . vertexCount ; i + + )
{
// Retrieve a face normal from A shape
Vector2 normal = dataA . normals [ i ] ;
2018-03-10 19:25:17 +01:00
Vector2 transNormal = Mat2MultiplyVector2 ( shapeA . transform , normal ) ;
2016-11-21 20:30:46 +01:00
// Transform face normal into B shape's model space
2018-03-10 19:25:17 +01:00
Mat2 buT = Mat2Transpose ( shapeB . transform ) ;
2016-11-21 20:30:46 +01:00
normal = Mat2MultiplyVector2 ( buT , transNormal ) ;
// Retrieve support point from B shape along -n
Vector2 support = GetSupport ( shapeB , ( Vector2 ) { - normal . x , - normal . y } ) ;
// 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 ] ;
vertex = Mat2MultiplyVector2 ( shapeA . transform , vertex ) ;
2016-11-21 20:30:46 +01:00
vertex = Vector2Add ( vertex , shapeA . body - > position ) ;
vertex = Vector2Subtract ( vertex , shapeB . body - > position ) ;
vertex = Mat2MultiplyVector2 ( buT , vertex ) ;
// Compute penetration distance in B shape's model space
float distance = MathDot ( normal , Vector2Subtract ( support , vertex ) ) ;
// 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 )
{
PolygonData refData = ref . vertexData ;
PolygonData incData = inc . vertexData ;
Vector2 referenceNormal = refData . normals [ index ] ;
// Calculate normal in incident's frame of reference
2018-03-10 19:25:17 +01:00
referenceNormal = Mat2MultiplyVector2 ( ref . transform , referenceNormal ) ; // To world space
referenceNormal = Mat2MultiplyVector2 ( Mat2Transpose ( 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 ;
for ( int i = 0 ; i < incData . vertexCount ; i + + )
{
float dot = MathDot ( referenceNormal , incData . normals [ i ] ) ;
if ( dot < minDot )
{
minDot = dot ;
incidentFace = i ;
}
}
// Assign face vertices for incident face
2018-03-10 19:25:17 +01:00
* v0 = Mat2MultiplyVector2 ( inc . transform , incData . positions [ incidentFace ] ) ;
2016-11-21 20:30:46 +01:00
* v0 = Vector2Add ( * v0 , inc . body - > position ) ;
incidentFace = ( ( ( incidentFace + 1 ) < incData . vertexCount ) ? ( incidentFace + 1 ) : 0 ) ;
2018-03-10 19:25:17 +01:00
* v1 = Mat2MultiplyVector2 ( inc . transform , incData . positions [ incidentFace ] ) ;
2016-11-21 20:30:46 +01:00
* v1 = Vector2Add ( * v1 , inc . body - > position ) ;
}
// Calculates clipping based on a normal and two faces
static int Clip ( Vector2 normal , float clip , Vector2 * faceA , Vector2 * faceB )
{
int sp = 0 ;
Vector2 out [ 2 ] = { * faceA , * faceB } ;
// Retrieve distances from each endpoint to the line
float distanceA = MathDot ( normal , * faceA ) - clip ;
float distanceB = MathDot ( normal , * faceB ) - clip ;
// 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 ;
Vector2 delta = Vector2Subtract ( * faceB , * faceA ) ;
delta . x * = alpha ;
delta . y * = alpha ;
out [ sp ] = Vector2Add ( out [ sp ] , delta ) ;
sp + + ;
}
// Assign the new converted values
* faceA = out [ 0 ] ;
* faceB = out [ 1 ] ;
return sp ;
}
// Check if values are between bias range
static bool BiasGreaterThan ( float valueA , float valueB )
{
return ( valueA > = ( valueB * 0.95f + valueA * 0.01f ) ) ;
}
// Returns the barycenter of a triangle given by 3 points
static Vector2 TriangleBarycenter ( Vector2 v1 , Vector2 v2 , Vector2 v3 )
{
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 ;
}
2017-12-24 15:59:03 +01:00
// Initializes hi-resolution MONOTONIC timer
2016-11-21 20:30:46 +01:00
static void InitTimer ( void )
{
srand ( time ( NULL ) ) ; // Initialize random seed
2019-10-17 17:18:03 +02:00
2017-12-24 15:59:03 +01:00
# if defined(_WIN32)
QueryPerformanceFrequency ( ( unsigned long long int * ) & frequency ) ;
# endif
2016-11-21 20:30:46 +01:00
2017-12-24 15:59:03 +01:00
# if defined(__linux__)
struct timespec now ;
if ( clock_gettime ( CLOCK_MONOTONIC , & now ) = = 0 ) frequency = 1000000000 ;
# endif
2016-11-21 20:30:46 +01:00
2017-12-24 15:59:03 +01:00
# if defined(__APPLE__)
mach_timebase_info_data_t timebase ;
mach_timebase_info ( & timebase ) ;
frequency = ( timebase . denom * 1e9 ) / timebase . numer ;
# endif
2019-10-17 17:18:03 +02:00
2017-12-24 15:59:03 +01:00
baseTime = GetTimeCount ( ) ; // Get MONOTONIC clock time offset
startTime = GetCurrentTime ( ) ; // Get current time
2016-11-21 20:30:46 +01:00
}
2017-12-24 15:59:03 +01:00
// Get hi-res MONOTONIC time measure in seconds
static uint64_t GetTimeCount ( void )
2016-11-21 20:30:46 +01:00
{
2019-05-20 16:37:44 +02:00
uint64_t value = 0 ;
2019-10-17 17:18:03 +02:00
2017-12-24 15:59:03 +01:00
# if defined(_WIN32)
QueryPerformanceCounter ( ( unsigned long long int * ) & value ) ;
# endif
2016-11-21 20:30:46 +01:00
2017-12-24 15:59:03 +01:00
# if defined(__linux__)
struct timespec now ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
value = ( uint64_t ) now . tv_sec * ( uint64_t ) 1000000000 + ( uint64_t ) now . tv_nsec ;
# endif
2016-11-21 20:30:46 +01:00
2017-12-24 15:59:03 +01:00
# if defined(__APPLE__)
value = mach_absolute_time ( ) ;
# endif
2016-11-21 20:30:46 +01:00
2017-12-24 15:59:03 +01:00
return value ;
}
2016-11-21 20:30:46 +01:00
2017-12-24 15:59:03 +01:00
// Get current time in milliseconds
static double GetCurrentTime ( void )
{
return ( double ) ( GetTimeCount ( ) - baseTime ) / frequency * 1000 ;
2016-11-21 20:30:46 +01:00
}
// Returns the cross product of a vector and a value
static inline Vector2 MathCross ( float value , Vector2 vector )
{
return ( Vector2 ) { - value * vector . y , value * vector . x } ;
}
// Returns the cross product of two vectors
static inline float MathCrossVector2 ( Vector2 v1 , Vector2 v2 )
{
return ( v1 . x * v2 . y - v1 . y * v2 . x ) ;
}
// Returns the len square root of a vector
static inline float MathLenSqr ( Vector2 vector )
{
return ( vector . x * vector . x + vector . y * vector . y ) ;
}
// Returns the dot product of two vectors
static inline float MathDot ( Vector2 v1 , Vector2 v2 )
{
return ( v1 . x * v2 . x + v1 . y * v2 . y ) ;
}
// Returns the square root of distance between two vectors
static inline float DistSqr ( Vector2 v1 , Vector2 v2 )
{
Vector2 dir = Vector2Subtract ( v1 , v2 ) ;
return MathDot ( dir , dir ) ;
}
// Returns the normalized values of a vector
static void MathNormalize ( Vector2 * vector )
{
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 ;
}
2017-05-11 17:22:25 +02:00
# if defined(PHYSAC_STANDALONE)
2016-11-21 20:30:46 +01:00
// Returns the sum of two given vectors
static inline Vector2 Vector2Add ( Vector2 v1 , Vector2 v2 )
{
return ( Vector2 ) { v1 . x + v2 . x , v1 . y + v2 . y } ;
}
// Returns the subtract of two given vectors
static inline Vector2 Vector2Subtract ( Vector2 v1 , Vector2 v2 )
{
return ( Vector2 ) { v1 . x - v2 . x , v1 . y - v2 . y } ;
2017-12-24 15:59:03 +01:00
}
2017-05-11 17:22:25 +02:00
# endif
2016-11-21 20:30:46 +01:00
// Creates a matrix 2x2 from a given radians value
2018-03-10 19:25:17 +01:00
static Mat2 Mat2Radians ( float radians )
2016-11-21 20:30:46 +01:00
{
float c = cosf ( radians ) ;
float s = sinf ( radians ) ;
return ( Mat2 ) { c , - s , s , c } ;
}
// Set values from radians to a created matrix 2x2
static void Mat2Set ( Mat2 * matrix , float radians )
{
float cos = cosf ( radians ) ;
float sin = sinf ( radians ) ;
matrix - > m00 = cos ;
matrix - > m01 = - sin ;
matrix - > m10 = sin ;
matrix - > m11 = cos ;
}
// Returns the transpose of a given matrix 2x2
static inline Mat2 Mat2Transpose ( Mat2 matrix )
{
return ( Mat2 ) { matrix . m00 , matrix . m10 , matrix . m01 , matrix . m11 } ;
}
// Multiplies a vector by a matrix 2x2
static inline Vector2 Mat2MultiplyVector2 ( Mat2 matrix , Vector2 vector )
{
return ( Vector2 ) { matrix . m00 * vector . x + matrix . m01 * vector . y , matrix . m10 * vector . x + matrix . m11 * vector . y } ;
2016-06-09 20:01:59 +02:00
}
2018-07-29 13:09:30 +02:00
# endif // PHYSAC_IMPLEMENTATION