From 677f420bf00d346b8b5a84ac17beaf70111dbf2b Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 20 Jan 2021 20:55:12 +0100 Subject: [PATCH] REVIEWED: physac module and examples #1525 --- examples/physics/physics_demo.c | 34 +- examples/physics/physics_friction.c | 21 +- examples/physics/physics_movement.c | 21 +- examples/physics/physics_restitution.c | 22 +- examples/physics/physics_shatter.c | 38 +- src/physac.h | 1065 +++++++++++------------- 6 files changed, 535 insertions(+), 666 deletions(-) diff --git a/examples/physics/physics_demo.c b/examples/physics/physics_demo.c index 421c82a90..9763bf990 100644 --- a/examples/physics/physics_demo.c +++ b/examples/physics/physics_demo.c @@ -1,24 +1,19 @@ /******************************************************************************************* * -* Physac - Physics demo +* raylib [physac] example - physics demo * -* 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) +* This example has been created using raylib 1.5 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Use the following line to compile: +* This example uses physac 1.1 (https://github.com/raysan5/raylib/blob/master/src/physac.h) * -* gcc -o $(NAME_PART).exe $(FILE_NAME) -s -static / -* -lraylib -lpthread -lglfw3 -lopengl32 -lgdi32 -lopenal32 -lwinmm / -* -std=c99 -Wl,--subsystem,windows -Wl,-allow-multiple-definition -* -* Copyright (c) 2016-2018 Victor Fisac +* Copyright (c) 2016-2021 Victor Fisac (@victorfisac) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ #include "raylib.h" #define PHYSAC_IMPLEMENTATION -#define PHYSAC_NO_THREADS #include "physac.h" int main(void) @@ -29,12 +24,11 @@ int main(void) const int screenHeight = 450; SetConfigFlags(FLAG_MSAA_4X_HINT); - InitWindow(screenWidth, screenHeight, "Physac [raylib] - Physics demo"); + InitWindow(screenWidth, screenHeight, "raylib [physac] example - physics demo"); // Physac logo drawing position int logoX = screenWidth - MeasureText("Physac", 30) - 10; int logoY = 15; - bool needsReset = false; // Initialize physics and default physics bodies InitPhysics(); @@ -55,25 +49,17 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - // Delay initialization of variables due to physics reset async - RunPhysicsStep(); + UpdatePhysics(); // Update physics system - if (needsReset) + if (IsKeyPressed('R')) // Reset physics system { + ResetPhysics(); + floor = CreatePhysicsBodyRectangle((Vector2){ screenWidth/2, screenHeight }, 500, 100, 10); floor->enabled = false; circle = CreatePhysicsBodyCircle((Vector2){ screenWidth/2, screenHeight/2 }, 45, 10); circle->enabled = false; - - needsReset = false; - } - - // Reset physics input - if (IsKeyPressed('R')) - { - ResetPhysics(); - needsReset = true; } // Physics body creation inputs diff --git a/examples/physics/physics_friction.c b/examples/physics/physics_friction.c index 0acf88aea..b91950391 100644 --- a/examples/physics/physics_friction.c +++ b/examples/physics/physics_friction.c @@ -1,24 +1,19 @@ /******************************************************************************************* * -* Physac - Physics friction +* raylib [physac] example - physics friction * -* 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) +* This example has been created using raylib 1.5 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Use the following line to compile: +* This example uses physac 1.1 (https://github.com/raysan5/raylib/blob/master/src/physac.h) * -* gcc -o $(NAME_PART).exe $(FILE_NAME) -s -static / -* -lraylib -lpthread -lglfw3 -lopengl32 -lgdi32 -lopenal32 -lwinmm / -* -std=c99 -Wl,--subsystem,windows -Wl,-allow-multiple-definition -* -* Copyright (c) 2016-2018 Victor Fisac +* Copyright (c) 2016-2021 Victor Fisac (@victorfisac) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ #include "raylib.h" #define PHYSAC_IMPLEMENTATION -#define PHYSAC_NO_THREADS #include "physac.h" int main(void) @@ -29,7 +24,7 @@ int main(void) const int screenHeight = 450; SetConfigFlags(FLAG_MSAA_4X_HINT); - InitWindow(screenWidth, screenHeight, "Physac [raylib] - Physics friction"); + InitWindow(screenWidth, screenHeight, "raylib [physac] example - physics friction"); // Physac logo drawing position int logoX = screenWidth - MeasureText("Physac", 30) - 10; @@ -73,9 +68,9 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - RunPhysicsStep(); + UpdatePhysics(); // Update physics system - if (IsKeyPressed('R')) // Reset physics input + if (IsKeyPressed('R')) // Reset physics system { // Reset dynamic physics bodies position, velocity and rotation bodyA->position = (Vector2){ 35, screenHeight*0.6f }; diff --git a/examples/physics/physics_movement.c b/examples/physics/physics_movement.c index d946811d1..73a1f9277 100644 --- a/examples/physics/physics_movement.c +++ b/examples/physics/physics_movement.c @@ -1,24 +1,19 @@ /******************************************************************************************* * -* Physac - Physics movement +* raylib [physac] example - physics movement * -* 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) +* This example has been created using raylib 1.5 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Use the following line to compile: +* This example uses physac 1.1 (https://github.com/raysan5/raylib/blob/master/src/physac.h) * -* gcc -o $(NAME_PART).exe $(FILE_NAME) -s -static / -* -lraylib -lpthread -lglfw3 -lopengl32 -lgdi32 -lopenal32 -lwinmm / -* -std=c99 -Wl,--subsystem,windows -Wl,-allow-multiple-definition -* -* Copyright (c) 2016-2018 Victor Fisac +* Copyright (c) 2016-2021 Victor Fisac (@victorfisac) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ #include "raylib.h" #define PHYSAC_IMPLEMENTATION -#define PHYSAC_NO_THREADS #include "physac.h" #define VELOCITY 0.5f @@ -31,7 +26,7 @@ int main(void) const int screenHeight = 450; SetConfigFlags(FLAG_MSAA_4X_HINT); - InitWindow(screenWidth, screenHeight, "Physac [raylib] - Physics movement"); + InitWindow(screenWidth, screenHeight, "raylib [physac] example - physics movement"); // Physac logo drawing position int logoX = screenWidth - MeasureText("Physac", 30) - 10; @@ -66,9 +61,9 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - RunPhysicsStep(); + UpdatePhysics(); // Update physics system - if (IsKeyPressed('R')) // Reset physics input + if (IsKeyPressed('R')) // Reset physics input { // Reset movement physics body position, velocity and rotation body->position = (Vector2){ screenWidth/2, screenHeight/2 }; diff --git a/examples/physics/physics_restitution.c b/examples/physics/physics_restitution.c index 12a2a9220..787db98d9 100644 --- a/examples/physics/physics_restitution.c +++ b/examples/physics/physics_restitution.c @@ -1,24 +1,19 @@ /******************************************************************************************* * -* Physac - Physics restitution +* raylib [physac] example - physics restitution * -* 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) +* This example has been created using raylib 1.5 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Use the following line to compile: +* This example uses physac 1.1 (https://github.com/raysan5/raylib/blob/master/src/physac.h) * -* gcc -o $(NAME_PART).exe $(FILE_NAME) -s -static / -* -lraylib -lpthread -lglfw3 -lopengl32 -lgdi32 -lopenal32 -lwinmm / -* -std=c99 -Wl,--subsystem,windows -Wl,-allow-multiple-definition -* -* Copyright (c) 2016-2018 Victor Fisac +* Copyright (c) 2016-2021 Victor Fisac (@victorfisac) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ #include "raylib.h" #define PHYSAC_IMPLEMENTATION -#define PHYSAC_NO_THREADS #include "physac.h" int main(void) @@ -29,7 +24,7 @@ int main(void) const int screenHeight = 450; SetConfigFlags(FLAG_MSAA_4X_HINT); - InitWindow(screenWidth, screenHeight, "Physac [raylib] - Physics restitution"); + InitWindow(screenWidth, screenHeight, "raylib [physac] example - physics restitution"); // Physac logo drawing position int logoX = screenWidth - MeasureText("Physac", 30) - 10; @@ -62,9 +57,9 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - RunPhysicsStep(); + UpdatePhysics(); // Update physics system - if (IsKeyPressed('R')) // Reset physics input + if (IsKeyPressed('R')) // Reset physics input { // Reset circles physics bodies position and velocity circleA->position = (Vector2){ screenWidth*0.25f, screenHeight/2 }; @@ -124,6 +119,7 @@ int main(void) DestroyPhysicsBody(circleB); DestroyPhysicsBody(circleC); DestroyPhysicsBody(floor); + ClosePhysics(); // Unitialize physics CloseWindow(); // Close window and OpenGL context diff --git a/examples/physics/physics_shatter.c b/examples/physics/physics_shatter.c index cbc65221d..46876ff7c 100644 --- a/examples/physics/physics_shatter.c +++ b/examples/physics/physics_shatter.c @@ -1,24 +1,19 @@ /******************************************************************************************* * -* Physac - Body shatter +* raylib [physac] example - physics shatter * -* 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) +* This example has been created using raylib 1.5 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Use the following line to compile: +* This example uses physac 1.1 (https://github.com/raysan5/raylib/blob/master/src/physac.h) * -* gcc -o $(NAME_PART).exe $(FILE_NAME) -s -static / -* -lraylib -lpthread -lglfw3 -lopengl32 -lgdi32 -lopenal32 -lwinmm / -* -std=c99 -Wl,--subsystem,windows -Wl,-allow-multiple-definition -* -* Copyright (c) 2016-2018 Victor Fisac +* Copyright (c) 2016-2021 Victor Fisac (@victorfisac) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ #include "raylib.h" #define PHYSAC_IMPLEMENTATION -#define PHYSAC_NO_THREADS #include "physac.h" int main(void) @@ -29,12 +24,11 @@ int main(void) const int screenHeight = 450; SetConfigFlags(FLAG_MSAA_4X_HINT); - InitWindow(screenWidth, screenHeight, "Physac [raylib] - Body shatter"); + InitWindow(screenWidth, screenHeight, "raylib [physac] example - physics shatter"); // Physac logo drawing position int logoX = screenWidth - MeasureText("Physac", 30) - 10; int logoY = 15; - bool needsReset = false; // Initialize physics and default physics bodies InitPhysics(); @@ -49,31 +43,23 @@ int main(void) // Main game loop while (!WindowShouldClose()) // Detect window close button or ESC key { - // Update - RunPhysicsStep(); - //---------------------------------------------------------------------------------- - // Delay initialization of variables due to physics reset asynchronous - if (needsReset) - { - // Create random polygon physics body to shatter - CreatePhysicsBodyPolygon((Vector2){ screenWidth/2, screenHeight/2 }, GetRandomValue(80, 200), GetRandomValue(3, 8), 10); - needsReset = false; - } - - if (IsKeyPressed('R')) // Reset physics input + UpdatePhysics(); // Update physics system + + if (IsKeyPressed('R')) // Reset physics input { ResetPhysics(); - needsReset = true; + + CreatePhysicsBodyPolygon((Vector2){ screenWidth/2, screenHeight/2 }, GetRandomValue(80, 200), GetRandomValue(3, 8), 10); } if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) // Physics shatter input { - // Note: some values need to be stored in variables due to asynchronous changes during main thread int count = GetPhysicsBodiesCount(); for (int i = count - 1; i >= 0; i--) { PhysicsBody currentBody = GetPhysicsBody(i); + if (currentBody != NULL) PhysicsShatter(currentBody, GetMousePosition(), 10/currentBody->inverseMass); } } diff --git a/src/physac.h b/src/physac.h index c3898d2fc..695e399d4 100644 --- a/src/physac.h +++ b/src/physac.h @@ -1,6 +1,6 @@ /********************************************************************************************** * -* Physac v1.0 - 2D Physics library for videogames +* Physac v1.1 - 2D Physics library for videogames * * DESCRIPTION: * @@ -20,38 +20,44 @@ * The generated implementation will stay private inside implementation file and all * internal symbols and functions will only be visible inside that file. * -* #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. -* -* #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). -* * #define PHYSAC_DEBUG -* Traces log messages when creating and destroying physics bodies and detects errors in physics -* calculations and reference exceptions; it is useful for debug purposes +* Show debug traces log messages about physic bodies creation/destruction, physic system errors, +* some calculations results and NULL reference exceptions +* +* #define PHYSAC_DEFINE_VECTOR2_TYPE +* Forces library to define struct Vector2 data type (float x; float y) +* +* #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. * * #define PHYSAC_MALLOC() +* #define PHYSAC_CALLOC() * #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. * +* COMPILATION: * -* 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) +* Use the following code to compile with GCC: +* gcc -o $(NAME_PART).exe $(FILE_NAME) -s -static -lraylib -lopengl32 -lgdi32 -lwinmm -std=c99 * -* Use the following code to compile: -* gcc -o $(NAME_PART).exe $(FILE_NAME) -s -static -lraylib -lpthread -lopengl32 -lgdi32 -lwinmm -std=c99 -* -* VERY THANKS TO: -* Ramon Santamaria (github: @raysan5) +* 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 * * * LICENSE: zlib/libpng * -* Copyright (c) 2016-2018 Victor Fisac (github: @victorfisac) +* Copyright (c) 2016-2021 Victor Fisac (@victorfisac) and Ramon Santamaria (@raysan5) * * 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. @@ -87,6 +93,9 @@ #ifndef PHYSAC_MALLOC #define PHYSAC_MALLOC(size) malloc(size) #endif +#ifndef PHYSAC_CALLOC + #define PHYSAC_CALLOC(size, n) calloc(size, n) +#endif #ifndef PHYSAC_FREE #define PHYSAC_FREE(ptr) free(ptr) #endif @@ -94,10 +103,10 @@ //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#define PHYSAC_MAX_BODIES 64 -#define PHYSAC_MAX_MANIFOLDS 4096 -#define PHYSAC_MAX_VERTICES 24 -#define PHYSAC_CIRCLE_VERTICES 24 +#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 #define PHYSAC_COLLISION_ITERATIONS 100 #define PHYSAC_PENETRATION_ALLOWANCE 0.05f @@ -106,34 +115,28 @@ #define PHYSAC_PI 3.14159265358979323846 #define PHYSAC_DEG2RAD (PHYSAC_PI/180.0f) -//---------------------------------------------------------------------------------- -// Types and Structures Definition -// NOTE: Below types are required for PHYSAC_STANDALONE usage -//---------------------------------------------------------------------------------- -#if defined(PHYSAC_STANDALONE) - // Boolean type - #if defined(__STDC__) && __STDC_VERSION__ >= 199901L - #include - #elif !defined(__cplusplus) && !defined(bool) - typedef enum { false, true } bool; - #endif - - // Vector2 type - typedef struct Vector2 { - float x; - float y; - } Vector2; -#endif - //---------------------------------------------------------------------------------- // Data Types Structure Definition //---------------------------------------------------------------------------------- +#if defined(__STDC__) && __STDC_VERSION__ >= 199901L + #include +#elif !defined(__cplusplus) && !defined(bool) + typedef enum { false, true } bool; +#endif -typedef enum PhysicsShapeType { PHYSICS_CIRCLE, PHYSICS_POLYGON } PhysicsShapeType; +typedef enum PhysicsShapeType { PHYSICS_CIRCLE = 0, PHYSICS_POLYGON } PhysicsShapeType; // Previously defined to be used in PhysicsShape struct as circular dependencies typedef struct PhysicsBodyData *PhysicsBody; +#if defined(PHYSAC_DEFINE_VECTOR2_TYPE) +// Vector2 type +typedef struct Vector2 { + float x; + float y; +} Vector2; +#endif + // Matrix2x2 type (used for polygon shape rotation matrix) typedef struct Matrix2x2 { float m00; @@ -142,22 +145,22 @@ typedef struct Matrix2x2 { float m11; } Matrix2x2; -typedef struct PolygonData { - unsigned int vertexCount; // Current used vertex and normals count - Vector2 positions[PHYSAC_MAX_VERTICES]; // Polygon vertex positions vectors - Vector2 normals[PHYSAC_MAX_VERTICES]; // Polygon vertex normals vectors -} PolygonData; +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; 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) + 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) Matrix2x2 transform; // Vertices transform matrix 2x2 - PolygonData vertexData; // Polygon shape vertices position and normals data (just used for polygon shapes) } PhysicsShape; typedef struct PhysicsBodyData { - unsigned int id; // Reference unique identifier + unsigned int id; // 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 @@ -175,11 +178,11 @@ typedef struct PhysicsBodyData { 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) + PhysicsShape shape; // Physics body shape information (type, radius, vertices, transform) } PhysicsBodyData; typedef struct PhysicsManifoldData { - unsigned int id; // Reference unique identifier + unsigned int id; // Unique identifier PhysicsBody bodyA; // Manifold first physics body reference PhysicsBody bodyB; // Manifold second physics body reference float penetration; // Depth of penetration from collision @@ -198,26 +201,32 @@ extern "C" { // Prevents name mangling of fun //---------------------------------------------------------------------------------- // Module Functions Declaration //---------------------------------------------------------------------------------- -PHYSACDEF void InitPhysics(void); // Initializes physics values, pointers and creates physics loop thread -PHYSACDEF void RunPhysicsStep(void); // Run physics step, to be used if PHYSICS_NO_THREADS is set in your main loop +// 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 PHYSACDEF void SetPhysicsTimeStep(double delta); // Sets physics fixed time step in milliseconds. 1.666666 by default -PHYSACDEF bool IsPhysicsEnabled(void); // Returns true if physics thread is currently enabled PHYSACDEF void SetPhysicsGravity(float x, float y); // Sets physics global gravity force + +// Physic body creation/destroy 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 DestroyPhysicsBody(PhysicsBody body); // Destroy a physics body + +// Physic body forces 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 void SetPhysicsBodyRotation(PhysicsBody body, float radians); // Sets physics body shape transform based on radians parameter + +// Query physics info PHYSACDEF PhysicsBody GetPhysicsBody(int index); // Returns a physics body of the bodies pool at a specific index +PHYSACDEF int GetPhysicsBodiesCount(void); // Returns the current amount of created physics bodies 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 #if defined(__cplusplus) } @@ -233,151 +242,138 @@ PHYSACDEF void ClosePhysics(void); #if defined(PHYSAC_IMPLEMENTATION) -#if !defined(PHYSAC_NO_THREADS) - #include // Required for: pthread_t, pthread_create() -#endif - -#if defined(PHYSAC_DEBUG) - -#endif - // Support TRACELOG macros #if defined(PHYSAC_DEBUG) #include // Required for: printf() #define TRACELOG(...) printf(__VA_ARGS__) #else - #define TRACELOG(...) (void)0 + #define TRACELOG(...) (void)0; #endif -#include // Required for: malloc(), free(), srand(), rand() +#include // Required for: malloc(), calloc(), free() #include // Required for: cosf(), sinf(), fabs(), sqrtf() -#if !defined(PHYSAC_STANDALONE) - #include "raymath.h" // Required for: Vector2Add(), Vector2Subtract() +#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) + // Time management functionality + #include // Required for: time(), clock_gettime() + #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 // Required for: timespec + #elif defined(__APPLE__) // macOS also defines __MACH__ + #include // Required for: mach_absolute_time() + #endif #endif -// Time management functionality -#include // Required for: time(), clock_gettime() -#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 // Required for: timespec -#elif defined(__APPLE__) // macOS also defines __MACH__ - #include // Required for: mach_absolute_time() +// 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) #endif //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#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 -#define PHYSAC_K 1.0f/3.0f -#define PHYSAC_VECTOR_ZERO (Vector2){ 0.0f, 0.0f } +#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 } //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -#if !defined(PHYSAC_NO_THREADS) -static pthread_t physicsThreadId; // Physics thread id -#endif -static unsigned int usedMemory = 0; // Total allocated dynamic memory -static bool physicsThreadEnabled = false; // Physics thread enabled state -static double baseTime = 0.0; // Offset time for MONOTONIC clock -static double startTime = 0.0; // Start time in milliseconds -static double deltaTime = 1.0/60.0/10.0 * 1000; // Delta time used for physics steps, in milliseconds -static double currentTime = 0.0; // Current time in milliseconds -static unsigned long long int frequency = 0; // Hi-res clock frequency +static double deltaTime = 1.0/60.0/10.0 * 1000; // Delta time in milliseconds used for physics steps -static double accumulator = 0.0; // Physics time step delta time accumulator -static unsigned int stepsCount = 0; // Total physics steps processed -static Vector2 gravityForce = { 0.0f, 9.81f }; // Physics world gravity force +#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 +static double startTime = 0.0; // Start time in milliseconds +static double currentTime = 0.0; // Current time in milliseconds +#endif + +// Physics system configuration 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 +static Vector2 gravityForce = { 0.0f, 9.81f }; // Physics world gravity force + +// Utilities variables +static unsigned int usedMemory = 0; // Total allocated dynamic memory + //---------------------------------------------------------------------------------- // Module Internal Functions Declaration //---------------------------------------------------------------------------------- +#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) +// Timming measure functions +static void InitTimer(void); // Initializes hi-resolution MONOTONIC timer +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) + static int FindAvailableBodyIndex(); // Finds a valid index for a new physics body initialization -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) static int FindAvailableManifoldIndex(); // Finds a valid index for a new manifold initialization +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 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 IntegratePhysicsImpulses(PhysicsManifold manifold); // Integrates physics collisions impulses to solve collisions 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 +static float FindAxisLeastPenetration(int *faceIndex, PhysicsShape shapeA, PhysicsShape shapeB); // Finds polygon shapes axis least penetration -static void InitTimer(void); // Initializes hi-resolution MONOTONIC timer -static unsigned long long int GetTimeCount(void); // Get hi-res MONOTONIC time measure in mseconds -static double GetCurrentTime(void); // Get current time measure in milliseconds - -// Math functions -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 -#if defined(PHYSAC_STANDALONE) -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 -#endif - -static Matrix2x2 Mat2Radians(float radians); // Creates a matrix 2x2 from a given radians value -static void Mat2Set(Matrix2x2 *matrix, float radians); // Set values from radians to a created matrix 2x2 -static inline Matrix2x2 Mat2Transpose(Matrix2x2 matrix); // Returns the transpose of a given matrix 2x2 -static inline Vector2 Mat2MultiplyVector2(Matrix2x2 matrix, Vector2 vector); // Multiplies a vector by a matrix 2x2 +// 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 //---------------------------------------------------------------------------------- // Module Functions Definition //---------------------------------------------------------------------------------- + // 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); - #endif - +#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) // Initialize high resolution timer InitTimer(); +#endif - #if defined(PHYSAC_DEBUG) - TRACELOG("[PHYSAC] physics module initialized successfully\n"); - #endif - - accumulator = 0.0; -} - -// Returns true if physics thread is currently enabled -PHYSACDEF bool IsPhysicsEnabled(void) -{ - return physicsThreadEnabled; + TRACELOG("[PHYSAC] Physics module initialized successfully\n"); } // Sets physics global gravity force @@ -390,47 +386,42 @@ PHYSACDEF void SetPhysicsGravity(float x, float y) // Creates a new circle physics body with generic parameters PHYSACDEF PhysicsBody CreatePhysicsBodyCircle(Vector2 pos, float radius, float density) { - PhysicsBody newBody = CreatePhysicsBodyPolygon(pos, radius, PHYSAC_CIRCLE_VERTICES, density); - return newBody; + PhysicsBody body = CreatePhysicsBodyPolygon(pos, radius, PHYSAC_DEFAULT_CIRCLE_VERTICES, density); + return body; } // Creates a new rectangle physics body with generic parameters PHYSACDEF PhysicsBody CreatePhysicsBodyRectangle(Vector2 pos, float width, float height, float density) { - PhysicsBody newBody = (PhysicsBody)PHYSAC_MALLOC(sizeof(PhysicsBodyData)); + // NOTE: Make sure body data is initialized to 0 + PhysicsBody body = (PhysicsBody)PHYSAC_CALLOC(sizeof(PhysicsBodyData), 1); usedMemory += sizeof(PhysicsBodyData); - int newId = FindAvailableBodyIndex(); - if (newId != -1) + int id = FindAvailableBodyIndex(); + if (id != -1) { // Initialize new body with generic values - newBody->id = newId; - newBody->enabled = true; - newBody->position = pos; - newBody->velocity = (Vector2){ 0.0f, 0.0f }; - newBody->force = (Vector2){ 0.0f, 0.0f }; - newBody->angularVelocity = 0.0f; - newBody->torque = 0.0f; - newBody->orient = 0.0f; - newBody->shape.type = PHYSICS_POLYGON; - newBody->shape.body = newBody; - newBody->shape.radius = 0.0f; - newBody->shape.transform = Mat2Radians(0.0f); - newBody->shape.vertexData = CreateRectanglePolygon(pos, (Vector2){ width, height }); + 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 }); // Calculate centroid and moment of inertia Vector2 center = { 0.0f, 0.0f }; float area = 0.0f; float inertia = 0.0f; - for (int i = 0; i < newBody->shape.vertexData.vertexCount; i++) + for (int i = 0; i < body->shape.vertexData.vertexCount; i++) { // Triangle vertices, third vertex implied as (0, 0) - Vector2 p1 = newBody->shape.vertexData.positions[i]; - int nextIndex = (((i + 1) < newBody->shape.vertexData.vertexCount) ? (i + 1) : 0); - Vector2 p2 = newBody->shape.vertexData.positions[nextIndex]; + Vector2 p1 = body->shape.vertexData.positions[i]; + int nextIndex = (((i + 1) < body->shape.vertexData.vertexCount) ? (i + 1) : 0); + Vector2 p2 = body->shape.vertexData.positions[nextIndex]; - float D = MathCrossVector2(p1, p2); + float D = MathVector2CrossProduct(p1, p2); float triangleArea = D/2; area += triangleArea; @@ -449,74 +440,70 @@ PHYSACDEF PhysicsBody CreatePhysicsBodyRectangle(Vector2 pos, float width, float // 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++) + for (int i = 0; i < body->shape.vertexData.vertexCount; i++) { - newBody->shape.vertexData.positions[i].x -= center.x; - newBody->shape.vertexData.positions[i].y -= center.y; + body->shape.vertexData.positions[i].x -= center.x; + body->shape.vertexData.positions[i].y -= center.y; } - 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; - newBody->restitution = 0.0f; - newBody->useGravity = true; - newBody->isGrounded = false; - newBody->freezeOrient = false; + 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; // Add new body to bodies pointers array and update bodies count - bodies[physicsBodiesCount] = newBody; + bodies[physicsBodiesCount] = body; physicsBodiesCount++; - #if defined(PHYSAC_DEBUG) - TRACELOG("[PHYSAC] created polygon physics body id %i\n", newBody->id); - #endif + TRACELOG("[PHYSAC] Physic body created successfully (id: %i)\n", body->id); } - #if defined(PHYSAC_DEBUG) - else TRACELOG("[PHYSAC] new physics body creation failed because there is any available id to use\n"); - #endif + else TRACELOG("[PHYSAC] Physic body could not be created, PHYSAC_MAX_BODIES reached\n"); - return newBody; + return body; } // Creates a new polygon physics body with generic parameters PHYSACDEF PhysicsBody CreatePhysicsBodyPolygon(Vector2 pos, float radius, int sides, float density) { - PhysicsBody newBody = (PhysicsBody)PHYSAC_MALLOC(sizeof(PhysicsBodyData)); + PhysicsBody body = (PhysicsBody)PHYSAC_MALLOC(sizeof(PhysicsBodyData)); usedMemory += sizeof(PhysicsBodyData); - int newId = FindAvailableBodyIndex(); - if (newId != -1) + int id = FindAvailableBodyIndex(); + if (id != -1) { // Initialize new body with generic values - newBody->id = newId; - newBody->enabled = true; - newBody->position = pos; - newBody->velocity = PHYSAC_VECTOR_ZERO; - newBody->force = PHYSAC_VECTOR_ZERO; - newBody->angularVelocity = 0.0f; - newBody->torque = 0.0f; - newBody->orient = 0.0f; - newBody->shape.type = PHYSICS_POLYGON; - newBody->shape.body = newBody; - newBody->shape.transform = Mat2Radians(0.0f); - newBody->shape.vertexData = CreateRandomPolygon(radius, sides); + 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); // Calculate centroid and moment of inertia Vector2 center = { 0.0f, 0.0f }; float area = 0.0f; float inertia = 0.0f; - for (int i = 0; i < newBody->shape.vertexData.vertexCount; i++) + for (int i = 0; i < body->shape.vertexData.vertexCount; i++) { // Triangle vertices, third vertex implied as (0, 0) - Vector2 position1 = newBody->shape.vertexData.positions[i]; - int nextIndex = (((i + 1) < newBody->shape.vertexData.vertexCount) ? (i + 1) : 0); - Vector2 position2 = newBody->shape.vertexData.positions[nextIndex]; + Vector2 position1 = body->shape.vertexData.positions[i]; + int nextIndex = (((i + 1) < body->shape.vertexData.vertexCount) ? (i + 1) : 0); + Vector2 position2 = body->shape.vertexData.positions[nextIndex]; - float cross = MathCrossVector2(position1, position2); + float cross = MathVector2CrossProduct(position1, position2); float triangleArea = cross/2; area += triangleArea; @@ -535,42 +522,38 @@ PHYSACDEF PhysicsBody CreatePhysicsBodyPolygon(Vector2 pos, float radius, int si // 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++) + for (int i = 0; i < body->shape.vertexData.vertexCount; i++) { - newBody->shape.vertexData.positions[i].x -= center.x; - newBody->shape.vertexData.positions[i].y -= center.y; + body->shape.vertexData.positions[i].x -= center.x; + body->shape.vertexData.positions[i].y -= center.y; } - 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; - newBody->restitution = 0.0f; - newBody->useGravity = true; - newBody->isGrounded = false; - newBody->freezeOrient = false; + 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; // Add new body to bodies pointers array and update bodies count - bodies[physicsBodiesCount] = newBody; + bodies[physicsBodiesCount] = body; physicsBodiesCount++; - #if defined(PHYSAC_DEBUG) - TRACELOG("[PHYSAC] created polygon physics body id %i\n", newBody->id); - #endif + TRACELOG("[PHYSAC] Physic body created successfully (id: %i)\n", body->id); } - #if defined(PHYSAC_DEBUG) - else TRACELOG("[PHYSAC] new physics body creation failed because there is any available id to use\n"); - #endif + else TRACELOG("[PHYSAC] Physics body could not be created, PHYSAC_MAX_BODIES reached\n"); - return newBody; + return body; } // Adds a force to a physics body PHYSACDEF void PhysicsAddForce(PhysicsBody body, Vector2 force) { - if (body != NULL) body->force = Vector2Add(body->force, force); + if (body != NULL) body->force = MathVector2Add(body->force, force); } // Adds an angular force to a physics body @@ -586,15 +569,15 @@ PHYSACDEF void PhysicsShatter(PhysicsBody body, Vector2 position, float force) { if (body->shape.type == PHYSICS_POLYGON) { - PolygonData vertexData = body->shape.vertexData; + PhysicsVertexData vertexData = body->shape.vertexData; bool collision = false; for (int i = 0; i < vertexData.vertexCount; i++) { Vector2 positionA = body->position; - Vector2 positionB = Mat2MultiplyVector2(body->shape.transform, Vector2Add(body->position, vertexData.positions[i])); + Vector2 positionB = MathMatVector2Product(body->shape.transform, MathVector2Add(body->position, vertexData.positions[i])); int nextIndex = (((i + 1) < vertexData.vertexCount) ? (i + 1) : 0); - Vector2 positionC = Mat2MultiplyVector2(body->shape.transform, Vector2Add(body->position, vertexData.positions[nextIndex])); + Vector2 positionC = MathMatVector2Product(body->shape.transform, MathVector2Add(body->position, vertexData.positions[nextIndex])); // Check collision between each triangle float alpha = ((positionB.y - positionC.y)*(position.x - positionC.x) + (positionC.x - positionB.x)*(position.y - positionC.y))/ @@ -626,54 +609,54 @@ PHYSACDEF void PhysicsShatter(PhysicsBody body, Vector2 position, float force) for (int i = 0; i < count; i++) { int nextIndex = (((i + 1) < count) ? (i + 1) : 0); - Vector2 center = TriangleBarycenter(vertices[i], vertices[nextIndex], PHYSAC_VECTOR_ZERO); - center = Vector2Add(bodyPos, center); - Vector2 offset = Vector2Subtract(center, bodyPos); + Vector2 center = MathTriangleBarycenter(vertices[i], vertices[nextIndex], PHYSAC_VECTOR_ZERO); + center = MathVector2Add(bodyPos, center); + Vector2 offset = MathVector2Subtract(center, bodyPos); - PhysicsBody newBody = CreatePhysicsBodyPolygon(center, 10, 3, 10); // Create polygon physics body with relevant values + PhysicsBody body = CreatePhysicsBodyPolygon(center, 10, 3, 10); // Create polygon physics body with relevant values - PolygonData newData = { 0 }; - newData.vertexCount = 3; + PhysicsVertexData vertexData = { 0 }; + vertexData.vertexCount = 3; - newData.positions[0] = Vector2Subtract(vertices[i], offset); - newData.positions[1] = Vector2Subtract(vertices[nextIndex], offset); - newData.positions[2] = Vector2Subtract(position, center); + vertexData.positions[0] = MathVector2Subtract(vertices[i], offset); + vertexData.positions[1] = MathVector2Subtract(vertices[nextIndex], offset); + vertexData.positions[2] = MathVector2Subtract(position, center); // Separate vertices to avoid unnecessary physics collisions - 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; + 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; // Calculate polygon faces normals - for (int j = 0; j < newData.vertexCount; j++) + for (int j = 0; j < vertexData.vertexCount; j++) { - int nextVertex = (((j + 1) < newData.vertexCount) ? (j + 1) : 0); - Vector2 face = Vector2Subtract(newData.positions[nextVertex], newData.positions[j]); + int nextVertex = (((j + 1) < vertexData.vertexCount) ? (j + 1) : 0); + Vector2 face = MathVector2Subtract(vertexData.positions[nextVertex], vertexData.positions[j]); - newData.normals[j] = (Vector2){ face.y, -face.x }; - MathNormalize(&newData.normals[j]); + vertexData.normals[j] = CLITERAL(Vector2){ face.y, -face.x }; + MathVector2Normalize(&vertexData.normals[j]); } // Apply computed vertex data to new physics body shape - newBody->shape.vertexData = newData; - newBody->shape.transform = trans; + body->shape.vertexData = vertexData; + body->shape.transform = trans; // Calculate centroid and moment of inertia center = PHYSAC_VECTOR_ZERO; float area = 0.0f; float inertia = 0.0f; - for (int j = 0; j < newBody->shape.vertexData.vertexCount; j++) + for (int j = 0; j < body->shape.vertexData.vertexCount; j++) { // Triangle vertices, third vertex implied as (0, 0) - Vector2 p1 = newBody->shape.vertexData.positions[j]; - int nextVertex = (((j + 1) < newBody->shape.vertexData.vertexCount) ? (j + 1) : 0); - Vector2 p2 = newBody->shape.vertexData.positions[nextVertex]; + Vector2 p1 = body->shape.vertexData.positions[j]; + int nextVertex = (((j + 1) < body->shape.vertexData.vertexCount) ? (j + 1) : 0); + Vector2 p2 = body->shape.vertexData.positions[nextVertex]; - float D = MathCrossVector2(p1, p2); + float D = MathVector2CrossProduct(p1, p2); float triangleArea = D/2; area += triangleArea; @@ -690,32 +673,30 @@ PHYSACDEF void PhysicsShatter(PhysicsBody body, Vector2 position, float force) 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); + 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); // Calculate explosion force direction - Vector2 pointA = newBody->position; - Vector2 pointB = Vector2Subtract(newData.positions[1], newData.positions[0]); + Vector2 pointA = body->position; + Vector2 pointB = MathVector2Subtract(vertexData.positions[1], vertexData.positions[0]); pointB.x /= 2.0f; pointB.y /= 2.0f; - Vector2 forceDirection = Vector2Subtract(Vector2Add(pointA, Vector2Add(newData.positions[0], pointB)), newBody->position); - MathNormalize(&forceDirection); + Vector2 forceDirection = MathVector2Subtract(MathVector2Add(pointA, MathVector2Add(vertexData.positions[0], pointB)), body->position); + MathVector2Normalize(&forceDirection); forceDirection.x *= force; forceDirection.y *= force; // Apply force to new physics body - PhysicsAddForce(newBody, forceDirection); + PhysicsAddForce(body, forceDirection); } PHYSAC_FREE(vertices); } } } - #if defined(PHYSAC_DEBUG) - else TRACELOG("[PHYSAC] error when trying to shatter a null reference physics body"); - #endif + else TRACELOG("[PHYSAC] WARNING: PhysicsShatter: NULL physic body\n"); } // Returns the current amount of created physics bodies @@ -733,16 +714,9 @@ PHYSACDEF PhysicsBody GetPhysicsBody(int index) { body = bodies[index]; - if (body == NULL) - { - #if defined(PHYSAC_DEBUG) - TRACELOG("[PHYSAC] error when trying to get a null reference physics body"); - #endif - } + if (body == NULL) TRACELOG("[PHYSAC] WARNING: GetPhysicsBody: NULL physic body\n"); } - #if defined(PHYSAC_DEBUG) - else TRACELOG("[PHYSAC] physics body index is out of bounds"); - #endif + else TRACELOG("[PHYSAC] WARNING: Physic body index is out of bounds\n"); return body; } @@ -757,13 +731,9 @@ PHYSACDEF int GetPhysicsShapeType(int index) PhysicsBody body = bodies[index]; if (body != NULL) result = body->shape.type; - #if defined(PHYSAC_DEBUG) - else TRACELOG("[PHYSAC] error when trying to get a null reference physics body"); - #endif + else TRACELOG("[PHYSAC] WARNING: GetPhysicsShapeType: NULL physic body\n"); } - #if defined(PHYSAC_DEBUG) - else TRACELOG("[PHYSAC] physics body index is out of bounds"); - #endif + else TRACELOG("[PHYSAC] WARNING: Physic body index is out of bounds\n"); return result; } @@ -781,18 +751,14 @@ PHYSACDEF int GetPhysicsShapeVerticesCount(int index) { switch (body->shape.type) { - case PHYSICS_CIRCLE: result = PHYSAC_CIRCLE_VERTICES; break; + case PHYSICS_CIRCLE: result = PHYSAC_DEFAULT_CIRCLE_VERTICES; break; case PHYSICS_POLYGON: result = body->shape.vertexData.vertexCount; break; default: break; } } - #if defined(PHYSAC_DEBUG) - else TRACELOG("[PHYSAC] error when trying to get a null reference physics body"); - #endif + else TRACELOG("[PHYSAC] WARNING: GetPhysicsShapeVerticesCount: NULL physic body\n"); } - #if defined(PHYSAC_DEBUG) - else TRACELOG("[PHYSAC] physics body index is out of bounds"); - #endif + else TRACELOG("[PHYSAC] WARNING: Physic body index is out of bounds\n"); return result; } @@ -808,20 +774,18 @@ PHYSACDEF Vector2 GetPhysicsShapeVertex(PhysicsBody body, int vertex) { case PHYSICS_CIRCLE: { - 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; + 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; } break; case PHYSICS_POLYGON: { - PolygonData vertexData = body->shape.vertexData; - position = Vector2Add(body->position, Mat2MultiplyVector2(body->shape.transform, vertexData.positions[vertex])); + PhysicsVertexData vertexData = body->shape.vertexData; + position = MathVector2Add(body->position, MathMatVector2Product(body->shape.transform, vertexData.positions[vertex])); } break; default: break; } } - #if defined(PHYSAC_DEBUG) - else TRACELOG("[PHYSAC] error when trying to get a null reference physics body"); - #endif + else TRACELOG("[PHYSAC] WARNING: GetPhysicsShapeVertex: NULL physic body\n"); return position; } @@ -833,7 +797,7 @@ PHYSACDEF void SetPhysicsBodyRotation(PhysicsBody body, float radians) { body->orient = radians; - if (body->shape.type == PHYSICS_POLYGON) body->shape.transform = Mat2Radians(radians); + if (body->shape.type == PHYSICS_POLYGON) body->shape.transform = MathMatFromRadians(radians); } } @@ -856,9 +820,7 @@ PHYSACDEF void DestroyPhysicsBody(PhysicsBody body) if (index == -1) { - #if defined(PHYSAC_DEBUG) - TRACELOG("[PHYSAC] Not possible to find body id %i in pointers array\n", id); - #endif + TRACELOG("[PHYSAC] WARNING: Requested body (id: %i) can not be found\n", id); return; // Prevent access to index -1 } @@ -876,13 +838,9 @@ PHYSACDEF void DestroyPhysicsBody(PhysicsBody body) // Update physics bodies count physicsBodiesCount--; - #if defined(PHYSAC_DEBUG) - TRACELOG("[PHYSAC] destroyed physics body id %i\n", id); - #endif + TRACELOG("[PHYSAC] Physic body destroyed successfully (id: %i)\n", id); } - #if defined(PHYSAC_DEBUG) - else TRACELOG("[PHYSAC] error trying to destroy a null referenced body\n"); - #endif + else TRACELOG("[PHYSAC] WARNING: DestroyPhysicsBody: NULL physic body\n"); } // Destroys created physics bodies and manifolds and resets global values @@ -918,32 +876,28 @@ PHYSACDEF void ResetPhysics(void) physicsManifoldsCount = 0; - #if defined(PHYSAC_DEBUG) - TRACELOG("[PHYSAC] physics module reset successfully\n"); - #endif + TRACELOG("[PHYSAC] Physics module reseted successfully\n"); } // 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 - // 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) TRACELOG("[PHYSAC] physics module closed with %i still allocated bodies [MEMORY: %i bytes]\n", physicsBodiesCount, usedMemory); - else if (physicsManifoldsCount > 0 || usedMemory != 0) TRACELOG("[PHYSAC] physics module closed with %i still allocated manifolds [MEMORY: %i bytes]\n", physicsManifoldsCount, usedMemory); - else TRACELOG("[PHYSAC] physics module closed successfully\n"); - #endif + // 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"); } //---------------------------------------------------------------------------------- @@ -978,10 +932,10 @@ static int FindAvailableBodyIndex() return index; } -// Creates a random polygon shape with max vertex distance from polygon pivot -static PolygonData CreateRandomPolygon(float radius, int sides) +// Creates a default polygon shape with max vertex distance from polygon pivot +static PhysicsVertexData CreateDefaultPolygon(float radius, int sides) { - PolygonData data = { 0 }; + PhysicsVertexData data = { 0 }; data.vertexCount = sides; // Calculate polygon vertices positions @@ -995,67 +949,43 @@ static PolygonData CreateRandomPolygon(float radius, int sides) for (int i = 0; i < data.vertexCount; i++) { int nextIndex = (((i + 1) < sides) ? (i + 1) : 0); - Vector2 face = Vector2Subtract(data.positions[nextIndex], data.positions[i]); + Vector2 face = MathVector2Subtract(data.positions[nextIndex], data.positions[i]); - data.normals[i] = (Vector2){ face.y, -face.x }; - MathNormalize(&data.normals[i]); + data.normals[i] = CLITERAL(Vector2){ face.y, -face.x }; + MathVector2Normalize(&data.normals[i]); } return data; } // Creates a rectangle polygon shape based on a min and max positions -static PolygonData CreateRectanglePolygon(Vector2 pos, Vector2 size) +static PhysicsVertexData CreateRectanglePolygon(Vector2 pos, Vector2 size) { - PolygonData data = { 0 }; + PhysicsVertexData data = { 0 }; data.vertexCount = 4; // Calculate polygon vertices positions - 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 }; + 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 (int i = 0; i < data.vertexCount; i++) { int nextIndex = (((i + 1) < data.vertexCount) ? (i + 1) : 0); - Vector2 face = Vector2Subtract(data.positions[nextIndex], data.positions[i]); + Vector2 face = MathVector2Subtract(data.positions[nextIndex], data.positions[i]); - data.normals[i] = (Vector2){ face.y, -face.x }; - MathNormalize(&data.normals[i]); + data.normals[i] = CLITERAL(Vector2){ face.y, -face.x }; + MathVector2Normalize(&data.normals[i]); } return data; } -// Physics loop thread function -static void *PhysicsLoop(void *arg) +// Update physics step (dynamics, collisions and position corrections) +void UpdatePhysicsStep(void) { -#if !defined(PHYSAC_NO_THREADS) - #if defined(PHYSAC_DEBUG) - TRACELOG("[PHYSAC] physics thread created successfully\n"); - #endif - - // Initialize physics loop thread values - physicsThreadEnabled = true; - - // Physics update loop - while (physicsThreadEnabled) - { - RunPhysicsStep(); - } -#endif - - return NULL; -} - -// Physics steps calculations (dynamics, collisions and position corrections) -static void PhysicsStep(void) -{ - // Update current steps count - stepsCount++; - // Clear previous generated collisions information for (int i = physicsManifoldsCount - 1; i >= 0; i--) { @@ -1091,15 +1021,15 @@ static void PhysicsStep(void) 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; + 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; } } } @@ -1156,31 +1086,34 @@ static void PhysicsStep(void) } } -// Wrapper to ensure PhysicsStep is run with at a fixed time step -PHYSACDEF void RunPhysicsStep(void) +// Update physics system +// Physics steps are launched at a fixed time step if enabled +PHYSACDEF void UpdatePhysics(void) { - // Calculate current time +#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) + static double deltaTimeAccumulator = 0.0; + + // Calculate current time (ms) currentTime = GetCurrentTime(); - // Calculate current delta time + // Calculate current delta time (ms) const double delta = currentTime - startTime; // Store the time elapsed since the last frame began - accumulator += delta; + deltaTimeAccumulator += delta; // Fixed time stepping loop - while (accumulator >= deltaTime) + while (deltaTimeAccumulator >= deltaTime) { -#ifdef PHYSAC_DEBUG - //TRACELOG("currentTime %f, startTime %f, accumulator-pre %f, accumulator-post %f, delta %f, deltaTime %f\n", - // currentTime, startTime, accumulator, accumulator-deltaTime, delta, deltaTime); -#endif - PhysicsStep(); - accumulator -= deltaTime; + UpdatePhysicsStep(); + deltaTimeAccumulator -= deltaTime; } // Record the starting of this frame startTime = currentTime; +#else + UpdatePhysicsStep(); +#endif } PHYSACDEF void SetPhysicsTimeStep(double delta) @@ -1220,34 +1153,32 @@ static int FindAvailableManifoldIndex() // Creates a new physics manifold to solve collision static PhysicsManifold CreatePhysicsManifold(PhysicsBody a, PhysicsBody b) { - PhysicsManifold newManifold = (PhysicsManifold)PHYSAC_MALLOC(sizeof(PhysicsManifoldData)); + PhysicsManifold manifold = (PhysicsManifold)PHYSAC_MALLOC(sizeof(PhysicsManifoldData)); usedMemory += sizeof(PhysicsManifoldData); - int newId = FindAvailableManifoldIndex(); - if (newId != -1) + int id = FindAvailableManifoldIndex(); + if (id != -1) { // Initialize new manifold with generic values - newManifold->id = newId; - newManifold->bodyA = a; - newManifold->bodyB = b; - newManifold->penetration = 0; - newManifold->normal = PHYSAC_VECTOR_ZERO; - newManifold->contacts[0] = PHYSAC_VECTOR_ZERO; - newManifold->contacts[1] = PHYSAC_VECTOR_ZERO; - newManifold->contactsCount = 0; - newManifold->restitution = 0.0f; - newManifold->dynamicFriction = 0.0f; - newManifold->staticFriction = 0.0f; + 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; // Add new body to bodies pointers array and update bodies count - contacts[physicsManifoldsCount] = newManifold; + contacts[physicsManifoldsCount] = manifold; physicsManifoldsCount++; } - #if defined(PHYSAC_DEBUG) - else TRACELOG("[PHYSAC] new physics manifold creation failed because there is any available id to use\n"); - #endif + else TRACELOG("[PHYSAC] Physic manifold could not be created, PHYSAC_MAX_MANIFOLDS reached\n"); - return newManifold; + return manifold; } // Unitializes and destroys a physics manifold @@ -1267,13 +1198,7 @@ static void DestroyPhysicsManifold(PhysicsManifold manifold) } } - if (index == -1) - { - #if defined(PHYSAC_DEBUG) - TRACELOG("[PHYSAC] Not possible to manifold id %i in pointers array\n", id); - #endif - return; // Prevent access to index -1 - } + if (index == -1) return; // Prevent access to index -1 // Free manifold allocated memory PHYSAC_FREE(manifold); @@ -1289,9 +1214,7 @@ static void DestroyPhysicsManifold(PhysicsManifold manifold) // Update physics manifolds count physicsManifoldsCount--; } - #if defined(PHYSAC_DEBUG) - else TRACELOG("[PHYSAC] error trying to destroy a null referenced manifold\n"); - #endif + else TRACELOG("[PHYSAC] WARNING: DestroyPhysicsManifold: NULL physic manifold\n"); } // Solves a created physics manifold between two physics bodies @@ -1333,9 +1256,9 @@ static void SolveCircleToCircle(PhysicsManifold manifold) if ((bodyA == NULL) || (bodyB == NULL)) return; // Calculate translational vector, which is normal - Vector2 normal = Vector2Subtract(bodyB->position, bodyA->position); + Vector2 normal = MathVector2Subtract(bodyB->position, bodyA->position); - float distSqr = MathLenSqr(normal); + float distSqr = MathVector2SqrLen(normal); float radius = bodyA->shape.radius + bodyB->shape.radius; // Check if circles are not in contact @@ -1351,14 +1274,14 @@ static void SolveCircleToCircle(PhysicsManifold manifold) if (distance == 0.0f) { manifold->penetration = bodyA->shape.radius; - manifold->normal = (Vector2){ 1.0f, 0.0f }; + manifold->normal = CLITERAL(Vector2){ 1.0f, 0.0f }; 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 }; + 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 }; } // Update physics body grounded state if normal direction is down @@ -1377,17 +1300,17 @@ static void SolveCircleToPolygon(PhysicsManifold manifold) // Transform circle center to polygon transform space Vector2 center = bodyA->position; - center = Mat2MultiplyVector2(Mat2Transpose(bodyB->shape.transform), Vector2Subtract(center, bodyB->position)); + center = MathMatVector2Product(MathMatTranspose(bodyB->shape.transform), MathVector2Subtract(center, bodyB->position)); // 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; + PhysicsVertexData vertexData = bodyB->shape.vertexData; for (int i = 0; i < vertexData.vertexCount; i++) { - float currentSeparation = MathDot(vertexData.normals[i], Vector2Subtract(center, vertexData.positions[i])); + float currentSeparation = MathVector2DotProduct(vertexData.normals[i], MathVector2Subtract(center, vertexData.positions[i])); if (currentSeparation > bodyA->shape.radius) return; @@ -1407,53 +1330,53 @@ static void SolveCircleToPolygon(PhysicsManifold manifold) if (separation < PHYSAC_EPSILON) { manifold->contactsCount = 1; - Vector2 normal = Mat2MultiplyVector2(bodyB->shape.transform, vertexData.normals[faceNormal]); - 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 }; + 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 }; 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)); + float dot1 = MathVector2DotProduct(MathVector2Subtract(center, v1), MathVector2Subtract(v2, v1)); + float dot2 = MathVector2DotProduct(MathVector2Subtract(center, v2), MathVector2Subtract(v1, v2)); manifold->penetration = bodyA->shape.radius - separation; if (dot1 <= 0.0f) // Closest to v1 { - if (DistSqr(center, v1) > bodyA->shape.radius*bodyA->shape.radius) return; + if (MathVector2SqrDistance(center, v1) > bodyA->shape.radius*bodyA->shape.radius) return; manifold->contactsCount = 1; - Vector2 normal = Vector2Subtract(v1, center); - normal = Mat2MultiplyVector2(bodyB->shape.transform, normal); - MathNormalize(&normal); + Vector2 normal = MathVector2Subtract(v1, center); + normal = MathMatVector2Product(bodyB->shape.transform, normal); + MathVector2Normalize(&normal); manifold->normal = normal; - v1 = Mat2MultiplyVector2(bodyB->shape.transform, v1); - v1 = Vector2Add(v1, bodyB->position); + v1 = MathMatVector2Product(bodyB->shape.transform, v1); + v1 = MathVector2Add(v1, bodyB->position); manifold->contacts[0] = v1; } else if (dot2 <= 0.0f) // Closest to v2 { - if (DistSqr(center, v2) > bodyA->shape.radius*bodyA->shape.radius) return; + if (MathVector2SqrDistance(center, v2) > bodyA->shape.radius*bodyA->shape.radius) return; manifold->contactsCount = 1; - Vector2 normal = Vector2Subtract(v2, center); - v2 = Mat2MultiplyVector2(bodyB->shape.transform, v2); - v2 = Vector2Add(v2, bodyB->position); + Vector2 normal = MathVector2Subtract(v2, center); + v2 = MathMatVector2Product(bodyB->shape.transform, v2); + v2 = MathVector2Add(v2, bodyB->position); manifold->contacts[0] = v2; - normal = Mat2MultiplyVector2(bodyB->shape.transform, normal); - MathNormalize(&normal); + normal = MathMatVector2Product(bodyB->shape.transform, normal); + MathVector2Normalize(&normal); manifold->normal = normal; } else // Closest to face { Vector2 normal = vertexData.normals[faceNormal]; - if (MathDot(Vector2Subtract(center, v1), normal) > bodyA->shape.radius) return; + if (MathVector2DotProduct(MathVector2Subtract(center, v1), normal) > bodyA->shape.radius) return; - normal = Mat2MultiplyVector2(bodyB->shape.transform, normal); - 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 }; + 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 }; manifold->contactsCount = 1; } } @@ -1500,7 +1423,8 @@ static void SolvePolygonToPolygon(PhysicsManifold manifold) PhysicsShape incPoly; // Incident // Determine which shape contains reference face - if (BiasGreaterThan(penetrationA, penetrationB)) + // Checking bias range for penetration + if (penetrationA >= (penetrationB*0.95f + penetrationA*0.01f)) { refPoly = bodyA; incPoly = bodyB; @@ -1519,37 +1443,37 @@ static void SolvePolygonToPolygon(PhysicsManifold manifold) FindIncidentFace(&incidentFace[0], &incidentFace[1], refPoly, incPoly, referenceIndex); // Setup reference face vertices - PolygonData refData = refPoly.vertexData; + PhysicsVertexData refData = refPoly.vertexData; Vector2 v1 = refData.positions[referenceIndex]; referenceIndex = (((referenceIndex + 1) < refData.vertexCount) ? (referenceIndex + 1) : 0); Vector2 v2 = refData.positions[referenceIndex]; // Transform vertices to world space - v1 = Mat2MultiplyVector2(refPoly.transform, v1); - v1 = Vector2Add(v1, refPoly.body->position); - v2 = Mat2MultiplyVector2(refPoly.transform, v2); - v2 = Vector2Add(v2, refPoly.body->position); + v1 = MathMatVector2Product(refPoly.transform, v1); + v1 = MathVector2Add(v1, refPoly.body->position); + v2 = MathMatVector2Product(refPoly.transform, v2); + v2 = MathVector2Add(v2, refPoly.body->position); // Calculate reference face side normal in world space - Vector2 sidePlaneNormal = Vector2Subtract(v2, v1); - MathNormalize(&sidePlaneNormal); + Vector2 sidePlaneNormal = MathVector2Subtract(v2, v1); + MathVector2Normalize(&sidePlaneNormal); // Orthogonalize Vector2 refFaceNormal = { sidePlaneNormal.y, -sidePlaneNormal.x }; - float refC = MathDot(refFaceNormal, v1); - float negSide = MathDot(sidePlaneNormal, v1)*-1; - float posSide = MathDot(sidePlaneNormal, v2); + float refC = MathVector2DotProduct(refFaceNormal, v1); + float negSide = MathVector2DotProduct(sidePlaneNormal, v1)*-1; + float posSide = MathVector2DotProduct(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; + // 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; // Flip normal if required - manifold->normal = (flip ? (Vector2){ -refFaceNormal.x, -refFaceNormal.y } : refFaceNormal); + manifold->normal = (flip ? CLITERAL(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; + int currentPoint = 0; // MathVector2Clipped points behind reference face + float separation = MathVector2DotProduct(refFaceNormal, incidentFace[0]) - refC; if (separation <= 0.0f) { manifold->contacts[currentPoint] = incidentFace[0]; @@ -1558,7 +1482,7 @@ static void SolvePolygonToPolygon(PhysicsManifold manifold) } else manifold->penetration = 0.0f; - separation = MathDot(refFaceNormal, incidentFace[1]) - refC; + separation = MathVector2DotProduct(refFaceNormal, incidentFace[1]) - refC; if (separation <= 0.0f) { @@ -1606,11 +1530,11 @@ static void InitializePhysicsManifolds(PhysicsManifold manifold) for (int i = 0; i < manifold->contactsCount; i++) { // 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 radiusA = MathVector2Subtract(manifold->contacts[i], bodyA->position); + Vector2 radiusB = MathVector2Subtract(manifold->contacts[i], bodyB->position); - Vector2 crossA = MathCross(bodyA->angularVelocity, radiusA); - Vector2 crossB = MathCross(bodyB->angularVelocity, radiusB); + Vector2 crossA = MathVector2Product(radiusA, bodyA->angularVelocity); + Vector2 crossB = MathVector2Product(radiusB, bodyB->angularVelocity); Vector2 radiusV = { 0.0f, 0.0f }; radiusV.x = bodyB->velocity.x + crossB.x - bodyA->velocity.x - crossA.x; @@ -1618,7 +1542,7 @@ static void InitializePhysicsManifolds(PhysicsManifold manifold) // 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 - if (MathLenSqr(radiusV) < (MathLenSqr((Vector2){ gravityForce.x*deltaTime/1000, gravityForce.y*deltaTime/1000 }) + PHYSAC_EPSILON)) manifold->restitution = 0; + if (MathVector2SqrLen(radiusV) < (MathVector2SqrLen(CLITERAL(Vector2){ gravityForce.x*deltaTime/1000, gravityForce.y*deltaTime/1000 }) + PHYSAC_EPSILON)) manifold->restitution = 0; } } @@ -1641,22 +1565,22 @@ static void IntegratePhysicsImpulses(PhysicsManifold manifold) 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); + Vector2 radiusA = MathVector2Subtract(manifold->contacts[i], bodyA->position); + Vector2 radiusB = MathVector2Subtract(manifold->contacts[i], bodyB->position); // Calculate relative velocity Vector2 radiusV = { 0.0f, 0.0f }; - 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; + 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; // Relative velocity along the normal - float contactVelocity = MathDot(radiusV, manifold->normal); + float contactVelocity = MathVector2DotProduct(radiusV, manifold->normal); // Do not resolve if velocities are separating if (contactVelocity > 0.0f) return; - float raCrossN = MathCrossVector2(radiusA, manifold->normal); - float rbCrossN = MathCrossVector2(radiusB, manifold->normal); + float raCrossN = MathVector2CrossProduct(radiusA, manifold->normal); + float rbCrossN = MathVector2CrossProduct(radiusB, manifold->normal); float inverseMassSum = bodyA->inverseMass + bodyB->inverseMass + (raCrossN*raCrossN)*bodyA->inverseInertia + (rbCrossN*rbCrossN)*bodyB->inverseInertia; @@ -1672,25 +1596,25 @@ static void IntegratePhysicsImpulses(PhysicsManifold manifold) { 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 (!bodyA->freezeOrient) bodyA->angularVelocity += bodyA->inverseInertia*MathVector2CrossProduct(radiusA, CLITERAL(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); + if (!bodyB->freezeOrient) bodyB->angularVelocity += bodyB->inverseInertia*MathVector2CrossProduct(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; + 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; - Vector2 tangent = { radiusV.x - (manifold->normal.x*MathDot(radiusV, manifold->normal)), radiusV.y - (manifold->normal.y*MathDot(radiusV, manifold->normal)) }; - MathNormalize(&tangent); + Vector2 tangent = { radiusV.x - (manifold->normal.x*MathVector2DotProduct(radiusV, manifold->normal)), radiusV.y - (manifold->normal.y*MathVector2DotProduct(radiusV, manifold->normal)) }; + MathVector2Normalize(&tangent); // Calculate impulse tangent magnitude - float impulseTangent = -MathDot(radiusV, tangent); + float impulseTangent = -MathVector2DotProduct(radiusV, tangent); impulseTangent /= inverseMassSum; impulseTangent /= (float)manifold->contactsCount; @@ -1701,8 +1625,8 @@ static void IntegratePhysicsImpulses(PhysicsManifold manifold) // Apply coulumb's law Vector2 tangentImpulse = { 0.0f, 0.0f }; - 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 }; + 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 }; // Apply friction impulse if (bodyA->enabled) @@ -1710,7 +1634,7 @@ static void IntegratePhysicsImpulses(PhysicsManifold manifold) 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 (!bodyA->freezeOrient) bodyA->angularVelocity += bodyA->inverseInertia*MathVector2CrossProduct(radiusA, CLITERAL(Vector2){ -tangentImpulse.x, -tangentImpulse.y }); } if (bodyB->enabled) @@ -1718,7 +1642,7 @@ static void IntegratePhysicsImpulses(PhysicsManifold manifold) bodyB->velocity.x += bodyB->inverseMass*(tangentImpulse.x); bodyB->velocity.y += bodyB->inverseMass*(tangentImpulse.y); - if (!bodyB->freezeOrient) bodyB->angularVelocity += bodyB->inverseInertia*MathCrossVector2(radiusB, tangentImpulse); + if (!bodyB->freezeOrient) bodyB->angularVelocity += bodyB->inverseInertia*MathVector2CrossProduct(radiusB, tangentImpulse); } } } @@ -1732,7 +1656,7 @@ static void IntegratePhysicsVelocity(PhysicsBody body) body->position.y += body->velocity.y*deltaTime; if (!body->freezeOrient) body->orient += body->angularVelocity*deltaTime; - Mat2Set(&body->shape.transform, body->orient); + body->shape.transform = MathMatFromRadians(body->orient); IntegratePhysicsForces(body); } @@ -1746,8 +1670,8 @@ static void CorrectPhysicsPositions(PhysicsManifold manifold) 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; + 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; if (bodyA->enabled) { @@ -1767,12 +1691,12 @@ static Vector2 GetSupport(PhysicsShape shape, Vector2 dir) { float bestProjection = -PHYSAC_FLT_MAX; Vector2 bestVertex = { 0.0f, 0.0f }; - PolygonData data = shape.vertexData; + PhysicsVertexData data = shape.vertexData; for (int i = 0; i < data.vertexCount; i++) { Vector2 vertex = data.positions[i]; - float projection = MathDot(vertex, dir); + float projection = MathVector2DotProduct(vertex, dir); if (projection > bestProjection) { @@ -1790,31 +1714,31 @@ static float FindAxisLeastPenetration(int *faceIndex, PhysicsShape shapeA, Physi float bestDistance = -PHYSAC_FLT_MAX; int bestIndex = 0; - PolygonData dataA = shapeA.vertexData; - //PolygonData dataB = shapeB.vertexData; + PhysicsVertexData dataA = shapeA.vertexData; + //PhysicsVertexData dataB = shapeB.vertexData; for (int i = 0; i < dataA.vertexCount; i++) { // Retrieve a face normal from A shape Vector2 normal = dataA.normals[i]; - Vector2 transNormal = Mat2MultiplyVector2(shapeA.transform, normal); + Vector2 transNormal = MathMatVector2Product(shapeA.transform, normal); // Transform face normal into B shape's model space - Matrix2x2 buT = Mat2Transpose(shapeB.transform); - normal = Mat2MultiplyVector2(buT, transNormal); + Matrix2x2 buT = MathMatTranspose(shapeB.transform); + normal = MathMatVector2Product(buT, transNormal); // Retrieve support point from B shape along -n - Vector2 support = GetSupport(shapeB, (Vector2){ -normal.x, -normal.y }); + Vector2 support = GetSupport(shapeB, CLITERAL(Vector2){ -normal.x, -normal.y }); // Retrieve vertex on face from A shape, transform into B shape's model space Vector2 vertex = dataA.positions[i]; - vertex = Mat2MultiplyVector2(shapeA.transform, vertex); - vertex = Vector2Add(vertex, shapeA.body->position); - vertex = Vector2Subtract(vertex, shapeB.body->position); - vertex = Mat2MultiplyVector2(buT, vertex); + vertex = MathMatVector2Product(shapeA.transform, vertex); + vertex = MathVector2Add(vertex, shapeA.body->position); + vertex = MathVector2Subtract(vertex, shapeB.body->position); + vertex = MathMatVector2Product(buT, vertex); // Compute penetration distance in B shape's model space - float distance = MathDot(normal, Vector2Subtract(support, vertex)); + float distance = MathVector2DotProduct(normal, MathVector2Subtract(support, vertex)); // Store greatest distance if (distance > bestDistance) @@ -1831,14 +1755,14 @@ static float FindAxisLeastPenetration(int *faceIndex, PhysicsShape shapeA, Physi // 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; + PhysicsVertexData refData = ref.vertexData; + PhysicsVertexData incData = inc.vertexData; Vector2 referenceNormal = refData.normals[index]; // Calculate normal in incident's frame of reference - referenceNormal = Mat2MultiplyVector2(ref.transform, referenceNormal); // To world space - referenceNormal = Mat2MultiplyVector2(Mat2Transpose(inc.transform), referenceNormal); // To incident's model space + referenceNormal = MathMatVector2Product(ref.transform, referenceNormal); // To world space + referenceNormal = MathMatVector2Product(MathMatTranspose(inc.transform), referenceNormal); // To incident's model space // Find most anti-normal face on polygon int incidentFace = 0; @@ -1846,7 +1770,7 @@ static void FindIncidentFace(Vector2 *v0, Vector2 *v1, PhysicsShape ref, Physics for (int i = 0; i < incData.vertexCount; i++) { - float dot = MathDot(referenceNormal, incData.normals[i]); + float dot = MathVector2DotProduct(referenceNormal, incData.normals[i]); if (dot < minDot) { @@ -1856,22 +1780,22 @@ static void FindIncidentFace(Vector2 *v0, Vector2 *v1, PhysicsShape ref, Physics } // Assign face vertices for incident face - *v0 = Mat2MultiplyVector2(inc.transform, incData.positions[incidentFace]); - *v0 = Vector2Add(*v0, inc.body->position); + *v0 = MathMatVector2Product(inc.transform, incData.positions[incidentFace]); + *v0 = MathVector2Add(*v0, inc.body->position); incidentFace = (((incidentFace + 1) < incData.vertexCount) ? (incidentFace + 1) : 0); - *v1 = Mat2MultiplyVector2(inc.transform, incData.positions[incidentFace]); - *v1 = Vector2Add(*v1, inc.body->position); + *v1 = MathMatVector2Product(inc.transform, incData.positions[incidentFace]); + *v1 = MathVector2Add(*v1, inc.body->position); } -// Calculates clipping based on a normal and two faces -static int Clip(Vector2 normal, float clip, Vector2 *faceA, Vector2 *faceB) +// Returns clipping value based on a normal and two faces +static int MathVector2Clip(Vector2 normal, Vector2 *faceA, Vector2 *faceB, float clip) { 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; + float distanceA = MathVector2DotProduct(normal, *faceA) - clip; + float distanceB = MathVector2DotProduct(normal, *faceB) - clip; // If negative (behind plane) if (distanceA <= 0.0f) out[sp++] = *faceA; @@ -1883,10 +1807,10 @@ static int Clip(Vector2 normal, float clip, Vector2 *faceA, Vector2 *faceB) // Push intersection point float alpha = distanceA/(distanceA - distanceB); out[sp] = *faceA; - Vector2 delta = Vector2Subtract(*faceB, *faceA); + Vector2 delta = MathVector2Subtract(*faceB, *faceA); delta.x *= alpha; delta.y *= alpha; - out[sp] = Vector2Add(out[sp], delta); + out[sp] = MathVector2Add(out[sp], delta); sp++; } @@ -1897,14 +1821,8 @@ static int Clip(Vector2 normal, float clip, Vector2 *faceA, Vector2 *faceB) 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) +static Vector2 MathTriangleBarycenter(Vector2 v1, Vector2 v2, Vector2 v3) { Vector2 result = { 0.0f, 0.0f }; @@ -1914,11 +1832,10 @@ static Vector2 TriangleBarycenter(Vector2 v1, Vector2 v2, Vector2 v3) return result; } +#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) // Initializes hi-resolution MONOTONIC timer static void InitTimer(void) { - srand(time(NULL)); // Initialize random seed - #if defined(_WIN32) QueryPerformanceFrequency((unsigned long long int *) &frequency); #endif @@ -1934,12 +1851,12 @@ static void InitTimer(void) frequency = (timebase.denom*1e9)/timebase.numer; #endif - baseTime = GetTimeCount(); // Get MONOTONIC clock time offset - startTime = GetCurrentTime(); // Get current time + baseClockTicks = GetClockTicks(); // Get MONOTONIC clock time offset + startTime = GetCurrentTime(); // Get current time in milliseconds } -// Get hi-res MONOTONIC time measure in seconds -static unsigned long long int GetTimeCount(void) +// Get hi-res MONOTONIC time measure in clock ticks +static unsigned long long int GetClockTicks(void) { unsigned long long int value = 0; @@ -1963,42 +1880,45 @@ static unsigned long long int GetTimeCount(void) // Get current time in milliseconds static double GetCurrentTime(void) { - return (double)(GetTimeCount() - baseTime)/frequency*1000; + return (double)(GetClockTicks() - baseClockTicks)/frequency*1000; } +#endif // !PHYSAC_AVOID_TIMMING_SYSTEM + // Returns the cross product of a vector and a value -static inline Vector2 MathCross(float value, Vector2 vector) +static inline Vector2 MathVector2Product(Vector2 vector, float value) { - return (Vector2){ -value*vector.y, value*vector.x }; + Vector2 result = { -value*vector.y, value*vector.x }; + return result; } // Returns the cross product of two vectors -static inline float MathCrossVector2(Vector2 v1, Vector2 v2) +static inline float MathVector2CrossProduct(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) +static inline float MathVector2SqrLen(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) +static inline float MathVector2DotProduct(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) +static inline float MathVector2SqrDistance(Vector2 v1, Vector2 v2) { - Vector2 dir = Vector2Subtract(v1, v2); - return MathDot(dir, dir); + Vector2 dir = MathVector2Subtract(v1, v2); + return MathVector2DotProduct(dir, dir); } // Returns the normalized values of a vector -static void MathNormalize(Vector2 *vector) +static void MathVector2Normalize(Vector2 *vector) { float length, ilength; @@ -2013,51 +1933,42 @@ static void MathNormalize(Vector2 *vector) vector->y *= ilength; } -#if defined(PHYSAC_STANDALONE) // Returns the sum of two given vectors -static inline Vector2 Vector2Add(Vector2 v1, Vector2 v2) +static inline Vector2 MathVector2Add(Vector2 v1, Vector2 v2) { - return (Vector2){ v1.x + v2.x, v1.y + v2.y }; + Vector2 result = { v1.x + v2.x, v1.y + v2.y }; + return result; } // Returns the subtract of two given vectors -static inline Vector2 Vector2Subtract(Vector2 v1, Vector2 v2) +static inline Vector2 MathVector2Subtract(Vector2 v1, Vector2 v2) { - return (Vector2){ v1.x - v2.x, v1.y - v2.y }; + Vector2 result = { v1.x - v2.x, v1.y - v2.y }; + return result; } -#endif // Creates a matrix 2x2 from a given radians value -static Matrix2x2 Mat2Radians(float radians) -{ - float c = cosf(radians); - float s = sinf(radians); - - return (Matrix2x2){ c, -s, s, c }; -} - -// Set values from radians to a created matrix 2x2 -static void Mat2Set(Matrix2x2 *matrix, float radians) +static Matrix2x2 MathMatFromRadians(float radians) { float cos = cosf(radians); float sin = sinf(radians); - matrix->m00 = cos; - matrix->m01 = -sin; - matrix->m10 = sin; - matrix->m11 = cos; + Matrix2x2 result = { cos, -sin, sin, cos }; + return result; } // Returns the transpose of a given matrix 2x2 -static inline Matrix2x2 Mat2Transpose(Matrix2x2 matrix) +static inline Matrix2x2 MathMatTranspose(Matrix2x2 matrix) { - return (Matrix2x2){ matrix.m00, matrix.m10, matrix.m01, matrix.m11 }; + Matrix2x2 result = { matrix.m00, matrix.m10, matrix.m01, matrix.m11 }; + return result; } // Multiplies a vector by a matrix 2x2 -static inline Vector2 Mat2MultiplyVector2(Matrix2x2 matrix, Vector2 vector) +static inline Vector2 MathMatVector2Product(Matrix2x2 matrix, Vector2 vector) { - return (Vector2){ matrix.m00*vector.x + matrix.m01*vector.y, matrix.m10*vector.x + matrix.m11*vector.y }; + Vector2 result = { matrix.m00*vector.x + matrix.m01*vector.y, matrix.m10*vector.x + matrix.m11*vector.y }; + return result; } #endif // PHYSAC_IMPLEMENTATION