diff options
Diffstat (limited to 'libs/raylib/src/physac.h')
-rw-r--r-- | libs/raylib/src/physac.h | 2063 |
1 files changed, 0 insertions, 2063 deletions
diff --git a/libs/raylib/src/physac.h b/libs/raylib/src/physac.h deleted file mode 100644 index d9b534b..0000000 --- a/libs/raylib/src/physac.h +++ /dev/null @@ -1,2063 +0,0 @@ -/********************************************************************************************** -* -* Physac v1.0 - 2D Physics library for videogames -* -* DESCRIPTION: -* -* Physac is a small 2D physics engine written in pure C. The engine uses a fixed time-step thread loop -* to simluate physics. A physics step contains the following phases: get collision information, -* apply dynamics, collision solving and position correction. It uses a very simple struct for physic -* bodies with a position vector to be used in any 3D rendering API. -* -* CONFIGURATION: -* -* #define PHYSAC_IMPLEMENTATION -* Generates the implementation of the library into the included file. -* If not defined, the library is in header only mode and can be included in other headers -* or source files without problems. But only ONE file should hold the implementation. -* -* #define PHYSAC_STATIC (defined by default) -* 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 -* -* #define PHYSAC_MALLOC() -* #define PHYSAC_FREE() -* You can define your own malloc/free implementation replacing stdlib.h malloc()/free() functions. -* Otherwise it will include stdlib.h and use the C standard library malloc()/free() function. -* -* -* 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: -* gcc -o $(NAME_PART).exe $(FILE_NAME) -s -static -lraylib -lpthread -lopengl32 -lgdi32 -lwinmm -std=c99 -* -* VERY THANKS TO: -* Ramon Santamaria (github: @raysan5) -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2016-2018 Victor Fisac (github: @victorfisac) -* -* This software is provided "as-is", without any express or implied warranty. In no event -* will the authors be held liable for any damages arising from the use of this software. -* -* Permission is granted to anyone to use this software for any purpose, including commercial -* applications, and to alter it and redistribute it freely, subject to the following restrictions: -* -* 1. The origin of this software must not be misrepresented; you must not claim that you -* wrote the original software. If you use this software in a product, an acknowledgment -* in the product documentation would be appreciated but is not required. -* -* 2. Altered source versions must be plainly marked as such, and must not be misrepresented -* as being the original software. -* -* 3. This notice may not be removed or altered from any source distribution. -* -**********************************************************************************************/ - -#if !defined(PHYSAC_H) -#define PHYSAC_H - -#if defined(PHYSAC_STATIC) - #define PHYSACDEF static // Functions just visible to module including this file -#else - #if defined(__cplusplus) - #define PHYSACDEF extern "C" // Functions visible from other files (no name mangling of functions in C++) - #else - #define PHYSACDEF extern // Functions visible from other files - #endif -#endif - -// Allow custom memory allocators -#ifndef PHYSAC_MALLOC - #define PHYSAC_MALLOC(size) malloc(size) -#endif -#ifndef PHYSAC_FREE - #define PHYSAC_FREE(ptr) free(ptr) -#endif - -//---------------------------------------------------------------------------------- -// 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_COLLISION_ITERATIONS 100 -#define PHYSAC_PENETRATION_ALLOWANCE 0.05f -#define PHYSAC_PENETRATION_CORRECTION 0.4f - -#define PHYSAC_PI 3.14159265358979323846 -#define PHYSAC_DEG2RAD (PHYSAC_PI/180.0f) - -//---------------------------------------------------------------------------------- -// 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 <stdbool.h> - #elif !defined(__cplusplus) && !defined(bool) - typedef enum { false, true } bool; - #endif - - // Vector2 type - typedef struct Vector2 { - float x; - float y; - } Vector2; -#endif - -typedef enum PhysicsShapeType { PHYSICS_CIRCLE, PHYSICS_POLYGON } PhysicsShapeType; - -// Previously defined to be used in PhysicsShape struct as circular dependencies -typedef struct PhysicsBodyData *PhysicsBody; - -#if defined(__cplusplus) -extern "C" { // Prevents name mangling of functions -#endif - -//---------------------------------------------------------------------------------- -// 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 -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 -PHYSACDEF PhysicsBody CreatePhysicsBodyCircle(Vector2 pos, float radius, float density); // Creates a new circle physics body with generic parameters -PHYSACDEF PhysicsBody CreatePhysicsBodyRectangle(Vector2 pos, float width, float height, float density); // Creates a new rectangle physics body with generic parameters -PHYSACDEF PhysicsBody CreatePhysicsBodyPolygon(Vector2 pos, float radius, int sides, float density); // Creates a new polygon physics body with generic parameters -PHYSACDEF void PhysicsAddForce(PhysicsBody body, Vector2 force); // Adds a force to a physics body -PHYSACDEF void PhysicsAddTorque(PhysicsBody body, float amount); // Adds an angular force to a physics body -PHYSACDEF void PhysicsShatter(PhysicsBody body, Vector2 position, float force); // Shatters a polygon shape physics body to little physics bodies with explosion force -PHYSACDEF int GetPhysicsBodiesCount(void); // Returns the current amount of created physics bodies -PHYSACDEF PhysicsBody GetPhysicsBody(int index); // Returns a physics body of the bodies pool at a specific index -PHYSACDEF int GetPhysicsShapeType(int index); // Returns the physics body shape type (PHYSICS_CIRCLE or PHYSICS_POLYGON) -PHYSACDEF int GetPhysicsShapeVerticesCount(int index); // Returns the amount of vertices of a physics body shape -PHYSACDEF Vector2 GetPhysicsShapeVertex(PhysicsBody body, int vertex); // Returns transformed position of a body shape (body position + vertex transformed position) -PHYSACDEF void SetPhysicsBodyRotation(PhysicsBody body, float radians); // Sets physics body shape transform based on radians parameter -PHYSACDEF void DestroyPhysicsBody(PhysicsBody body); // Unitializes and destroy a physics body -PHYSACDEF void ResetPhysics(void); // Destroys created physics bodies and manifolds and resets global values -PHYSACDEF void ClosePhysics(void); // Unitializes physics pointers and closes physics loop thread - -#if defined(__cplusplus) -} -#endif - -#endif // PHYSAC_H - -/*********************************************************************************** -* -* PHYSAC IMPLEMENTATION -* -************************************************************************************/ - -#if defined(PHYSAC_IMPLEMENTATION) - -#if !defined(PHYSAC_NO_THREADS) - #include <pthread.h> // Required for: pthread_t, pthread_create() -#endif - -#if defined(PHYSAC_DEBUG) - -#endif - -// Support TRACELOG macros -#if defined(PHYSAC_DEBUG) - #include <stdio.h> // Required for: printf() - #define TRACELOG(...) printf(__VA_ARGS__) -#else - #define TRACELOG(...) (void)0 -#endif - -#include <stdlib.h> // Required for: malloc(), free(), srand(), rand() -#include <math.h> // Required for: cosf(), sinf(), fabs(), sqrtf() - -#if !defined(PHYSAC_STANDALONE) - #include "raymath.h" // Required for: Vector2Add(), Vector2Subtract() -#endif - -// Time management functionality -#include <time.h> // 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 <sys/time.h> // Required for: timespec -#elif defined(__APPLE__) // macOS also defines __MACH__ - #include <mach/mach_time.h> // Required for: mach_absolute_time() -#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 } - -//---------------------------------------------------------------------------------- -// Data Types Structure Definition -//---------------------------------------------------------------------------------- - -// Matrix2x2 type (used for polygon shape rotation matrix) -typedef struct Matrix2x2 { - float m00; - float m01; - float m10; - 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 PhysicsShape { - PhysicsShapeType type; // Physics shape type (circle or polygon) - PhysicsBody body; // Shape physics body reference - float radius; // Circle 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 - bool enabled; // Enabled dynamics state (collisions are calculated anyway) - Vector2 position; // Physics body shape pivot - Vector2 velocity; // Current linear velocity applied to position - Vector2 force; // Current linear force (reset to 0 every step) - float angularVelocity; // Current angular velocity applied to orient - float torque; // Current angular force (reset to 0 every step) - float orient; // Rotation in radians - float inertia; // Moment of inertia - float inverseInertia; // Inverse value of inertia - float mass; // Physics body mass - float inverseMass; // Inverse value of mass - float staticFriction; // Friction when the body has not movement (0 to 1) - float dynamicFriction; // Friction when the body has movement (0 to 1) - float restitution; // Restitution coefficient of the body (0 to 1) - bool useGravity; // Apply gravity force to dynamics - bool isGrounded; // Physics grounded on other body state - bool freezeOrient; // Physics rotation constraint - PhysicsShape shape; // Physics body shape information (type, radius, vertices, normals) -} PhysicsBodyData; - -typedef struct PhysicsManifoldData { - unsigned int id; // Reference unique identifier - PhysicsBody bodyA; // Manifold first physics body reference - PhysicsBody bodyB; // Manifold second physics body reference - float penetration; // Depth of penetration from collision - Vector2 normal; // Normal direction vector from 'a' to 'b' - Vector2 contacts[2]; // Points of contact during collision - unsigned int contactsCount; // Current collision number of contacts - float restitution; // Mixed restitution during collision - float dynamicFriction; // Mixed dynamic friction during collision - float staticFriction; // Mixed static friction during collision -} PhysicsManifoldData, *PhysicsManifold; - -//---------------------------------------------------------------------------------- -// 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 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 -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 - -//---------------------------------------------------------------------------------- -// Module Internal Functions Declaration -//---------------------------------------------------------------------------------- -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 PhysicsManifold CreatePhysicsManifold(PhysicsBody a, PhysicsBody b); // Creates a new physics manifold to solve collision -static void DestroyPhysicsManifold(PhysicsManifold manifold); // Unitializes and destroys a physics manifold -static void SolvePhysicsManifold(PhysicsManifold manifold); // Solves a created physics manifold between two physics bodies -static void SolveCircleToCircle(PhysicsManifold manifold); // Solves collision between two circle shape physics bodies -static void SolveCircleToPolygon(PhysicsManifold manifold); // Solves collision between a circle to a polygon shape physics bodies -static void SolvePolygonToCircle(PhysicsManifold manifold); // Solves collision between a polygon to a circle shape physics bodies -static void SolvePolygonToPolygon(PhysicsManifold manifold); // Solves collision between two polygons shape physics bodies -static void IntegratePhysicsForces(PhysicsBody body); // Integrates physics forces into velocity -static void InitializePhysicsManifolds(PhysicsManifold manifold); // Initializes physics manifolds to solve collisions -static void IntegratePhysicsImpulses(PhysicsManifold manifold); // Integrates physics collisions impulses to solve collisions -static void IntegratePhysicsVelocity(PhysicsBody body); // Integrates physics velocity into position and forces -static void CorrectPhysicsPositions(PhysicsManifold manifold); // Corrects physics bodies positions based on manifolds collision information -static float FindAxisLeastPenetration(int *faceIndex, PhysicsShape shapeA, PhysicsShape shapeB); // Finds polygon shapes axis least penetration -static void FindIncidentFace(Vector2 *v0, Vector2 *v1, PhysicsShape ref, PhysicsShape inc, int index); // Finds two polygon shapes incident face -static int Clip(Vector2 normal, float clip, Vector2 *faceA, Vector2 *faceB); // Calculates clipping based on a normal and two faces -static bool BiasGreaterThan(float valueA, float valueB); // Check if values are between bias range -static Vector2 TriangleBarycenter(Vector2 v1, Vector2 v2, Vector2 v3); // Returns the barycenter of a triangle given by 3 points - -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 - -//---------------------------------------------------------------------------------- -// 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 - - // Initialize high resolution timer - InitTimer(); - - #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; -} - -// Sets physics global gravity force -PHYSACDEF void SetPhysicsGravity(float x, float y) -{ - gravityForce.x = x; - gravityForce.y = 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; -} - -// 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)); - usedMemory += sizeof(PhysicsBodyData); - - int newId = FindAvailableBodyIndex(); - if (newId != -1) - { - // Initialize new body with generic values - newBody->id = newId; - newBody->enabled = true; - newBody->position = pos; - newBody->velocity = (Vector2){ 0.0f }; - newBody->force = (Vector2){ 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 }); - - // 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++) - { - // 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]; - - float D = MathCrossVector2(p1, p2); - float triangleArea = D/2; - - area += triangleArea; - - // Use area to weight the centroid average, not just vertex position - center.x += triangleArea*PHYSAC_K*(p1.x + p2.x); - center.y += triangleArea*PHYSAC_K*(p1.y + p2.y); - - float intx2 = p1.x*p1.x + p2.x*p1.x + p2.x*p2.x; - float inty2 = p1.y*p1.y + p2.y*p1.y + p2.y*p2.y; - inertia += (0.25f*PHYSAC_K*D)*(intx2 + inty2); - } - - center.x *= 1.0f/area; - center.y *= 1.0f/area; - - // Translate vertices to centroid (make the centroid (0, 0) for the polygon in model space) - // Note: this is not really necessary - for (int i = 0; i < newBody->shape.vertexData.vertexCount; i++) - { - newBody->shape.vertexData.positions[i].x -= center.x; - newBody->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; - - // Add new body to bodies pointers array and update bodies count - bodies[physicsBodiesCount] = newBody; - physicsBodiesCount++; - - #if defined(PHYSAC_DEBUG) - TRACELOG("[PHYSAC] created polygon physics body id %i\n", newBody->id); - #endif - } - #if defined(PHYSAC_DEBUG) - else TRACELOG("[PHYSAC] new physics body creation failed because there is any available id to use\n"); - #endif - - return newBody; -} - -// 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)); - usedMemory += sizeof(PhysicsBodyData); - - int newId = FindAvailableBodyIndex(); - if (newId != -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); - - // 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++) - { - // 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]; - - float cross = MathCrossVector2(position1, position2); - float triangleArea = cross/2; - - area += triangleArea; - - // Use area to weight the centroid average, not just vertex position - center.x += triangleArea*PHYSAC_K*(position1.x + position2.x); - center.y += triangleArea*PHYSAC_K*(position1.y + position2.y); - - float intx2 = position1.x*position1.x + position2.x*position1.x + position2.x*position2.x; - float inty2 = position1.y*position1.y + position2.y*position1.y + position2.y*position2.y; - inertia += (0.25f*PHYSAC_K*cross)*(intx2 + inty2); - } - - center.x *= 1.0f/area; - center.y *= 1.0f/area; - - // Translate vertices to centroid (make the centroid (0, 0) for the polygon in model space) - // Note: this is not really necessary - for (int i = 0; i < newBody->shape.vertexData.vertexCount; i++) - { - newBody->shape.vertexData.positions[i].x -= center.x; - newBody->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; - - // Add new body to bodies pointers array and update bodies count - bodies[physicsBodiesCount] = newBody; - physicsBodiesCount++; - - #if defined(PHYSAC_DEBUG) - TRACELOG("[PHYSAC] created polygon physics body id %i\n", newBody->id); - #endif - } - #if defined(PHYSAC_DEBUG) - else TRACELOG("[PHYSAC] new physics body creation failed because there is any available id to use\n"); - #endif - - return newBody; -} - -// Adds a force to a physics body -PHYSACDEF void PhysicsAddForce(PhysicsBody body, Vector2 force) -{ - if (body != NULL) body->force = Vector2Add(body->force, force); -} - -// Adds an angular force to a physics body -PHYSACDEF void PhysicsAddTorque(PhysicsBody body, float amount) -{ - if (body != NULL) body->torque += amount; -} - -// Shatters a polygon shape physics body to little physics bodies with explosion force -PHYSACDEF void PhysicsShatter(PhysicsBody body, Vector2 position, float force) -{ - if (body != NULL) - { - if (body->shape.type == PHYSICS_POLYGON) - { - PolygonData 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])); - int nextIndex = (((i + 1) < vertexData.vertexCount) ? (i + 1) : 0); - Vector2 positionC = Mat2MultiplyVector2(body->shape.transform, Vector2Add(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))/ - ((positionB.y - positionC.y)*(positionA.x - positionC.x) + (positionC.x - positionB.x)*(positionA.y - positionC.y)); - - float beta = ((positionC.y - positionA.y)*(position.x - positionC.x) + (positionA.x - positionC.x)*(position.y - positionC.y))/ - ((positionB.y - positionC.y)*(positionA.x - positionC.x) + (positionC.x - positionB.x)*(positionA.y - positionC.y)); - - float gamma = 1.0f - alpha - beta; - - if ((alpha > 0.0f) && (beta > 0.0f) & (gamma > 0.0f)) - { - collision = true; - break; - } - } - - if (collision) - { - int count = vertexData.vertexCount; - Vector2 bodyPos = body->position; - Vector2 *vertices = (Vector2 *)PHYSAC_MALLOC(sizeof(Vector2)*count); - Matrix2x2 trans = body->shape.transform; - for (int i = 0; i < count; i++) vertices[i] = vertexData.positions[i]; - - // Destroy shattered physics body - DestroyPhysicsBody(body); - - 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); - - PhysicsBody newBody = CreatePhysicsBodyPolygon(center, 10, 3, 10); // Create polygon physics body with relevant values - - PolygonData newData = { 0 }; - newData.vertexCount = 3; - - newData.positions[0] = Vector2Subtract(vertices[i], offset); - newData.positions[1] = Vector2Subtract(vertices[nextIndex], offset); - newData.positions[2] = Vector2Subtract(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; - - // Calculate polygon faces normals - for (int j = 0; j < newData.vertexCount; j++) - { - int nextVertex = (((j + 1) < newData.vertexCount) ? (j + 1) : 0); - Vector2 face = Vector2Subtract(newData.positions[nextVertex], newData.positions[j]); - - newData.normals[j] = (Vector2){ face.y, -face.x }; - MathNormalize(&newData.normals[j]); - } - - // Apply computed vertex data to new physics body shape - newBody->shape.vertexData = newData; - newBody->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++) - { - // 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]; - - float D = MathCrossVector2(p1, p2); - float triangleArea = D/2; - - area += triangleArea; - - // Use area to weight the centroid average, not just vertex position - center.x += triangleArea*PHYSAC_K*(p1.x + p2.x); - center.y += triangleArea*PHYSAC_K*(p1.y + p2.y); - - float intx2 = p1.x*p1.x + p2.x*p1.x + p2.x*p2.x; - float inty2 = p1.y*p1.y + p2.y*p1.y + p2.y*p2.y; - inertia += (0.25f*PHYSAC_K*D)*(intx2 + inty2); - } - - center.x *= 1.0f/area; - center.y *= 1.0f/area; - - newBody->mass = area; - newBody->inverseMass = ((newBody->mass != 0.0f) ? 1.0f/newBody->mass : 0.0f); - newBody->inertia = inertia; - newBody->inverseInertia = ((newBody->inertia != 0.0f) ? 1.0f/newBody->inertia : 0.0f); - - // Calculate explosion force direction - Vector2 pointA = newBody->position; - Vector2 pointB = Vector2Subtract(newData.positions[1], newData.positions[0]); - pointB.x /= 2.0f; - pointB.y /= 2.0f; - Vector2 forceDirection = Vector2Subtract(Vector2Add(pointA, Vector2Add(newData.positions[0], pointB)), newBody->position); - MathNormalize(&forceDirection); - forceDirection.x *= force; - forceDirection.y *= force; - - // Apply force to new physics body - PhysicsAddForce(newBody, forceDirection); - } - - PHYSAC_FREE(vertices); - } - } - } - #if defined(PHYSAC_DEBUG) - else TRACELOG("[PHYSAC] error when trying to shatter a null reference physics body"); - #endif -} - -// Returns the current amount of created physics bodies -PHYSACDEF int GetPhysicsBodiesCount(void) -{ - return physicsBodiesCount; -} - -// Returns a physics body of the bodies pool at a specific index -PHYSACDEF PhysicsBody GetPhysicsBody(int index) -{ - PhysicsBody body = NULL; - - if (index < physicsBodiesCount) - { - body = bodies[index]; - - if (body == NULL) - { - #if defined(PHYSAC_DEBUG) - TRACELOG("[PHYSAC] error when trying to get a null reference physics body"); - #endif - } - } - #if defined(PHYSAC_DEBUG) - else TRACELOG("[PHYSAC] physics body index is out of bounds"); - #endif - - return body; -} - -// Returns the physics body shape type (PHYSICS_CIRCLE or PHYSICS_POLYGON) -PHYSACDEF int GetPhysicsShapeType(int index) -{ - int result = -1; - - if (index < physicsBodiesCount) - { - 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 - } - #if defined(PHYSAC_DEBUG) - else TRACELOG("[PHYSAC] physics body index is out of bounds"); - #endif - - return result; -} - -// Returns the amount of vertices of a physics body shape -PHYSACDEF int GetPhysicsShapeVerticesCount(int index) -{ - int result = 0; - - if (index < physicsBodiesCount) - { - PhysicsBody body = bodies[index]; - - if (body != NULL) - { - switch (body->shape.type) - { - case PHYSICS_CIRCLE: result = PHYSAC_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 - } - #if defined(PHYSAC_DEBUG) - else TRACELOG("[PHYSAC] physics body index is out of bounds"); - #endif - - return result; -} - -// Returns transformed position of a body shape (body position + vertex transformed position) -PHYSACDEF Vector2 GetPhysicsShapeVertex(PhysicsBody body, int vertex) -{ - Vector2 position = { 0.0f, 0.0f }; - - if (body != NULL) - { - switch (body->shape.type) - { - 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; - } break; - case PHYSICS_POLYGON: - { - PolygonData vertexData = body->shape.vertexData; - position = Vector2Add(body->position, Mat2MultiplyVector2(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 - - return position; -} - -// Sets physics body shape transform based on radians parameter -PHYSACDEF void SetPhysicsBodyRotation(PhysicsBody body, float radians) -{ - if (body != NULL) - { - body->orient = radians; - - if (body->shape.type == PHYSICS_POLYGON) body->shape.transform = Mat2Radians(radians); - } -} - -// Unitializes and destroys a physics body -PHYSACDEF void DestroyPhysicsBody(PhysicsBody body) -{ - if (body != NULL) - { - int id = body->id; - int index = -1; - - for (int i = 0; i < physicsBodiesCount; i++) - { - if (bodies[i]->id == id) - { - index = i; - break; - } - } - - if (index == -1) - { - #if defined(PHYSAC_DEBUG) - TRACELOG("[PHYSAC] Not possible to find body id %i in pointers array\n", id); - #endif - return; // Prevent access to index -1 - } - - // Free body allocated memory - PHYSAC_FREE(body); - usedMemory -= sizeof(PhysicsBodyData); - bodies[index] = NULL; - - // Reorder physics bodies pointers array and its catched index - for (int i = index; i < physicsBodiesCount; i++) - { - if ((i + 1) < physicsBodiesCount) bodies[i] = bodies[i + 1]; - } - - // Update physics bodies count - physicsBodiesCount--; - - #if defined(PHYSAC_DEBUG) - TRACELOG("[PHYSAC] destroyed physics body id %i\n", id); - #endif - } - #if defined(PHYSAC_DEBUG) - else TRACELOG("[PHYSAC] error trying to destroy a null referenced body\n"); - #endif -} - -// Destroys created physics bodies and manifolds and resets global values -PHYSACDEF void ResetPhysics(void) -{ - // Unitialize physics bodies dynamic memory allocations - for (int i = physicsBodiesCount - 1; i >= 0; i--) - { - PhysicsBody body = bodies[i]; - - if (body != NULL) - { - PHYSAC_FREE(body); - bodies[i] = NULL; - usedMemory -= sizeof(PhysicsBodyData); - } - } - - physicsBodiesCount = 0; - - // Unitialize physics manifolds dynamic memory allocations - for (int i = physicsManifoldsCount - 1; i >= 0; i--) - { - PhysicsManifold manifold = contacts[i]; - - if (manifold != NULL) - { - PHYSAC_FREE(manifold); - contacts[i] = NULL; - usedMemory -= sizeof(PhysicsManifoldData); - } - } - - physicsManifoldsCount = 0; - - #if defined(PHYSAC_DEBUG) - TRACELOG("[PHYSAC] physics module reset successfully\n"); - #endif -} - -// Unitializes physics pointers and exits physics loop thread -PHYSACDEF void ClosePhysics(void) -{ - // Exit physics loop thread - physicsThreadEnabled = false; - - #if !defined(PHYSAC_NO_THREADS) - pthread_join(physicsThreadId, NULL); - #endif - - // 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 -} - -//---------------------------------------------------------------------------------- -// Module Internal Functions Definition -//---------------------------------------------------------------------------------- -// Finds a valid index for a new physics body initialization -static int FindAvailableBodyIndex() -{ - int index = -1; - for (int i = 0; i < PHYSAC_MAX_BODIES; i++) - { - int currentId = i; - - // Check if current id already exist in other physics body - for (int k = 0; k < physicsBodiesCount; k++) - { - if (bodies[k]->id == currentId) - { - currentId++; - break; - } - } - - // If it is not used, use it as new physics body id - if (currentId == i) - { - index = i; - break; - } - } - - return index; -} - -// Creates a random polygon shape with max vertex distance from polygon pivot -static PolygonData CreateRandomPolygon(float radius, int sides) -{ - PolygonData data = { 0 }; - data.vertexCount = sides; - - // Calculate polygon vertices positions - for (int i = 0; i < data.vertexCount; i++) - { - data.positions[i].x = cosf(360.0f/sides*i*PHYSAC_DEG2RAD)*radius; - data.positions[i].y = sinf(360.0f/sides*i*PHYSAC_DEG2RAD)*radius; - } - - // Calculate polygon faces normals - 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]); - - data.normals[i] = (Vector2){ face.y, -face.x }; - MathNormalize(&data.normals[i]); - } - - return data; -} - -// Creates a rectangle polygon shape based on a min and max positions -static PolygonData CreateRectanglePolygon(Vector2 pos, Vector2 size) -{ - PolygonData data = { 0 }; - data.vertexCount = 4; - - // Calculate polygon vertices positions - 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 }; - - // 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]); - - data.normals[i] = (Vector2){ face.y, -face.x }; - MathNormalize(&data.normals[i]); - } - - return data; -} - -// Physics loop thread function -static void *PhysicsLoop(void *arg) -{ -#if !defined(PHYSAC_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--) - { - PhysicsManifold manifold = contacts[i]; - if (manifold != NULL) DestroyPhysicsManifold(manifold); - } - - // Reset physics bodies grounded state - for (int i = 0; i < physicsBodiesCount; i++) - { - PhysicsBody body = bodies[i]; - body->isGrounded = false; - } - - // Generate new collision information - for (int i = 0; i < physicsBodiesCount; i++) - { - PhysicsBody bodyA = bodies[i]; - - if (bodyA != NULL) - { - for (int j = i + 1; j < physicsBodiesCount; j++) - { - PhysicsBody bodyB = bodies[j]; - - if (bodyB != NULL) - { - if ((bodyA->inverseMass == 0) && (bodyB->inverseMass == 0)) continue; - - PhysicsManifold manifold = CreatePhysicsManifold(bodyA, bodyB); - SolvePhysicsManifold(manifold); - - if (manifold->contactsCount > 0) - { - // Create a new manifold with same information as previously solved manifold and add it to the manifolds pool last slot - PhysicsManifold newManifold = CreatePhysicsManifold(bodyA, bodyB); - newManifold->penetration = manifold->penetration; - newManifold->normal = manifold->normal; - newManifold->contacts[0] = manifold->contacts[0]; - newManifold->contacts[1] = manifold->contacts[1]; - newManifold->contactsCount = manifold->contactsCount; - newManifold->restitution = manifold->restitution; - newManifold->dynamicFriction = manifold->dynamicFriction; - newManifold->staticFriction = manifold->staticFriction; - } - } - } - } - } - - // Integrate forces to physics bodies - for (int i = 0; i < physicsBodiesCount; i++) - { - PhysicsBody body = bodies[i]; - if (body != NULL) IntegratePhysicsForces(body); - } - - // Initialize physics manifolds to solve collisions - for (int i = 0; i < physicsManifoldsCount; i++) - { - PhysicsManifold manifold = contacts[i]; - if (manifold != NULL) InitializePhysicsManifolds(manifold); - } - - // Integrate physics collisions impulses to solve collisions - for (int i = 0; i < PHYSAC_COLLISION_ITERATIONS; i++) - { - for (int j = 0; j < physicsManifoldsCount; j++) - { - PhysicsManifold manifold = contacts[i]; - if (manifold != NULL) IntegratePhysicsImpulses(manifold); - } - } - - // Integrate velocity to physics bodies - for (int i = 0; i < physicsBodiesCount; i++) - { - PhysicsBody body = bodies[i]; - if (body != NULL) IntegratePhysicsVelocity(body); - } - - // Correct physics bodies positions based on manifolds collision information - for (int i = 0; i < physicsManifoldsCount; i++) - { - PhysicsManifold manifold = contacts[i]; - if (manifold != NULL) CorrectPhysicsPositions(manifold); - } - - // Clear physics bodies forces - for (int i = 0; i < physicsBodiesCount; i++) - { - PhysicsBody body = bodies[i]; - if (body != NULL) - { - body->force = PHYSAC_VECTOR_ZERO; - body->torque = 0.0f; - } - } -} - -// Wrapper to ensure PhysicsStep is run with at a fixed time step -PHYSACDEF void RunPhysicsStep(void) -{ - // Calculate current time - currentTime = GetCurrentTime(); - - // Calculate current delta time - const double delta = currentTime - startTime; - - // Store the time elapsed since the last frame began - accumulator += delta; - - // Fixed time stepping loop - while (accumulator >= 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; - } - - // Record the starting of this frame - startTime = currentTime; -} - -PHYSACDEF void SetPhysicsTimeStep(double delta) -{ - deltaTime = delta; -} - -// Finds a valid index for a new manifold initialization -static int FindAvailableManifoldIndex() -{ - int index = -1; - for (int i = 0; i < PHYSAC_MAX_MANIFOLDS; i++) - { - int currentId = i; - - // Check if current id already exist in other physics body - for (int k = 0; k < physicsManifoldsCount; k++) - { - if (contacts[k]->id == currentId) - { - currentId++; - break; - } - } - - // If it is not used, use it as new physics body id - if (currentId == i) - { - index = i; - break; - } - } - - return index; -} - -// Creates a new physics manifold to solve collision -static PhysicsManifold CreatePhysicsManifold(PhysicsBody a, PhysicsBody b) -{ - PhysicsManifold newManifold = (PhysicsManifold)PHYSAC_MALLOC(sizeof(PhysicsManifoldData)); - usedMemory += sizeof(PhysicsManifoldData); - - int newId = FindAvailableManifoldIndex(); - if (newId != -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; - - // Add new body to bodies pointers array and update bodies count - contacts[physicsManifoldsCount] = newManifold; - physicsManifoldsCount++; - } - #if defined(PHYSAC_DEBUG) - else TRACELOG("[PHYSAC] new physics manifold creation failed because there is any available id to use\n"); - #endif - - return newManifold; -} - -// Unitializes and destroys a physics manifold -static void DestroyPhysicsManifold(PhysicsManifold manifold) -{ - if (manifold != NULL) - { - int id = manifold->id; - int index = -1; - - for (int i = 0; i < physicsManifoldsCount; i++) - { - if (contacts[i]->id == id) - { - index = i; - break; - } - } - - 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 - } - - // Free manifold allocated memory - PHYSAC_FREE(manifold); - usedMemory -= sizeof(PhysicsManifoldData); - contacts[index] = NULL; - - // Reorder physics manifolds pointers array and its catched index - for (int i = index; i < physicsManifoldsCount; i++) - { - if ((i + 1) < physicsManifoldsCount) contacts[i] = contacts[i + 1]; - } - - // Update physics manifolds count - physicsManifoldsCount--; - } - #if defined(PHYSAC_DEBUG) - else TRACELOG("[PHYSAC] error trying to destroy a null referenced manifold\n"); - #endif -} - -// Solves a created physics manifold between two physics bodies -static void SolvePhysicsManifold(PhysicsManifold manifold) -{ - switch (manifold->bodyA->shape.type) - { - case PHYSICS_CIRCLE: - { - switch (manifold->bodyB->shape.type) - { - case PHYSICS_CIRCLE: SolveCircleToCircle(manifold); break; - case PHYSICS_POLYGON: SolveCircleToPolygon(manifold); break; - default: break; - } - } break; - case PHYSICS_POLYGON: - { - switch (manifold->bodyB->shape.type) - { - case PHYSICS_CIRCLE: SolvePolygonToCircle(manifold); break; - case PHYSICS_POLYGON: SolvePolygonToPolygon(manifold); break; - default: break; - } - } break; - default: break; - } - - // Update physics body grounded state if normal direction is down and grounded state is not set yet in previous manifolds - if (!manifold->bodyB->isGrounded) manifold->bodyB->isGrounded = (manifold->normal.y < 0); -} - -// Solves collision between two circle shape physics bodies -static void SolveCircleToCircle(PhysicsManifold manifold) -{ - PhysicsBody bodyA = manifold->bodyA; - PhysicsBody bodyB = manifold->bodyB; - - if ((bodyA == NULL) || (bodyB == NULL)) return; - - // Calculate translational vector, which is normal - Vector2 normal = Vector2Subtract(bodyB->position, bodyA->position); - - float distSqr = MathLenSqr(normal); - float radius = bodyA->shape.radius + bodyB->shape.radius; - - // Check if circles are not in contact - if (distSqr >= radius*radius) - { - manifold->contactsCount = 0; - return; - } - - float distance = sqrtf(distSqr); - manifold->contactsCount = 1; - - if (distance == 0.0f) - { - manifold->penetration = bodyA->shape.radius; - manifold->normal = (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 }; - } - - // Update physics body grounded state if normal direction is down - if (!bodyA->isGrounded) bodyA->isGrounded = (manifold->normal.y < 0); -} - -// Solves collision between a circle to a polygon shape physics bodies -static void SolveCircleToPolygon(PhysicsManifold manifold) -{ - PhysicsBody bodyA = manifold->bodyA; - PhysicsBody bodyB = manifold->bodyB; - - if ((bodyA == NULL) || (bodyB == NULL)) return; - - manifold->contactsCount = 0; - - // Transform circle center to polygon transform space - Vector2 center = bodyA->position; - center = Mat2MultiplyVector2(Mat2Transpose(bodyB->shape.transform), Vector2Subtract(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; - - for (int i = 0; i < vertexData.vertexCount; i++) - { - float currentSeparation = MathDot(vertexData.normals[i], Vector2Subtract(center, vertexData.positions[i])); - - if (currentSeparation > bodyA->shape.radius) return; - - if (currentSeparation > separation) - { - separation = currentSeparation; - faceNormal = i; - } - } - - // Grab face's vertices - Vector2 v1 = vertexData.positions[faceNormal]; - int nextIndex = (((faceNormal + 1) < vertexData.vertexCount) ? (faceNormal + 1) : 0); - Vector2 v2 = vertexData.positions[nextIndex]; - - // Check to see if center is within polygon - 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 }; - manifold->penetration = bodyA->shape.radius; - return; - } - - // Determine which voronoi region of the edge center of circle lies within - float dot1 = MathDot(Vector2Subtract(center, v1), Vector2Subtract(v2, v1)); - float dot2 = MathDot(Vector2Subtract(center, v2), Vector2Subtract(v1, v2)); - manifold->penetration = bodyA->shape.radius - separation; - - if (dot1 <= 0.0f) // Closest to v1 - { - if (DistSqr(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); - manifold->normal = normal; - v1 = Mat2MultiplyVector2(bodyB->shape.transform, v1); - v1 = Vector2Add(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; - - manifold->contactsCount = 1; - Vector2 normal = Vector2Subtract(v2, center); - v2 = Mat2MultiplyVector2(bodyB->shape.transform, v2); - v2 = Vector2Add(v2, bodyB->position); - manifold->contacts[0] = v2; - normal = Mat2MultiplyVector2(bodyB->shape.transform, normal); - MathNormalize(&normal); - manifold->normal = normal; - } - else // Closest to face - { - Vector2 normal = vertexData.normals[faceNormal]; - - if (MathDot(Vector2Subtract(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 }; - manifold->contactsCount = 1; - } -} - -// Solves collision between a polygon to a circle shape physics bodies -static void SolvePolygonToCircle(PhysicsManifold manifold) -{ - PhysicsBody bodyA = manifold->bodyA; - PhysicsBody bodyB = manifold->bodyB; - - if ((bodyA == NULL) || (bodyB == NULL)) return; - - manifold->bodyA = bodyB; - manifold->bodyB = bodyA; - SolveCircleToPolygon(manifold); - - manifold->normal.x *= -1.0f; - manifold->normal.y *= -1.0f; -} - -// Solves collision between two polygons shape physics bodies -static void SolvePolygonToPolygon(PhysicsManifold manifold) -{ - if ((manifold->bodyA == NULL) || (manifold->bodyB == NULL)) return; - - PhysicsShape bodyA = manifold->bodyA->shape; - PhysicsShape bodyB = manifold->bodyB->shape; - manifold->contactsCount = 0; - - // Check for separating axis with A shape's face planes - int faceA = 0; - float penetrationA = FindAxisLeastPenetration(&faceA, bodyA, bodyB); - if (penetrationA >= 0.0f) return; - - // Check for separating axis with B shape's face planes - int faceB = 0; - float penetrationB = FindAxisLeastPenetration(&faceB, bodyB, bodyA); - if (penetrationB >= 0.0f) return; - - int referenceIndex = 0; - bool flip = false; // Always point from A shape to B shape - - PhysicsShape refPoly; // Reference - PhysicsShape incPoly; // Incident - - // Determine which shape contains reference face - if (BiasGreaterThan(penetrationA, penetrationB)) - { - refPoly = bodyA; - incPoly = bodyB; - referenceIndex = faceA; - } - else - { - refPoly = bodyB; - incPoly = bodyA; - referenceIndex = faceB; - flip = true; - } - - // World space incident face - Vector2 incidentFace[2]; - FindIncidentFace(&incidentFace[0], &incidentFace[1], refPoly, incPoly, referenceIndex); - - // Setup reference face vertices - PolygonData refData = refPoly.vertexData; - 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); - - // Calculate reference face side normal in world space - Vector2 sidePlaneNormal = Vector2Subtract(v2, v1); - MathNormalize(&sidePlaneNormal); - - // Orthogonalize - Vector2 refFaceNormal = { sidePlaneNormal.y, -sidePlaneNormal.x }; - float refC = MathDot(refFaceNormal, v1); - float negSide = MathDot(sidePlaneNormal, v1)*-1; - float posSide = MathDot(sidePlaneNormal, v2); - - // Clip incident face to reference face side planes (due to floating point error, possible to not have required points - if (Clip((Vector2){ -sidePlaneNormal.x, -sidePlaneNormal.y }, negSide, &incidentFace[0], &incidentFace[1]) < 2) return; - if (Clip(sidePlaneNormal, posSide, &incidentFace[0], &incidentFace[1]) < 2) return; - - // Flip normal if required - manifold->normal = (flip ? (Vector2){ -refFaceNormal.x, -refFaceNormal.y } : refFaceNormal); - - // Keep points behind reference face - int currentPoint = 0; // Clipped points behind reference face - float separation = MathDot(refFaceNormal, incidentFace[0]) - refC; - if (separation <= 0.0f) - { - manifold->contacts[currentPoint] = incidentFace[0]; - manifold->penetration = -separation; - currentPoint++; - } - else manifold->penetration = 0.0f; - - separation = MathDot(refFaceNormal, incidentFace[1]) - refC; - - if (separation <= 0.0f) - { - manifold->contacts[currentPoint] = incidentFace[1]; - manifold->penetration += -separation; - currentPoint++; - - // Calculate total penetration average - manifold->penetration /= currentPoint; - } - - manifold->contactsCount = currentPoint; -} - -// Integrates physics forces into velocity -static void IntegratePhysicsForces(PhysicsBody body) -{ - if ((body == NULL) || (body->inverseMass == 0.0f) || !body->enabled) return; - - body->velocity.x += (body->force.x*body->inverseMass)*(deltaTime/2.0); - body->velocity.y += (body->force.y*body->inverseMass)*(deltaTime/2.0); - - if (body->useGravity) - { - body->velocity.x += gravityForce.x*(deltaTime/1000/2.0); - body->velocity.y += gravityForce.y*(deltaTime/1000/2.0); - } - - if (!body->freezeOrient) body->angularVelocity += body->torque*body->inverseInertia*(deltaTime/2.0); -} - -// Initializes physics manifolds to solve collisions -static void InitializePhysicsManifolds(PhysicsManifold manifold) -{ - PhysicsBody bodyA = manifold->bodyA; - PhysicsBody bodyB = manifold->bodyB; - - if ((bodyA == NULL) || (bodyB == NULL)) return; - - // Calculate average restitution, static and dynamic friction - manifold->restitution = sqrtf(bodyA->restitution*bodyB->restitution); - manifold->staticFriction = sqrtf(bodyA->staticFriction*bodyB->staticFriction); - manifold->dynamicFriction = sqrtf(bodyA->dynamicFriction*bodyB->dynamicFriction); - - 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 crossA = MathCross(bodyA->angularVelocity, radiusA); - Vector2 crossB = MathCross(bodyB->angularVelocity, radiusB); - - Vector2 radiusV = { 0.0f, 0.0f }; - radiusV.x = bodyB->velocity.x + crossB.x - bodyA->velocity.x - crossA.x; - radiusV.y = bodyB->velocity.y + crossB.y - bodyA->velocity.y - crossA.y; - - // Determine if we should perform a resting collision or not; - // The idea is if the only thing moving this object is gravity, then the collision should be performed without any restitution - if (MathLenSqr(radiusV) < (MathLenSqr((Vector2){ gravityForce.x*deltaTime/1000, gravityForce.y*deltaTime/1000 }) + PHYSAC_EPSILON)) manifold->restitution = 0; - } -} - -// Integrates physics collisions impulses to solve collisions -static void IntegratePhysicsImpulses(PhysicsManifold manifold) -{ - PhysicsBody bodyA = manifold->bodyA; - PhysicsBody bodyB = manifold->bodyB; - - if ((bodyA == NULL) || (bodyB == NULL)) return; - - // Early out and positional correct if both objects have infinite mass - if (fabs(bodyA->inverseMass + bodyB->inverseMass) <= PHYSAC_EPSILON) - { - bodyA->velocity = PHYSAC_VECTOR_ZERO; - bodyB->velocity = PHYSAC_VECTOR_ZERO; - return; - } - - for (int i = 0; i < manifold->contactsCount; i++) - { - // Calculate radius from center of mass to contact - Vector2 radiusA = Vector2Subtract(manifold->contacts[i], bodyA->position); - Vector2 radiusB = Vector2Subtract(manifold->contacts[i], bodyB->position); - - // Calculate relative velocity - 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; - - // Relative velocity along the normal - float contactVelocity = MathDot(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 inverseMassSum = bodyA->inverseMass + bodyB->inverseMass + (raCrossN*raCrossN)*bodyA->inverseInertia + (rbCrossN*rbCrossN)*bodyB->inverseInertia; - - // Calculate impulse scalar value - float impulse = -(1.0f + manifold->restitution)*contactVelocity; - impulse /= inverseMassSum; - impulse /= (float)manifold->contactsCount; - - // Apply impulse to each physics body - Vector2 impulseV = { manifold->normal.x*impulse, manifold->normal.y*impulse }; - - if (bodyA->enabled) - { - bodyA->velocity.x += bodyA->inverseMass*(-impulseV.x); - bodyA->velocity.y += bodyA->inverseMass*(-impulseV.y); - if (!bodyA->freezeOrient) bodyA->angularVelocity += bodyA->inverseInertia*MathCrossVector2(radiusA, (Vector2){ -impulseV.x, -impulseV.y }); - } - - if (bodyB->enabled) - { - bodyB->velocity.x += bodyB->inverseMass*(impulseV.x); - bodyB->velocity.y += bodyB->inverseMass*(impulseV.y); - if (!bodyB->freezeOrient) bodyB->angularVelocity += bodyB->inverseInertia*MathCrossVector2(radiusB, impulseV); - } - - // Apply friction impulse to each physics body - radiusV.x = bodyB->velocity.x + MathCross(bodyB->angularVelocity, radiusB).x - bodyA->velocity.x - MathCross(bodyA->angularVelocity, radiusA).x; - radiusV.y = bodyB->velocity.y + MathCross(bodyB->angularVelocity, radiusB).y - bodyA->velocity.y - MathCross(bodyA->angularVelocity, radiusA).y; - - Vector2 tangent = { radiusV.x - (manifold->normal.x*MathDot(radiusV, manifold->normal)), radiusV.y - (manifold->normal.y*MathDot(radiusV, manifold->normal)) }; - MathNormalize(&tangent); - - // Calculate impulse tangent magnitude - float impulseTangent = -MathDot(radiusV, tangent); - impulseTangent /= inverseMassSum; - impulseTangent /= (float)manifold->contactsCount; - - float absImpulseTangent = fabs(impulseTangent); - - // Don't apply tiny friction impulses - if (absImpulseTangent <= PHYSAC_EPSILON) return; - - // Apply coulumb's law - 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 }; - - // Apply friction impulse - if (bodyA->enabled) - { - bodyA->velocity.x += bodyA->inverseMass*(-tangentImpulse.x); - bodyA->velocity.y += bodyA->inverseMass*(-tangentImpulse.y); - - if (!bodyA->freezeOrient) bodyA->angularVelocity += bodyA->inverseInertia*MathCrossVector2(radiusA, (Vector2){ -tangentImpulse.x, -tangentImpulse.y }); - } - - if (bodyB->enabled) - { - bodyB->velocity.x += bodyB->inverseMass*(tangentImpulse.x); - bodyB->velocity.y += bodyB->inverseMass*(tangentImpulse.y); - - if (!bodyB->freezeOrient) bodyB->angularVelocity += bodyB->inverseInertia*MathCrossVector2(radiusB, tangentImpulse); - } - } -} - -// Integrates physics velocity into position and forces -static void IntegratePhysicsVelocity(PhysicsBody body) -{ - if ((body == NULL) ||!body->enabled) return; - - body->position.x += body->velocity.x*deltaTime; - body->position.y += body->velocity.y*deltaTime; - - if (!body->freezeOrient) body->orient += body->angularVelocity*deltaTime; - Mat2Set(&body->shape.transform, body->orient); - - IntegratePhysicsForces(body); -} - -// Corrects physics bodies positions based on manifolds collision information -static void CorrectPhysicsPositions(PhysicsManifold manifold) -{ - PhysicsBody bodyA = manifold->bodyA; - PhysicsBody bodyB = manifold->bodyB; - - 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; - - if (bodyA->enabled) - { - bodyA->position.x -= correction.x*bodyA->inverseMass; - bodyA->position.y -= correction.y*bodyA->inverseMass; - } - - if (bodyB->enabled) - { - bodyB->position.x += correction.x*bodyB->inverseMass; - bodyB->position.y += correction.y*bodyB->inverseMass; - } -} - -// Returns the extreme point along a direction within a polygon -static Vector2 GetSupport(PhysicsShape shape, Vector2 dir) -{ - float bestProjection = -PHYSAC_FLT_MAX; - Vector2 bestVertex = { 0.0f, 0.0f }; - PolygonData data = shape.vertexData; - - for (int i = 0; i < data.vertexCount; i++) - { - Vector2 vertex = data.positions[i]; - float projection = MathDot(vertex, dir); - - if (projection > bestProjection) - { - bestVertex = vertex; - bestProjection = projection; - } - } - - return bestVertex; -} - -// Finds polygon shapes axis least penetration -static float FindAxisLeastPenetration(int *faceIndex, PhysicsShape shapeA, PhysicsShape shapeB) -{ - float bestDistance = -PHYSAC_FLT_MAX; - int bestIndex = 0; - - PolygonData dataA = shapeA.vertexData; - //PolygonData 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); - - // Transform face normal into B shape's model space - Matrix2x2 buT = Mat2Transpose(shapeB.transform); - normal = Mat2MultiplyVector2(buT, transNormal); - - // Retrieve support point from B shape along -n - Vector2 support = GetSupport(shapeB, (Vector2){ -normal.x, -normal.y }); - - // Retrieve vertex on face from A shape, transform into B shape's model space - 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); - - // Compute penetration distance in B shape's model space - float distance = MathDot(normal, Vector2Subtract(support, vertex)); - - // Store greatest distance - if (distance > bestDistance) - { - bestDistance = distance; - bestIndex = i; - } - } - - *faceIndex = bestIndex; - return bestDistance; -} - -// Finds two polygon shapes incident face -static void FindIncidentFace(Vector2 *v0, Vector2 *v1, PhysicsShape ref, PhysicsShape inc, int index) -{ - PolygonData refData = ref.vertexData; - PolygonData incData = inc.vertexData; - - Vector2 referenceNormal = refData.normals[index]; - - // Calculate normal in incident's frame of reference - referenceNormal = Mat2MultiplyVector2(ref.transform, referenceNormal); // To world space - referenceNormal = Mat2MultiplyVector2(Mat2Transpose(inc.transform), referenceNormal); // To incident's model space - - // Find most anti-normal face on polygon - int incidentFace = 0; - float minDot = PHYSAC_FLT_MAX; - - for (int i = 0; i < incData.vertexCount; i++) - { - float dot = MathDot(referenceNormal, incData.normals[i]); - - if (dot < minDot) - { - minDot = dot; - incidentFace = i; - } - } - - // Assign face vertices for incident face - *v0 = Mat2MultiplyVector2(inc.transform, incData.positions[incidentFace]); - *v0 = Vector2Add(*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); -} - -// Calculates clipping based on a normal and two faces -static int Clip(Vector2 normal, float clip, Vector2 *faceA, Vector2 *faceB) -{ - int sp = 0; - Vector2 out[2] = { *faceA, *faceB }; - - // Retrieve distances from each endpoint to the line - float distanceA = MathDot(normal, *faceA) - clip; - float distanceB = MathDot(normal, *faceB) - clip; - - // If negative (behind plane) - if (distanceA <= 0.0f) out[sp++] = *faceA; - if (distanceB <= 0.0f) out[sp++] = *faceB; - - // If the points are on different sides of the plane - if ((distanceA*distanceB) < 0.0f) - { - // Push intersection point - float alpha = distanceA/(distanceA - distanceB); - out[sp] = *faceA; - Vector2 delta = Vector2Subtract(*faceB, *faceA); - delta.x *= alpha; - delta.y *= alpha; - out[sp] = Vector2Add(out[sp], delta); - sp++; - } - - // Assign the new converted values - *faceA = out[0]; - *faceB = out[1]; - - return sp; -} - -// Check if values are between bias range -static bool BiasGreaterThan(float valueA, float valueB) -{ - return (valueA >= (valueB*0.95f + valueA*0.01f)); -} - -// Returns the barycenter of a triangle given by 3 points -static Vector2 TriangleBarycenter(Vector2 v1, Vector2 v2, Vector2 v3) -{ - Vector2 result = { 0.0f, 0.0f }; - - result.x = (v1.x + v2.x + v3.x)/3; - result.y = (v1.y + v2.y + v3.y)/3; - - return result; -} - -// 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 - -#if defined(__EMSCRIPTEN__) || defined(__linux__) - struct timespec now; - if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) frequency = 1000000000; -#endif - -#if defined(__APPLE__) - mach_timebase_info_data_t timebase; - mach_timebase_info(&timebase); - frequency = (timebase.denom*1e9)/timebase.numer; -#endif - - baseTime = GetTimeCount(); // Get MONOTONIC clock time offset - startTime = GetCurrentTime(); // Get current time -} - -// Get hi-res MONOTONIC time measure in seconds -static unsigned long long int GetTimeCount(void) -{ - unsigned long long int value = 0; - -#if defined(_WIN32) - QueryPerformanceCounter((unsigned long long int *) &value); -#endif - -#if defined(__linux__) - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - value = (unsigned long long int)now.tv_sec*(unsigned long long int)1000000000 + (unsigned long long int)now.tv_nsec; -#endif - -#if defined(__APPLE__) - value = mach_absolute_time(); -#endif - - return value; -} - -// Get current time in milliseconds -static double GetCurrentTime(void) -{ - return (double)(GetTimeCount() - baseTime)/frequency*1000; -} - -// Returns the cross product of a vector and a value -static inline Vector2 MathCross(float value, Vector2 vector) -{ - return (Vector2){ -value*vector.y, value*vector.x }; -} - -// Returns the cross product of two vectors -static inline float MathCrossVector2(Vector2 v1, Vector2 v2) -{ - return (v1.x*v2.y - v1.y*v2.x); -} - -// Returns the len square root of a vector -static inline float MathLenSqr(Vector2 vector) -{ - return (vector.x*vector.x + vector.y*vector.y); -} - -// Returns the dot product of two vectors -static inline float MathDot(Vector2 v1, Vector2 v2) -{ - return (v1.x*v2.x + v1.y*v2.y); -} - -// Returns the square root of distance between two vectors -static inline float DistSqr(Vector2 v1, Vector2 v2) -{ - Vector2 dir = Vector2Subtract(v1, v2); - return MathDot(dir, dir); -} - -// Returns the normalized values of a vector -static void MathNormalize(Vector2 *vector) -{ - float length, ilength; - - Vector2 aux = *vector; - length = sqrtf(aux.x*aux.x + aux.y*aux.y); - - if (length == 0) length = 1.0f; - - ilength = 1.0f/length; - - vector->x *= ilength; - vector->y *= ilength; -} - -#if defined(PHYSAC_STANDALONE) -// Returns the sum of two given vectors -static inline Vector2 Vector2Add(Vector2 v1, Vector2 v2) -{ - return (Vector2){ v1.x + v2.x, v1.y + v2.y }; -} - -// Returns the subtract of two given vectors -static inline Vector2 Vector2Subtract(Vector2 v1, Vector2 v2) -{ - return (Vector2){ v1.x - v2.x, v1.y - v2.y }; -} -#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) -{ - float cos = cosf(radians); - float sin = sinf(radians); - - matrix->m00 = cos; - matrix->m01 = -sin; - matrix->m10 = sin; - matrix->m11 = cos; -} - -// Returns the transpose of a given matrix 2x2 -static inline Matrix2x2 Mat2Transpose(Matrix2x2 matrix) -{ - return (Matrix2x2){ matrix.m00, matrix.m10, matrix.m01, matrix.m11 }; -} - -// Multiplies a vector by a matrix 2x2 -static inline Vector2 Mat2MultiplyVector2(Matrix2x2 matrix, Vector2 vector) -{ - return (Vector2){ matrix.m00*vector.x + matrix.m01*vector.y, matrix.m10*vector.x + matrix.m11*vector.y }; -} - -#endif // PHYSAC_IMPLEMENTATION |