Wise&mystical  1.0
Project about Europe
Loading...
Searching...
No Matches
physac.h
Go to the documentation of this file.
1
72#if !defined(PHYSAC_H)
73#define PHYSAC_H
74
75// Function specifiers in case library is build/used as a shared library (Windows)
76// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll
77#if defined(_WIN32)
78 #if defined(BUILD_LIBTYPE_SHARED)
79 #define PHYSACDEF __declspec(dllexport) // We are building the library as a Win32 shared library (.dll)
80 #elif defined(USE_LIBTYPE_SHARED)
81 #define PHYSACDEF __declspec(dllimport) // We are using the library as a Win32 shared library (.dll)
82 #endif
83#endif
84
85#ifndef PHYSACDEF
86 #define PHYSACDEF // We are building or using physac as a static library
87#endif
88
89// Allow custom memory allocators
90#ifndef PHYSAC_MALLOC
91 #define PHYSAC_MALLOC(size) malloc(size)
92#endif
93#ifndef PHYSAC_CALLOC
94 #define PHYSAC_CALLOC(size, n) calloc(size, n)
95#endif
96#ifndef PHYSAC_FREE
97 #define PHYSAC_FREE(ptr) free(ptr)
98#endif
99
100//----------------------------------------------------------------------------------
101// Defines and Macros
102//----------------------------------------------------------------------------------
103#define PHYSAC_MAX_BODIES 64 // Maximum number of physic bodies supported
104#define PHYSAC_MAX_MANIFOLDS 4096 // Maximum number of physic bodies interactions (64x64)
105#define PHYSAC_MAX_VERTICES 24 // Maximum number of vertex for polygons shapes
106#define PHYSAC_DEFAULT_CIRCLE_VERTICES 24 // Default number of vertices for circle shapes
107
108#define PHYSAC_COLLISION_ITERATIONS 100
109#define PHYSAC_PENETRATION_ALLOWANCE 0.05f
110#define PHYSAC_PENETRATION_CORRECTION 0.4f
111
112#define PHYSAC_PI 3.14159265358979323846f
113#define PHYSAC_DEG2RAD (PHYSAC_PI/180.0f)
114
115//----------------------------------------------------------------------------------
116// Data Types Structure Definition
117//----------------------------------------------------------------------------------
118#if defined(__STDC__) && __STDC_VERSION__ >= 199901L
119 #include <stdbool.h>
120#endif
121
123
124// Previously defined to be used in PhysicsShape struct as circular dependencies
126
127#if !defined(RL_VECTOR2_TYPE)
128// Vector2 type
129typedef struct Vector2 {
130 float x;
131 float y;
133#endif
134
135// Matrix2x2 type (used for polygon shape rotation matrix)
136typedef struct Matrix2x2 {
137 float m00;
138 float m01;
139 float m10;
140 float m11;
142
143typedef struct PhysicsVertexData {
144 unsigned int vertexCount; // Vertex count (positions and normals)
145 Vector2 positions[PHYSAC_MAX_VERTICES]; // Vertex positions vectors
146 Vector2 normals[PHYSAC_MAX_VERTICES]; // Vertex normals vectors
148
149typedef struct PhysicsShape {
150 PhysicsShapeType type; // Shape type (circle or polygon)
151 PhysicsBody body; // Shape physics body data pointer
152 PhysicsVertexData vertexData; // Shape vertices data (used for polygon shapes)
153 float radius; // Shape radius (used for circle shapes)
154 Matrix2x2 transform; // Vertices transform matrix 2x2
156
157typedef struct PhysicsBodyData {
158 unsigned int id; // Unique identifier
159 bool enabled; // Enabled dynamics state (collisions are calculated anyway)
160 Vector2 position; // Physics body shape pivot
161 Vector2 velocity; // Current linear velocity applied to position
162 Vector2 force; // Current linear force (reset to 0 every step)
163 float angularVelocity; // Current angular velocity applied to orient
164 float torque; // Current angular force (reset to 0 every step)
165 float orient; // Rotation in radians
166 float inertia; // Moment of inertia
167 float inverseInertia; // Inverse value of inertia
168 float mass; // Physics body mass
169 float inverseMass; // Inverse value of mass
170 float staticFriction; // Friction when the body has not movement (0 to 1)
171 float dynamicFriction; // Friction when the body has movement (0 to 1)
172 float restitution; // Restitution coefficient of the body (0 to 1)
173 bool useGravity; // Apply gravity force to dynamics
174 bool isGrounded; // Physics grounded on other body state
175 bool freezeOrient; // Physics rotation constraint
176 PhysicsShape shape; // Physics body shape information (type, radius, vertices, transform)
178
179typedef struct PhysicsManifoldData {
180 unsigned int id; // Unique identifier
181 PhysicsBody bodyA; // Manifold first physics body reference
182 PhysicsBody bodyB; // Manifold second physics body reference
183 float penetration; // Depth of penetration from collision
184 Vector2 normal; // Normal direction vector from 'a' to 'b'
185 Vector2 contacts[2]; // Points of contact during collision
186 unsigned int contactsCount; // Current collision number of contacts
187 float restitution; // Mixed restitution during collision
188 float dynamicFriction; // Mixed dynamic friction during collision
189 float staticFriction; // Mixed static friction during collision
191
192//----------------------------------------------------------------------------------
193// Module Functions Declaration
194//----------------------------------------------------------------------------------
195
196#if defined(__cplusplus)
197extern "C" { // Prevents name mangling of functions
198#endif
199// Physics system management
200PHYSACDEF void InitPhysics(void); // Initializes physics system
201PHYSACDEF void UpdatePhysics(void); // Update physics system
202PHYSACDEF void ResetPhysics(void); // Reset physics system (global variables)
203PHYSACDEF void ClosePhysics(void); // Close physics system and unload used memory
204PHYSACDEF void SetPhysicsTimeStep(double delta); // Sets physics fixed time step in milliseconds. 1.666666 by default
205PHYSACDEF void SetPhysicsGravity(float x, float y); // Sets physics global gravity force
206
207// Physic body creation/destroy
208PHYSACDEF PhysicsBody CreatePhysicsBodyCircle(Vector2 pos, float radius, float density); // Creates a new circle physics body with generic parameters
209PHYSACDEF PhysicsBody CreatePhysicsBodyRectangle(Vector2 pos, float width, float height, float density); // Creates a new rectangle physics body with generic parameters
210PHYSACDEF PhysicsBody CreatePhysicsBodyPolygon(Vector2 pos, float radius, int sides, float density); // Creates a new polygon physics body with generic parameters
211PHYSACDEF void DestroyPhysicsBody(PhysicsBody body); // Destroy a physics body
212
213// Physic body forces
214PHYSACDEF void PhysicsAddForce(PhysicsBody body, Vector2 force); // Adds a force to a physics body
215PHYSACDEF void PhysicsAddTorque(PhysicsBody body, float amount); // Adds an angular force to a physics body
216PHYSACDEF void PhysicsShatter(PhysicsBody body, Vector2 position, float force); // Shatters a polygon shape physics body to little physics bodies with explosion force
217PHYSACDEF void SetPhysicsBodyRotation(PhysicsBody body, float radians); // Sets physics body shape transform based on radians parameter
218
219// Query physics info
220PHYSACDEF PhysicsBody GetPhysicsBody(int index); // Returns a physics body of the bodies pool at a specific index
221PHYSACDEF int GetPhysicsBodiesCount(void); // Returns the current amount of created physics bodies
222PHYSACDEF int GetPhysicsShapeType(int index); // Returns the physics body shape type (PHYSICS_CIRCLE or PHYSICS_POLYGON)
223PHYSACDEF int GetPhysicsShapeVerticesCount(int index); // Returns the amount of vertices of a physics body shape
224PHYSACDEF Vector2 GetPhysicsShapeVertex(PhysicsBody body, int vertex); // Returns transformed position of a body shape (body position + vertex transformed position)
225#if defined(__cplusplus)
226}
227#endif
228
229#endif // PHYSAC_H
230
231
237#if defined(PHYSAC_IMPLEMENTATION)
238
239// Support TRACELOG macros
240#if defined(PHYSAC_DEBUG)
241 #include <stdio.h> // Required for: printf()
242 #define TRACELOG(...) printf(__VA_ARGS__)
243#else
244 #define TRACELOG(...) (void)0;
245#endif
246
247#include <stdlib.h> // Required for: malloc(), calloc(), free()
248#include <math.h> // Required for: cosf(), sinf(), fabs(), sqrtf()
249
250#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM)
251 // Time management functionality
252 #include <time.h> // Required for: time(), clock_gettime()
253 #if defined(_WIN32)
254 #if defined(__cplusplus)
255 extern "C" { // Prevents name mangling of functions
256 #endif
257 // Functions required to query time on Windows
258 int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount);
259 int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency);
260 #if defined(__cplusplus)
261 }
262 #endif
263 #endif
264 #if defined(__linux__) || defined(__FreeBSD__)
265 #if _POSIX_C_SOURCE < 199309L
266 #undef _POSIX_C_SOURCE
267 #define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext.
268 #endif
269 #include <sys/time.h> // Required for: timespec
270 #endif
271 #if defined(__APPLE__) // macOS also defines __MACH__
272 #include <mach/mach_time.h> // Required for: mach_absolute_time()
273 #endif
274#endif
275
276// NOTE: MSVC C++ compiler does not support compound literals (C99 feature)
277// Plain structures in C++ (without constructors) can be initialized from { } initializers.
278#if defined(__cplusplus)
279 #define CLITERAL(type) type
280#else
281 #define CLITERAL(type) (type)
282#endif
283
284//----------------------------------------------------------------------------------
285// Defines and Macros
286//----------------------------------------------------------------------------------
287#define PHYSAC_MIN(a,b) (((a)<(b))?(a):(b))
288#define PHYSAC_MAX(a,b) (((a)>(b))?(a):(b))
289#define PHYSAC_FLT_MAX 3.402823466e+38f
290#define PHYSAC_EPSILON 0.000001f
291#define PHYSAC_K 1.0f/3.0f
292#define PHYSAC_VECTOR_ZERO CLITERAL(Vector2){ 0.0f, 0.0f }
293
294//----------------------------------------------------------------------------------
295// Global Variables Definition
296//----------------------------------------------------------------------------------
297static double deltaTime = 1.0/60.0/10.0 * 1000; // Delta time in milliseconds used for physics steps
298
299#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM)
300// Time measure variables
301static double baseClockTicks = 0.0; // Offset clock ticks for MONOTONIC clock
302static unsigned long long int frequency = 0; // Hi-res clock frequency
303static double startTime = 0.0; // Start time in milliseconds
304static double currentTime = 0.0; // Current time in milliseconds
305#endif
306
307// Physics system configuration
308static PhysicsBody bodies[PHYSAC_MAX_BODIES]; // Physics bodies pointers array
309static unsigned int physicsBodiesCount = 0; // Physics world current bodies counter
310static PhysicsManifold contacts[PHYSAC_MAX_MANIFOLDS]; // Physics bodies pointers array
311static unsigned int physicsManifoldsCount = 0; // Physics world current manifolds counter
312
313static Vector2 gravityForce = { 0.0f, 9.81f }; // Physics world gravity force
314
315// Utilities variables
316static unsigned int usedMemory = 0; // Total allocated dynamic memory
317
318//----------------------------------------------------------------------------------
319// Module Internal Functions Declaration
320//----------------------------------------------------------------------------------
321#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM)
322// Timming measure functions
323static void InitTimerHiRes(void); // Initializes hi-resolution MONOTONIC timer
324static unsigned long long int GetClockTicks(void); // Get hi-res MONOTONIC time measure in mseconds
325static double GetCurrentTime(void); // Get current time measure in milliseconds
326#endif
327
328static void UpdatePhysicsStep(void); // Update physics step (dynamics, collisions and position corrections)
329
330static int FindAvailableBodyIndex(); // Finds a valid index for a new physics body initialization
331static int FindAvailableManifoldIndex(); // Finds a valid index for a new manifold initialization
332static PhysicsVertexData CreateDefaultPolygon(float radius, int sides); // Creates a random polygon shape with max vertex distance from polygon pivot
333static PhysicsVertexData CreateRectanglePolygon(Vector2 pos, Vector2 size); // Creates a rectangle polygon shape based on a min and max positions
334
335static void InitializePhysicsManifolds(PhysicsManifold manifold); // Initializes physics manifolds to solve collisions
336static PhysicsManifold CreatePhysicsManifold(PhysicsBody a, PhysicsBody b); // Creates a new physics manifold to solve collision
337static void DestroyPhysicsManifold(PhysicsManifold manifold); // Unitializes and destroys a physics manifold
338
339static void SolvePhysicsManifold(PhysicsManifold manifold); // Solves a created physics manifold between two physics bodies
340static void SolveCircleToCircle(PhysicsManifold manifold); // Solves collision between two circle shape physics bodies
341static void SolveCircleToPolygon(PhysicsManifold manifold); // Solves collision between a circle to a polygon shape physics bodies
342static void SolvePolygonToCircle(PhysicsManifold manifold); // Solves collision between a polygon to a circle shape physics bodies
343static void SolvePolygonToPolygon(PhysicsManifold manifold); // Solves collision between two polygons shape physics bodies
344static void IntegratePhysicsForces(PhysicsBody body); // Integrates physics forces into velocity
345static void IntegratePhysicsVelocity(PhysicsBody body); // Integrates physics velocity into position and forces
346static void IntegratePhysicsImpulses(PhysicsManifold manifold); // Integrates physics collisions impulses to solve collisions
347static void CorrectPhysicsPositions(PhysicsManifold manifold); // Corrects physics bodies positions based on manifolds collision information
348static void FindIncidentFace(Vector2 *v0, Vector2 *v1, PhysicsShape ref, PhysicsShape inc, int index); // Finds two polygon shapes incident face
349static float FindAxisLeastPenetration(int *faceIndex, PhysicsShape shapeA, PhysicsShape shapeB); // Finds polygon shapes axis least penetration
350
351// Math required functions
352static Vector2 MathVector2Product(Vector2 vector, float value); // Returns the product of a vector and a value
353static float MathVector2CrossProduct(Vector2 v1, Vector2 v2); // Returns the cross product of two vectors
354static float MathVector2SqrLen(Vector2 vector); // Returns the len square root of a vector
355static float MathVector2DotProduct(Vector2 v1, Vector2 v2); // Returns the dot product of two vectors
356static inline float MathVector2SqrDistance(Vector2 v1, Vector2 v2); // Returns the square root of distance between two vectors
357static void MathVector2Normalize(Vector2 *vector); // Returns the normalized values of a vector
358static Vector2 MathVector2Add(Vector2 v1, Vector2 v2); // Returns the sum of two given vectors
359static Vector2 MathVector2Subtract(Vector2 v1, Vector2 v2); // Returns the subtract of two given vectors
360static Matrix2x2 MathMatFromRadians(float radians); // Returns a matrix 2x2 from a given radians value
361static inline Matrix2x2 MathMatTranspose(Matrix2x2 matrix); // Returns the transpose of a given matrix 2x2
362static inline Vector2 MathMatVector2Product(Matrix2x2 matrix, Vector2 vector); // Returns product between matrix 2x2 and vector
363static int MathVector2Clip(Vector2 normal, Vector2 *faceA, Vector2 *faceB, float clip); // Returns clipping value based on a normal and two faces
364static Vector2 MathTriangleBarycenter(Vector2 v1, Vector2 v2, Vector2 v3); // Returns the barycenter of a triangle given by 3 points
365
366//----------------------------------------------------------------------------------
367// Module Functions Definition
368//----------------------------------------------------------------------------------
369
370// Initializes physics values, pointers and creates physics loop thread
371void InitPhysics(void)
372{
373#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM)
374 // Initialize high resolution timer
375 InitTimerHiRes();
376#endif
377
378 TRACELOG("[PHYSAC] Physics module initialized successfully\n");
379}
380
381// Sets physics global gravity force
382void SetPhysicsGravity(float x, float y)
383{
384 gravityForce.x = x;
385 gravityForce.y = y;
386}
387
388// Creates a new circle physics body with generic parameters
389PhysicsBody CreatePhysicsBodyCircle(Vector2 pos, float radius, float density)
390{
392 return body;
393}
394
395// Creates a new rectangle physics body with generic parameters
396PhysicsBody CreatePhysicsBodyRectangle(Vector2 pos, float width, float height, float density)
397{
398 // NOTE: Make sure body data is initialized to 0
400 usedMemory += sizeof(PhysicsBodyData);
401
402 int id = FindAvailableBodyIndex();
403 if (id != -1)
404 {
405 // Initialize new body with generic values
406 body->id = id;
407 body->enabled = true;
408 body->position = pos;
409 body->shape.type = PHYSICS_POLYGON;
410 body->shape.body = body;
411 body->shape.transform = MathMatFromRadians(0.0f);
412 body->shape.vertexData = CreateRectanglePolygon(pos, CLITERAL(Vector2){ width, height });
413
414 // Calculate centroid and moment of inertia
415 Vector2 center = { 0.0f, 0.0f };
416 float area = 0.0f;
417 float inertia = 0.0f;
418
419 for (unsigned int i = 0; i < body->shape.vertexData.vertexCount; i++)
420 {
421 // Triangle vertices, third vertex implied as (0, 0)
422 Vector2 p1 = body->shape.vertexData.positions[i];
423 unsigned int nextIndex = (((i + 1) < body->shape.vertexData.vertexCount) ? (i + 1) : 0);
424 Vector2 p2 = body->shape.vertexData.positions[nextIndex];
425
426 float D = MathVector2CrossProduct(p1, p2);
427 float triangleArea = D/2;
428
429 area += triangleArea;
430
431 // Use area to weight the centroid average, not just vertex position
432 center.x += triangleArea*PHYSAC_K*(p1.x + p2.x);
433 center.y += triangleArea*PHYSAC_K*(p1.y + p2.y);
434
435 float intx2 = p1.x*p1.x + p2.x*p1.x + p2.x*p2.x;
436 float inty2 = p1.y*p1.y + p2.y*p1.y + p2.y*p2.y;
437 inertia += (0.25f*PHYSAC_K*D)*(intx2 + inty2);
438 }
439
440 center.x *= 1.0f/area;
441 center.y *= 1.0f/area;
442
443 // Translate vertices to centroid (make the centroid (0, 0) for the polygon in model space)
444 // Note: this is not really necessary
445 for (unsigned int i = 0; i < body->shape.vertexData.vertexCount; i++)
446 {
447 body->shape.vertexData.positions[i].x -= center.x;
448 body->shape.vertexData.positions[i].y -= center.y;
449 }
450
451 body->mass = density*area;
452 body->inverseMass = ((body->mass != 0.0f) ? 1.0f/body->mass : 0.0f);
453 body->inertia = density*inertia;
454 body->inverseInertia = ((body->inertia != 0.0f) ? 1.0f/body->inertia : 0.0f);
455 body->staticFriction = 0.4f;
456 body->dynamicFriction = 0.2f;
457 body->restitution = 0.0f;
458 body->useGravity = true;
459 body->isGrounded = false;
460 body->freezeOrient = false;
461
462 // Add new body to bodies pointers array and update bodies count
463 bodies[physicsBodiesCount] = body;
464 physicsBodiesCount++;
465
466 TRACELOG("[PHYSAC] Physic body created successfully (id: %i)\n", body->id);
467 }
468 else TRACELOG("[PHYSAC] Physic body could not be created, PHYSAC_MAX_BODIES reached\n");
469
470 return body;
471}
472
473// Creates a new polygon physics body with generic parameters
474PhysicsBody CreatePhysicsBodyPolygon(Vector2 pos, float radius, int sides, float density)
475{
477 usedMemory += sizeof(PhysicsBodyData);
478
479 int id = FindAvailableBodyIndex();
480 if (id != -1)
481 {
482 // Initialize new body with generic values
483 body->id = id;
484 body->enabled = true;
485 body->position = pos;
486 body->velocity = PHYSAC_VECTOR_ZERO;
487 body->force = PHYSAC_VECTOR_ZERO;
488 body->angularVelocity = 0.0f;
489 body->torque = 0.0f;
490 body->orient = 0.0f;
491 body->shape.type = PHYSICS_POLYGON;
492 body->shape.body = body;
493 body->shape.transform = MathMatFromRadians(0.0f);
494 body->shape.vertexData = CreateDefaultPolygon(radius, sides);
495
496 // Calculate centroid and moment of inertia
497 Vector2 center = { 0.0f, 0.0f };
498 float area = 0.0f;
499 float inertia = 0.0f;
500
501 for (unsigned int i = 0; i < body->shape.vertexData.vertexCount; i++)
502 {
503 // Triangle vertices, third vertex implied as (0, 0)
504 Vector2 position1 = body->shape.vertexData.positions[i];
505 unsigned int nextIndex = (((i + 1) < body->shape.vertexData.vertexCount) ? (i + 1) : 0);
506 Vector2 position2 = body->shape.vertexData.positions[nextIndex];
507
508 float cross = MathVector2CrossProduct(position1, position2);
509 float triangleArea = cross/2;
510
511 area += triangleArea;
512
513 // Use area to weight the centroid average, not just vertex position
514 center.x += triangleArea*PHYSAC_K*(position1.x + position2.x);
515 center.y += triangleArea*PHYSAC_K*(position1.y + position2.y);
516
517 float intx2 = position1.x*position1.x + position2.x*position1.x + position2.x*position2.x;
518 float inty2 = position1.y*position1.y + position2.y*position1.y + position2.y*position2.y;
519 inertia += (0.25f*PHYSAC_K*cross)*(intx2 + inty2);
520 }
521
522 center.x *= 1.0f/area;
523 center.y *= 1.0f/area;
524
525 // Translate vertices to centroid (make the centroid (0, 0) for the polygon in model space)
526 // Note: this is not really necessary
527 for (unsigned int i = 0; i < body->shape.vertexData.vertexCount; i++)
528 {
529 body->shape.vertexData.positions[i].x -= center.x;
530 body->shape.vertexData.positions[i].y -= center.y;
531 }
532
533 body->mass = density*area;
534 body->inverseMass = ((body->mass != 0.0f) ? 1.0f/body->mass : 0.0f);
535 body->inertia = density*inertia;
536 body->inverseInertia = ((body->inertia != 0.0f) ? 1.0f/body->inertia : 0.0f);
537 body->staticFriction = 0.4f;
538 body->dynamicFriction = 0.2f;
539 body->restitution = 0.0f;
540 body->useGravity = true;
541 body->isGrounded = false;
542 body->freezeOrient = false;
543
544 // Add new body to bodies pointers array and update bodies count
545 bodies[physicsBodiesCount] = body;
546 physicsBodiesCount++;
547
548 TRACELOG("[PHYSAC] Physic body created successfully (id: %i)\n", body->id);
549 }
550 else TRACELOG("[PHYSAC] Physics body could not be created, PHYSAC_MAX_BODIES reached\n");
551
552 return body;
553}
554
555// Adds a force to a physics body
556void PhysicsAddForce(PhysicsBody body, Vector2 force)
557{
558 if (body != NULL) body->force = MathVector2Add(body->force, force);
559}
560
561// Adds an angular force to a physics body
562void PhysicsAddTorque(PhysicsBody body, float amount)
563{
564 if (body != NULL) body->torque += amount;
565}
566
567// Shatters a polygon shape physics body to little physics bodies with explosion force
568void PhysicsShatter(PhysicsBody body, Vector2 position, float force)
569{
570 if (body != NULL)
571 {
572 if (body->shape.type == PHYSICS_POLYGON)
573 {
574 PhysicsVertexData vertexData = body->shape.vertexData;
575 bool collision = false;
576
577 for (unsigned int i = 0; i < vertexData.vertexCount; i++)
578 {
579 Vector2 positionA = body->position;
580 Vector2 positionB = MathMatVector2Product(body->shape.transform, MathVector2Add(body->position, vertexData.positions[i]));
581 unsigned int nextIndex = (((i + 1) < vertexData.vertexCount) ? (i + 1) : 0);
582 Vector2 positionC = MathMatVector2Product(body->shape.transform, MathVector2Add(body->position, vertexData.positions[nextIndex]));
583
584 // Check collision between each triangle
585 float alpha = ((positionB.y - positionC.y)*(position.x - positionC.x) + (positionC.x - positionB.x)*(position.y - positionC.y))/
586 ((positionB.y - positionC.y)*(positionA.x - positionC.x) + (positionC.x - positionB.x)*(positionA.y - positionC.y));
587
588 float beta = ((positionC.y - positionA.y)*(position.x - positionC.x) + (positionA.x - positionC.x)*(position.y - positionC.y))/
589 ((positionB.y - positionC.y)*(positionA.x - positionC.x) + (positionC.x - positionB.x)*(positionA.y - positionC.y));
590
591 float gamma = 1.0f - alpha - beta;
592
593 if ((alpha > 0.0f) && (beta > 0.0f) & (gamma > 0.0f))
594 {
595 collision = true;
596 break;
597 }
598 }
599
600 if (collision)
601 {
602 int count = vertexData.vertexCount;
603 Vector2 bodyPos = body->position;
604 Vector2 *vertices = (Vector2 *)PHYSAC_MALLOC(sizeof(Vector2)*count);
605 Matrix2x2 trans = body->shape.transform;
606 for (int i = 0; i < count; i++) vertices[i] = vertexData.positions[i];
607
608 // Destroy shattered physics body
609 DestroyPhysicsBody(body);
610
611 for (int i = 0; i < count; i++)
612 {
613 int nextIndex = (((i + 1) < count) ? (i + 1) : 0);
614 Vector2 center = MathTriangleBarycenter(vertices[i], vertices[nextIndex], PHYSAC_VECTOR_ZERO);
615 center = MathVector2Add(bodyPos, center);
616 Vector2 offset = MathVector2Subtract(center, bodyPos);
617
618 PhysicsBody body = CreatePhysicsBodyPolygon(center, 10, 3, 10); // Create polygon physics body with relevant values
619
620 PhysicsVertexData vertexData = { 0 };
621 vertexData.vertexCount = 3;
622
623 vertexData.positions[0] = MathVector2Subtract(vertices[i], offset);
624 vertexData.positions[1] = MathVector2Subtract(vertices[nextIndex], offset);
625 vertexData.positions[2] = MathVector2Subtract(position, center);
626
627 // Separate vertices to avoid unnecessary physics collisions
628 vertexData.positions[0].x *= 0.95f;
629 vertexData.positions[0].y *= 0.95f;
630 vertexData.positions[1].x *= 0.95f;
631 vertexData.positions[1].y *= 0.95f;
632 vertexData.positions[2].x *= 0.95f;
633 vertexData.positions[2].y *= 0.95f;
634
635 // Calculate polygon faces normals
636 for (unsigned int j = 0; j < vertexData.vertexCount; j++)
637 {
638 unsigned int nextVertex = (((j + 1) < vertexData.vertexCount) ? (j + 1) : 0);
639 Vector2 face = MathVector2Subtract(vertexData.positions[nextVertex], vertexData.positions[j]);
640
641 vertexData.normals[j] = CLITERAL(Vector2){ face.y, -face.x };
642 MathVector2Normalize(&vertexData.normals[j]);
643 }
644
645 // Apply computed vertex data to new physics body shape
646 body->shape.vertexData = vertexData;
647 body->shape.transform = trans;
648
649 // Calculate centroid and moment of inertia
650 center = PHYSAC_VECTOR_ZERO;
651 float area = 0.0f;
652 float inertia = 0.0f;
653
654 for (unsigned int j = 0; j < body->shape.vertexData.vertexCount; j++)
655 {
656 // Triangle vertices, third vertex implied as (0, 0)
657 Vector2 p1 = body->shape.vertexData.positions[j];
658 unsigned int nextVertex = (((j + 1) < body->shape.vertexData.vertexCount) ? (j + 1) : 0);
659 Vector2 p2 = body->shape.vertexData.positions[nextVertex];
660
661 float D = MathVector2CrossProduct(p1, p2);
662 float triangleArea = D/2;
663
664 area += triangleArea;
665
666 // Use area to weight the centroid average, not just vertex position
667 center.x += triangleArea*PHYSAC_K*(p1.x + p2.x);
668 center.y += triangleArea*PHYSAC_K*(p1.y + p2.y);
669
670 float intx2 = p1.x*p1.x + p2.x*p1.x + p2.x*p2.x;
671 float inty2 = p1.y*p1.y + p2.y*p1.y + p2.y*p2.y;
672 inertia += (0.25f*PHYSAC_K*D)*(intx2 + inty2);
673 }
674
675 center.x *= 1.0f/area;
676 center.y *= 1.0f/area;
677
678 body->mass = area;
679 body->inverseMass = ((body->mass != 0.0f) ? 1.0f/body->mass : 0.0f);
680 body->inertia = inertia;
681 body->inverseInertia = ((body->inertia != 0.0f) ? 1.0f/body->inertia : 0.0f);
682
683 // Calculate explosion force direction
684 Vector2 pointA = body->position;
685 Vector2 pointB = MathVector2Subtract(vertexData.positions[1], vertexData.positions[0]);
686 pointB.x /= 2.0f;
687 pointB.y /= 2.0f;
688 Vector2 forceDirection = MathVector2Subtract(MathVector2Add(pointA, MathVector2Add(vertexData.positions[0], pointB)), body->position);
689 MathVector2Normalize(&forceDirection);
690 forceDirection.x *= force;
691 forceDirection.y *= force;
692
693 // Apply force to new physics body
694 PhysicsAddForce(body, forceDirection);
695 }
696
697 PHYSAC_FREE(vertices);
698 }
699 }
700 }
701 else TRACELOG("[PHYSAC] WARNING: PhysicsShatter: NULL physic body\n");
702}
703
704// Returns the current amount of created physics bodies
705int GetPhysicsBodiesCount(void)
706{
707 return physicsBodiesCount;
708}
709
710// Returns a physics body of the bodies pool at a specific index
712{
713 PhysicsBody body = NULL;
714
715 if (index < (int)physicsBodiesCount)
716 {
717 body = bodies[index];
718
719 if (body == NULL) TRACELOG("[PHYSAC] WARNING: GetPhysicsBody: NULL physic body\n");
720 }
721 else TRACELOG("[PHYSAC] WARNING: Physic body index is out of bounds\n");
722
723 return body;
724}
725
726// Returns the physics body shape type (PHYSICS_CIRCLE or PHYSICS_POLYGON)
727int GetPhysicsShapeType(int index)
728{
729 int result = -1;
730
731 if (index < (int)physicsBodiesCount)
732 {
733 PhysicsBody body = bodies[index];
734
735 if (body != NULL) result = body->shape.type;
736 else TRACELOG("[PHYSAC] WARNING: GetPhysicsShapeType: NULL physic body\n");
737 }
738 else TRACELOG("[PHYSAC] WARNING: Physic body index is out of bounds\n");
739
740 return result;
741}
742
743// Returns the amount of vertices of a physics body shape
744int GetPhysicsShapeVerticesCount(int index)
745{
746 int result = 0;
747
748 if (index < (int)physicsBodiesCount)
749 {
750 PhysicsBody body = bodies[index];
751
752 if (body != NULL)
753 {
754 switch (body->shape.type)
755 {
757 case PHYSICS_POLYGON: result = body->shape.vertexData.vertexCount; break;
758 default: break;
759 }
760 }
761 else TRACELOG("[PHYSAC] WARNING: GetPhysicsShapeVerticesCount: NULL physic body\n");
762 }
763 else TRACELOG("[PHYSAC] WARNING: Physic body index is out of bounds\n");
764
765 return result;
766}
767
768// Returns transformed position of a body shape (body position + vertex transformed position)
770{
771 Vector2 position = { 0.0f, 0.0f };
772
773 if (body != NULL)
774 {
775 switch (body->shape.type)
776 {
777 case PHYSICS_CIRCLE:
778 {
779 position.x = body->position.x + cosf(360.0f/PHYSAC_DEFAULT_CIRCLE_VERTICES*vertex*PHYSAC_DEG2RAD)*body->shape.radius;
780 position.y = body->position.y + sinf(360.0f/PHYSAC_DEFAULT_CIRCLE_VERTICES*vertex*PHYSAC_DEG2RAD)*body->shape.radius;
781 } break;
782 case PHYSICS_POLYGON:
783 {
784 PhysicsVertexData vertexData = body->shape.vertexData;
785 position = MathVector2Add(body->position, MathMatVector2Product(body->shape.transform, vertexData.positions[vertex]));
786 } break;
787 default: break;
788 }
789 }
790 else TRACELOG("[PHYSAC] WARNING: GetPhysicsShapeVertex: NULL physic body\n");
791
792 return position;
793}
794
795// Sets physics body shape transform based on radians parameter
796void SetPhysicsBodyRotation(PhysicsBody body, float radians)
797{
798 if (body != NULL)
799 {
800 body->orient = radians;
801
802 if (body->shape.type == PHYSICS_POLYGON) body->shape.transform = MathMatFromRadians(radians);
803 }
804}
805
806// Unitializes and destroys a physics body
808{
809 if (body != NULL)
810 {
811 int id = body->id;
812 int index = -1;
813
814 for (unsigned int i = 0; i < physicsBodiesCount; i++)
815 {
816 if (bodies[i]->id == id)
817 {
818 index = i;
819 break;
820 }
821 }
822
823 if (index == -1)
824 {
825 TRACELOG("[PHYSAC] WARNING: Requested body (id: %i) can not be found\n", id);
826 return; // Prevent access to index -1
827 }
828
829 // Free body allocated memory
830 PHYSAC_FREE(body);
831 usedMemory -= sizeof(PhysicsBodyData);
832 bodies[index] = NULL;
833
834 // Reorder physics bodies pointers array and its catched index
835 for (unsigned int i = index; i < physicsBodiesCount; i++)
836 {
837 if ((i + 1) < physicsBodiesCount) bodies[i] = bodies[i + 1];
838 }
839
840 // Update physics bodies count
841 physicsBodiesCount--;
842
843 TRACELOG("[PHYSAC] Physic body destroyed successfully (id: %i)\n", id);
844 }
845 else TRACELOG("[PHYSAC] WARNING: DestroyPhysicsBody: NULL physic body\n");
846}
847
848// Destroys created physics bodies and manifolds and resets global values
849void ResetPhysics(void)
850{
851 if (physicsBodiesCount > 0)
852 {
853 // Unitialize physics bodies dynamic memory allocations
854 for (int i = physicsBodiesCount - 1; i >= 0; i--)
855 {
856 PhysicsBody body = bodies[i];
857
858 if (body != NULL)
859 {
860 PHYSAC_FREE(body);
861 bodies[i] = NULL;
862 usedMemory -= sizeof(PhysicsBodyData);
863 }
864 }
865
866 physicsBodiesCount = 0;
867 }
868
869 if (physicsManifoldsCount > 0)
870 {
871 // Unitialize physics manifolds dynamic memory allocations
872 for (int i = physicsManifoldsCount - 1; i >= 0; i--)
873 {
874 PhysicsManifold manifold = contacts[i];
875
876 if (manifold != NULL)
877 {
878 PHYSAC_FREE(manifold);
879 contacts[i] = NULL;
880 usedMemory -= sizeof(PhysicsManifoldData);
881 }
882 }
883
884 physicsManifoldsCount = 0;
885 }
886
887 TRACELOG("[PHYSAC] Physics module reseted successfully\n");
888}
889
890// Unitializes physics pointers and exits physics loop thread
891void ClosePhysics(void)
892{
893 // Unitialize physics manifolds dynamic memory allocations
894 if (physicsManifoldsCount > 0)
895 {
896 for (int i = physicsManifoldsCount - 1; i >= 0; i--) DestroyPhysicsManifold(contacts[i]);
897 }
898
899 // Unitialize physics bodies dynamic memory allocations
900 if (physicsBodiesCount > 0)
901 {
902 for (int i = physicsBodiesCount - 1; i >= 0; i--) DestroyPhysicsBody(bodies[i]);
903 }
904
905 // Trace log info
906 if ((physicsBodiesCount > 0) || (usedMemory != 0))
907 {
908 TRACELOG("[PHYSAC] WARNING: Physics module closed with unallocated bodies (BODIES: %i, MEMORY: %i bytes)\n", physicsBodiesCount, usedMemory);
909 }
910 else if ((physicsManifoldsCount > 0) || (usedMemory != 0))
911 {
912 TRACELOG("[PHYSAC] WARNING: Pysics module closed with unallocated manifolds (MANIFOLDS: %i, MEMORY: %i bytes)\n", physicsManifoldsCount, usedMemory);
913 }
914 else TRACELOG("[PHYSAC] Physics module closed successfully\n");
915}
916
917// Update physics system
918// Physics steps are launched at a fixed time step if enabled
919void UpdatePhysics(void)
920{
921#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM)
922 static double deltaTimeAccumulator = 0.0;
923
924 // Calculate current time (ms)
925 currentTime = GetCurrentTime();
926
927 // Calculate current delta time (ms)
928 const double delta = currentTime - startTime;
929
930 // Store the time elapsed since the last frame began
931 deltaTimeAccumulator += delta;
932
933 // Fixed time stepping loop
934 while (deltaTimeAccumulator >= deltaTime)
935 {
936 UpdatePhysicsStep();
937 deltaTimeAccumulator -= deltaTime;
938 }
939
940 // Record the starting of this frame
941 startTime = currentTime;
942#else
943 UpdatePhysicsStep();
944#endif
945}
946
947void SetPhysicsTimeStep(double delta)
948{
949 deltaTime = delta;
950}
951
952//----------------------------------------------------------------------------------
953// Module Internal Functions Definition
954//----------------------------------------------------------------------------------
955#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM)
956// Initializes hi-resolution MONOTONIC timer
957static void InitTimerHiRes(void)
958{
959#if defined(_WIN32)
960 QueryPerformanceFrequency((unsigned long long int *) &frequency);
961#endif
962
963#if defined(__EMSCRIPTEN__) || defined(__linux__)
964 struct timespec now;
965 if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) frequency = 1000000000;
966#endif
967
968#if defined(__APPLE__)
969 mach_timebase_info_data_t timebase;
970 mach_timebase_info(&timebase);
971 frequency = (timebase.denom*1e9)/timebase.numer;
972#endif
973
974 baseClockTicks = (double)GetClockTicks(); // Get MONOTONIC clock time offset
975 startTime = GetCurrentTime(); // Get current time in milliseconds
976}
977
978// Get hi-res MONOTONIC time measure in clock ticks
979static unsigned long long int GetClockTicks(void)
980{
981 unsigned long long int value = 0;
982
983#if defined(_WIN32)
984 QueryPerformanceCounter((unsigned long long int *) &value);
985#endif
986
987#if defined(__linux__)
988 struct timespec now;
989 clock_gettime(CLOCK_MONOTONIC, &now);
990 value = (unsigned long long int)now.tv_sec*(unsigned long long int)1000000000 + (unsigned long long int)now.tv_nsec;
991#endif
992
993#if defined(__APPLE__)
994 value = mach_absolute_time();
995#endif
996
997 return value;
998}
999
1000// Get current time in milliseconds
1001static double GetCurrentTime(void)
1002{
1003 return (double)(GetClockTicks() - baseClockTicks)/frequency*1000;
1004}
1005#endif // !PHYSAC_AVOID_TIMMING_SYSTEM
1006
1007// Update physics step (dynamics, collisions and position corrections)
1008static void UpdatePhysicsStep(void)
1009{
1010 // Clear previous generated collisions information
1011 for (int i = (int)physicsManifoldsCount - 1; i >= 0; i--)
1012 {
1013 PhysicsManifold manifold = contacts[i];
1014 if (manifold != NULL) DestroyPhysicsManifold(manifold);
1015 }
1016
1017 // Reset physics bodies grounded state
1018 for (unsigned int i = 0; i < physicsBodiesCount; i++)
1019 {
1020 PhysicsBody body = bodies[i];
1021 body->isGrounded = false;
1022 }
1023
1024 // Generate new collision information
1025 for (unsigned int i = 0; i < physicsBodiesCount; i++)
1026 {
1027 PhysicsBody bodyA = bodies[i];
1028
1029 if (bodyA != NULL)
1030 {
1031 for (unsigned int j = i + 1; j < physicsBodiesCount; j++)
1032 {
1033 PhysicsBody bodyB = bodies[j];
1034
1035 if (bodyB != NULL)
1036 {
1037 if ((bodyA->inverseMass == 0) && (bodyB->inverseMass == 0)) continue;
1038
1039 PhysicsManifold manifold = CreatePhysicsManifold(bodyA, bodyB);
1040 SolvePhysicsManifold(manifold);
1041
1042 if (manifold->contactsCount > 0)
1043 {
1044 // Create a new manifold with same information as previously solved manifold and add it to the manifolds pool last slot
1045 PhysicsManifold manifold = CreatePhysicsManifold(bodyA, bodyB);
1046 manifold->penetration = manifold->penetration;
1047 manifold->normal = manifold->normal;
1048 manifold->contacts[0] = manifold->contacts[0];
1049 manifold->contacts[1] = manifold->contacts[1];
1050 manifold->contactsCount = manifold->contactsCount;
1051 manifold->restitution = manifold->restitution;
1052 manifold->dynamicFriction = manifold->dynamicFriction;
1053 manifold->staticFriction = manifold->staticFriction;
1054 }
1055 }
1056 }
1057 }
1058 }
1059
1060 // Integrate forces to physics bodies
1061 for (unsigned int i = 0; i < physicsBodiesCount; i++)
1062 {
1063 PhysicsBody body = bodies[i];
1064 if (body != NULL) IntegratePhysicsForces(body);
1065 }
1066
1067 // Initialize physics manifolds to solve collisions
1068 for (unsigned int i = 0; i < physicsManifoldsCount; i++)
1069 {
1070 PhysicsManifold manifold = contacts[i];
1071 if (manifold != NULL) InitializePhysicsManifolds(manifold);
1072 }
1073
1074 // Integrate physics collisions impulses to solve collisions
1075 for (unsigned int i = 0; i < PHYSAC_COLLISION_ITERATIONS; i++)
1076 {
1077 for (unsigned int j = 0; j < physicsManifoldsCount; j++)
1078 {
1079 PhysicsManifold manifold = contacts[i];
1080 if (manifold != NULL) IntegratePhysicsImpulses(manifold);
1081 }
1082 }
1083
1084 // Integrate velocity to physics bodies
1085 for (unsigned int i = 0; i < physicsBodiesCount; i++)
1086 {
1087 PhysicsBody body = bodies[i];
1088 if (body != NULL) IntegratePhysicsVelocity(body);
1089 }
1090
1091 // Correct physics bodies positions based on manifolds collision information
1092 for (unsigned int i = 0; i < physicsManifoldsCount; i++)
1093 {
1094 PhysicsManifold manifold = contacts[i];
1095 if (manifold != NULL) CorrectPhysicsPositions(manifold);
1096 }
1097
1098 // Clear physics bodies forces
1099 for (unsigned int i = 0; i < physicsBodiesCount; i++)
1100 {
1101 PhysicsBody body = bodies[i];
1102 if (body != NULL)
1103 {
1104 body->force = PHYSAC_VECTOR_ZERO;
1105 body->torque = 0.0f;
1106 }
1107 }
1108}
1109
1110// Finds a valid index for a new physics body initialization
1111static int FindAvailableBodyIndex()
1112{
1113 int index = -1;
1114 for (int i = 0; i < PHYSAC_MAX_BODIES; i++)
1115 {
1116 int currentId = i;
1117
1118 // Check if current id already exist in other physics body
1119 for (unsigned int k = 0; k < physicsBodiesCount; k++)
1120 {
1121 if (bodies[k]->id == currentId)
1122 {
1123 currentId++;
1124 break;
1125 }
1126 }
1127
1128 // If it is not used, use it as new physics body id
1129 if (currentId == (int)i)
1130 {
1131 index = (int)i;
1132 break;
1133 }
1134 }
1135
1136 return index;
1137}
1138
1139// Creates a default polygon shape with max vertex distance from polygon pivot
1140static PhysicsVertexData CreateDefaultPolygon(float radius, int sides)
1141{
1142 PhysicsVertexData data = { 0 };
1143 data.vertexCount = sides;
1144
1145 // Calculate polygon vertices positions
1146 for (unsigned int i = 0; i < data.vertexCount; i++)
1147 {
1148 data.positions[i].x = (float)cosf(360.0f/sides*i*PHYSAC_DEG2RAD)*radius;
1149 data.positions[i].y = (float)sinf(360.0f/sides*i*PHYSAC_DEG2RAD)*radius;
1150 }
1151
1152 // Calculate polygon faces normals
1153 for (int i = 0; i < (int)data.vertexCount; i++)
1154 {
1155 int nextIndex = (((i + 1) < sides) ? (i + 1) : 0);
1156 Vector2 face = MathVector2Subtract(data.positions[nextIndex], data.positions[i]);
1157
1158 data.normals[i] = CLITERAL(Vector2){ face.y, -face.x };
1159 MathVector2Normalize(&data.normals[i]);
1160 }
1161
1162 return data;
1163}
1164
1165// Creates a rectangle polygon shape based on a min and max positions
1166static PhysicsVertexData CreateRectanglePolygon(Vector2 pos, Vector2 size)
1167{
1168 PhysicsVertexData data = { 0 };
1169 data.vertexCount = 4;
1170
1171 // Calculate polygon vertices positions
1172 data.positions[0] = CLITERAL(Vector2){ pos.x + size.x/2, pos.y - size.y/2 };
1173 data.positions[1] = CLITERAL(Vector2){ pos.x + size.x/2, pos.y + size.y/2 };
1174 data.positions[2] = CLITERAL(Vector2){ pos.x - size.x/2, pos.y + size.y/2 };
1175 data.positions[3] = CLITERAL(Vector2){ pos.x - size.x/2, pos.y - size.y/2 };
1176
1177 // Calculate polygon faces normals
1178 for (unsigned int i = 0; i < data.vertexCount; i++)
1179 {
1180 int nextIndex = (((i + 1) < data.vertexCount) ? (i + 1) : 0);
1181 Vector2 face = MathVector2Subtract(data.positions[nextIndex], data.positions[i]);
1182
1183 data.normals[i] = CLITERAL(Vector2){ face.y, -face.x };
1184 MathVector2Normalize(&data.normals[i]);
1185 }
1186
1187 return data;
1188}
1189
1190// Finds a valid index for a new manifold initialization
1191static int FindAvailableManifoldIndex()
1192{
1193 int index = -1;
1194 for (int i = 0; i < PHYSAC_MAX_MANIFOLDS; i++)
1195 {
1196 int currentId = i;
1197
1198 // Check if current id already exist in other physics body
1199 for (unsigned int k = 0; k < physicsManifoldsCount; k++)
1200 {
1201 if (contacts[k]->id == currentId)
1202 {
1203 currentId++;
1204 break;
1205 }
1206 }
1207
1208 // If it is not used, use it as new physics body id
1209 if (currentId == i)
1210 {
1211 index = i;
1212 break;
1213 }
1214 }
1215
1216 return index;
1217}
1218
1219// Creates a new physics manifold to solve collision
1220static PhysicsManifold CreatePhysicsManifold(PhysicsBody a, PhysicsBody b)
1221{
1223 usedMemory += sizeof(PhysicsManifoldData);
1224
1225 int id = FindAvailableManifoldIndex();
1226 if (id != -1)
1227 {
1228 // Initialize new manifold with generic values
1229 manifold->id = id;
1230 manifold->bodyA = a;
1231 manifold->bodyB = b;
1232 manifold->penetration = 0;
1233 manifold->normal = PHYSAC_VECTOR_ZERO;
1234 manifold->contacts[0] = PHYSAC_VECTOR_ZERO;
1235 manifold->contacts[1] = PHYSAC_VECTOR_ZERO;
1236 manifold->contactsCount = 0;
1237 manifold->restitution = 0.0f;
1238 manifold->dynamicFriction = 0.0f;
1239 manifold->staticFriction = 0.0f;
1240
1241 // Add new body to bodies pointers array and update bodies count
1242 contacts[physicsManifoldsCount] = manifold;
1243 physicsManifoldsCount++;
1244 }
1245 else TRACELOG("[PHYSAC] Physic manifold could not be created, PHYSAC_MAX_MANIFOLDS reached\n");
1246
1247 return manifold;
1248}
1249
1250// Unitializes and destroys a physics manifold
1251static void DestroyPhysicsManifold(PhysicsManifold manifold)
1252{
1253 if (manifold != NULL)
1254 {
1255 int id = manifold->id;
1256 int index = -1;
1257
1258 for (unsigned int i = 0; i < physicsManifoldsCount; i++)
1259 {
1260 if (contacts[i]->id == id)
1261 {
1262 index = i;
1263 break;
1264 }
1265 }
1266
1267 if (index == -1) return; // Prevent access to index -1
1268
1269 // Free manifold allocated memory
1270 PHYSAC_FREE(manifold);
1271 usedMemory -= sizeof(PhysicsManifoldData);
1272 contacts[index] = NULL;
1273
1274 // Reorder physics manifolds pointers array and its catched index
1275 for (unsigned int i = index; i < physicsManifoldsCount; i++)
1276 {
1277 if ((i + 1) < physicsManifoldsCount) contacts[i] = contacts[i + 1];
1278 }
1279
1280 // Update physics manifolds count
1281 physicsManifoldsCount--;
1282 }
1283 else TRACELOG("[PHYSAC] WARNING: DestroyPhysicsManifold: NULL physic manifold\n");
1284}
1285
1286// Solves a created physics manifold between two physics bodies
1287static void SolvePhysicsManifold(PhysicsManifold manifold)
1288{
1289 switch (manifold->bodyA->shape.type)
1290 {
1291 case PHYSICS_CIRCLE:
1292 {
1293 switch (manifold->bodyB->shape.type)
1294 {
1295 case PHYSICS_CIRCLE: SolveCircleToCircle(manifold); break;
1296 case PHYSICS_POLYGON: SolveCircleToPolygon(manifold); break;
1297 default: break;
1298 }
1299 } break;
1300 case PHYSICS_POLYGON:
1301 {
1302 switch (manifold->bodyB->shape.type)
1303 {
1304 case PHYSICS_CIRCLE: SolvePolygonToCircle(manifold); break;
1305 case PHYSICS_POLYGON: SolvePolygonToPolygon(manifold); break;
1306 default: break;
1307 }
1308 } break;
1309 default: break;
1310 }
1311
1312 // Update physics body grounded state if normal direction is down and grounded state is not set yet in previous manifolds
1313 if (!manifold->bodyB->isGrounded) manifold->bodyB->isGrounded = (manifold->normal.y < 0);
1314}
1315
1316// Solves collision between two circle shape physics bodies
1317static void SolveCircleToCircle(PhysicsManifold manifold)
1318{
1319 PhysicsBody bodyA = manifold->bodyA;
1320 PhysicsBody bodyB = manifold->bodyB;
1321
1322 if ((bodyA == NULL) || (bodyB == NULL)) return;
1323
1324 // Calculate translational vector, which is normal
1325 Vector2 normal = MathVector2Subtract(bodyB->position, bodyA->position);
1326
1327 float distSqr = MathVector2SqrLen(normal);
1328 float radius = bodyA->shape.radius + bodyB->shape.radius;
1329
1330 // Check if circles are not in contact
1331 if (distSqr >= radius*radius)
1332 {
1333 manifold->contactsCount = 0;
1334 return;
1335 }
1336
1337 float distance = sqrtf(distSqr);
1338 manifold->contactsCount = 1;
1339
1340 if (distance == 0.0f)
1341 {
1342 manifold->penetration = bodyA->shape.radius;
1343 manifold->normal = CLITERAL(Vector2){ 1.0f, 0.0f };
1344 manifold->contacts[0] = bodyA->position;
1345 }
1346 else
1347 {
1348 manifold->penetration = radius - distance;
1349 manifold->normal = CLITERAL(Vector2){ normal.x/distance, normal.y/distance }; // Faster than using MathVector2Normalize() due to sqrt is already performed
1350 manifold->contacts[0] = CLITERAL(Vector2){ manifold->normal.x*bodyA->shape.radius + bodyA->position.x, manifold->normal.y*bodyA->shape.radius + bodyA->position.y };
1351 }
1352
1353 // Update physics body grounded state if normal direction is down
1354 if (!bodyA->isGrounded) bodyA->isGrounded = (manifold->normal.y < 0);
1355}
1356
1357// Solves collision between a circle to a polygon shape physics bodies
1358static void SolveCircleToPolygon(PhysicsManifold manifold)
1359{
1360 PhysicsBody bodyA = manifold->bodyA;
1361 PhysicsBody bodyB = manifold->bodyB;
1362
1363 if ((bodyA == NULL) || (bodyB == NULL)) return;
1364
1365 manifold->contactsCount = 0;
1366
1367 // Transform circle center to polygon transform space
1368 Vector2 center = bodyA->position;
1369 center = MathMatVector2Product(MathMatTranspose(bodyB->shape.transform), MathVector2Subtract(center, bodyB->position));
1370
1371 // Find edge with minimum penetration
1372 // It is the same concept as using support points in SolvePolygonToPolygon
1373 float separation = -PHYSAC_FLT_MAX;
1374 int faceNormal = 0;
1375 PhysicsVertexData vertexData = bodyB->shape.vertexData;
1376
1377 for (unsigned int i = 0; i < vertexData.vertexCount; i++)
1378 {
1379 float currentSeparation = MathVector2DotProduct(vertexData.normals[i], MathVector2Subtract(center, vertexData.positions[i]));
1380
1381 if (currentSeparation > bodyA->shape.radius) return;
1382
1383 if (currentSeparation > separation)
1384 {
1385 separation = currentSeparation;
1386 faceNormal = i;
1387 }
1388 }
1389
1390 // Grab face's vertices
1391 Vector2 v1 = vertexData.positions[faceNormal];
1392 int nextIndex = (((faceNormal + 1) < (int)vertexData.vertexCount) ? (faceNormal + 1) : 0);
1393 Vector2 v2 = vertexData.positions[nextIndex];
1394
1395 // Check to see if center is within polygon
1396 if (separation < PHYSAC_EPSILON)
1397 {
1398 manifold->contactsCount = 1;
1399 Vector2 normal = MathMatVector2Product(bodyB->shape.transform, vertexData.normals[faceNormal]);
1400 manifold->normal = CLITERAL(Vector2){ -normal.x, -normal.y };
1401 manifold->contacts[0] = CLITERAL(Vector2){ manifold->normal.x*bodyA->shape.radius + bodyA->position.x, manifold->normal.y*bodyA->shape.radius + bodyA->position.y };
1402 manifold->penetration = bodyA->shape.radius;
1403 return;
1404 }
1405
1406 // Determine which voronoi region of the edge center of circle lies within
1407 float dot1 = MathVector2DotProduct(MathVector2Subtract(center, v1), MathVector2Subtract(v2, v1));
1408 float dot2 = MathVector2DotProduct(MathVector2Subtract(center, v2), MathVector2Subtract(v1, v2));
1409 manifold->penetration = bodyA->shape.radius - separation;
1410
1411 if (dot1 <= 0.0f) // Closest to v1
1412 {
1413 if (MathVector2SqrDistance(center, v1) > bodyA->shape.radius*bodyA->shape.radius) return;
1414
1415 manifold->contactsCount = 1;
1416 Vector2 normal = MathVector2Subtract(v1, center);
1417 normal = MathMatVector2Product(bodyB->shape.transform, normal);
1418 MathVector2Normalize(&normal);
1419 manifold->normal = normal;
1420 v1 = MathMatVector2Product(bodyB->shape.transform, v1);
1421 v1 = MathVector2Add(v1, bodyB->position);
1422 manifold->contacts[0] = v1;
1423 }
1424 else if (dot2 <= 0.0f) // Closest to v2
1425 {
1426 if (MathVector2SqrDistance(center, v2) > bodyA->shape.radius*bodyA->shape.radius) return;
1427
1428 manifold->contactsCount = 1;
1429 Vector2 normal = MathVector2Subtract(v2, center);
1430 v2 = MathMatVector2Product(bodyB->shape.transform, v2);
1431 v2 = MathVector2Add(v2, bodyB->position);
1432 manifold->contacts[0] = v2;
1433 normal = MathMatVector2Product(bodyB->shape.transform, normal);
1434 MathVector2Normalize(&normal);
1435 manifold->normal = normal;
1436 }
1437 else // Closest to face
1438 {
1439 Vector2 normal = vertexData.normals[faceNormal];
1440
1441 if (MathVector2DotProduct(MathVector2Subtract(center, v1), normal) > bodyA->shape.radius) return;
1442
1443 normal = MathMatVector2Product(bodyB->shape.transform, normal);
1444 manifold->normal = CLITERAL(Vector2){ -normal.x, -normal.y };
1445 manifold->contacts[0] = CLITERAL(Vector2){ manifold->normal.x*bodyA->shape.radius + bodyA->position.x, manifold->normal.y*bodyA->shape.radius + bodyA->position.y };
1446 manifold->contactsCount = 1;
1447 }
1448}
1449
1450// Solves collision between a polygon to a circle shape physics bodies
1451static void SolvePolygonToCircle(PhysicsManifold manifold)
1452{
1453 PhysicsBody bodyA = manifold->bodyA;
1454 PhysicsBody bodyB = manifold->bodyB;
1455
1456 if ((bodyA == NULL) || (bodyB == NULL)) return;
1457
1458 manifold->bodyA = bodyB;
1459 manifold->bodyB = bodyA;
1460 SolveCircleToPolygon(manifold);
1461
1462 manifold->normal.x *= -1.0f;
1463 manifold->normal.y *= -1.0f;
1464}
1465
1466// Solves collision between two polygons shape physics bodies
1467static void SolvePolygonToPolygon(PhysicsManifold manifold)
1468{
1469 if ((manifold->bodyA == NULL) || (manifold->bodyB == NULL)) return;
1470
1471 PhysicsShape bodyA = manifold->bodyA->shape;
1472 PhysicsShape bodyB = manifold->bodyB->shape;
1473 manifold->contactsCount = 0;
1474
1475 // Check for separating axis with A shape's face planes
1476 int faceA = 0;
1477 float penetrationA = FindAxisLeastPenetration(&faceA, bodyA, bodyB);
1478 if (penetrationA >= 0.0f) return;
1479
1480 // Check for separating axis with B shape's face planes
1481 int faceB = 0;
1482 float penetrationB = FindAxisLeastPenetration(&faceB, bodyB, bodyA);
1483 if (penetrationB >= 0.0f) return;
1484
1485 int referenceIndex = 0;
1486 bool flip = false; // Always point from A shape to B shape
1487
1488 PhysicsShape refPoly; // Reference
1489 PhysicsShape incPoly; // Incident
1490
1491 // Determine which shape contains reference face
1492 // Checking bias range for penetration
1493 if (penetrationA >= (penetrationB*0.95f + penetrationA*0.01f))
1494 {
1495 refPoly = bodyA;
1496 incPoly = bodyB;
1497 referenceIndex = faceA;
1498 }
1499 else
1500 {
1501 refPoly = bodyB;
1502 incPoly = bodyA;
1503 referenceIndex = faceB;
1504 flip = true;
1505 }
1506
1507 // World space incident face
1508 Vector2 incidentFace[2];
1509 FindIncidentFace(&incidentFace[0], &incidentFace[1], refPoly, incPoly, referenceIndex);
1510
1511 // Setup reference face vertices
1512 PhysicsVertexData refData = refPoly.vertexData;
1513 Vector2 v1 = refData.positions[referenceIndex];
1514 referenceIndex = (((referenceIndex + 1) < (int)refData.vertexCount) ? (referenceIndex + 1) : 0);
1515 Vector2 v2 = refData.positions[referenceIndex];
1516
1517 // Transform vertices to world space
1518 v1 = MathMatVector2Product(refPoly.transform, v1);
1519 v1 = MathVector2Add(v1, refPoly.body->position);
1520 v2 = MathMatVector2Product(refPoly.transform, v2);
1521 v2 = MathVector2Add(v2, refPoly.body->position);
1522
1523 // Calculate reference face side normal in world space
1524 Vector2 sidePlaneNormal = MathVector2Subtract(v2, v1);
1525 MathVector2Normalize(&sidePlaneNormal);
1526
1527 // Orthogonalize
1528 Vector2 refFaceNormal = { sidePlaneNormal.y, -sidePlaneNormal.x };
1529 float refC = MathVector2DotProduct(refFaceNormal, v1);
1530 float negSide = MathVector2DotProduct(sidePlaneNormal, v1)*-1;
1531 float posSide = MathVector2DotProduct(sidePlaneNormal, v2);
1532
1533 // MathVector2Clip incident face to reference face side planes (due to floating point error, possible to not have required points
1534 if (MathVector2Clip(CLITERAL(Vector2){ -sidePlaneNormal.x, -sidePlaneNormal.y }, &incidentFace[0], &incidentFace[1], negSide) < 2) return;
1535 if (MathVector2Clip(sidePlaneNormal, &incidentFace[0], &incidentFace[1], posSide) < 2) return;
1536
1537 // Flip normal if required
1538 manifold->normal = (flip ? CLITERAL(Vector2){ -refFaceNormal.x, -refFaceNormal.y } : refFaceNormal);
1539
1540 // Keep points behind reference face
1541 int currentPoint = 0; // MathVector2Clipped points behind reference face
1542 float separation = MathVector2DotProduct(refFaceNormal, incidentFace[0]) - refC;
1543 if (separation <= 0.0f)
1544 {
1545 manifold->contacts[currentPoint] = incidentFace[0];
1546 manifold->penetration = -separation;
1547 currentPoint++;
1548 }
1549 else manifold->penetration = 0.0f;
1550
1551 separation = MathVector2DotProduct(refFaceNormal, incidentFace[1]) - refC;
1552
1553 if (separation <= 0.0f)
1554 {
1555 manifold->contacts[currentPoint] = incidentFace[1];
1556 manifold->penetration += -separation;
1557 currentPoint++;
1558
1559 // Calculate total penetration average
1560 manifold->penetration /= currentPoint;
1561 }
1562
1563 manifold->contactsCount = currentPoint;
1564}
1565
1566// Integrates physics forces into velocity
1567static void IntegratePhysicsForces(PhysicsBody body)
1568{
1569 if ((body == NULL) || (body->inverseMass == 0.0f) || !body->enabled) return;
1570
1571 body->velocity.x += (float)((body->force.x*body->inverseMass)*(deltaTime/2.0));
1572 body->velocity.y += (float)((body->force.y*body->inverseMass)*(deltaTime/2.0));
1573
1574 if (body->useGravity)
1575 {
1576 body->velocity.x += (float)(gravityForce.x*(deltaTime/1000/2.0));
1577 body->velocity.y += (float)(gravityForce.y*(deltaTime/1000/2.0));
1578 }
1579
1580 if (!body->freezeOrient) body->angularVelocity += (float)(body->torque*body->inverseInertia*(deltaTime/2.0));
1581}
1582
1583// Initializes physics manifolds to solve collisions
1584static void InitializePhysicsManifolds(PhysicsManifold manifold)
1585{
1586 PhysicsBody bodyA = manifold->bodyA;
1587 PhysicsBody bodyB = manifold->bodyB;
1588
1589 if ((bodyA == NULL) || (bodyB == NULL)) return;
1590
1591 // Calculate average restitution, static and dynamic friction
1592 manifold->restitution = sqrtf(bodyA->restitution*bodyB->restitution);
1593 manifold->staticFriction = sqrtf(bodyA->staticFriction*bodyB->staticFriction);
1594 manifold->dynamicFriction = sqrtf(bodyA->dynamicFriction*bodyB->dynamicFriction);
1595
1596 for (unsigned int i = 0; i < manifold->contactsCount; i++)
1597 {
1598 // Caculate radius from center of mass to contact
1599 Vector2 radiusA = MathVector2Subtract(manifold->contacts[i], bodyA->position);
1600 Vector2 radiusB = MathVector2Subtract(manifold->contacts[i], bodyB->position);
1601
1602 Vector2 crossA = MathVector2Product(radiusA, bodyA->angularVelocity);
1603 Vector2 crossB = MathVector2Product(radiusB, bodyB->angularVelocity);
1604
1605 Vector2 radiusV = { 0.0f, 0.0f };
1606 radiusV.x = bodyB->velocity.x + crossB.x - bodyA->velocity.x - crossA.x;
1607 radiusV.y = bodyB->velocity.y + crossB.y - bodyA->velocity.y - crossA.y;
1608
1609 // Determine if we should perform a resting collision or not;
1610 // The idea is if the only thing moving this object is gravity, then the collision should be performed without any restitution
1611 if (MathVector2SqrLen(radiusV) < (MathVector2SqrLen(CLITERAL(Vector2){ (float)(gravityForce.x*deltaTime/1000), (float)(gravityForce.y*deltaTime/1000) }) + PHYSAC_EPSILON)) manifold->restitution = 0;
1612 }
1613}
1614
1615// Integrates physics collisions impulses to solve collisions
1616static void IntegratePhysicsImpulses(PhysicsManifold manifold)
1617{
1618 PhysicsBody bodyA = manifold->bodyA;
1619 PhysicsBody bodyB = manifold->bodyB;
1620
1621 if ((bodyA == NULL) || (bodyB == NULL)) return;
1622
1623 // Early out and positional correct if both objects have infinite mass
1624 if (fabs(bodyA->inverseMass + bodyB->inverseMass) <= PHYSAC_EPSILON)
1625 {
1626 bodyA->velocity = PHYSAC_VECTOR_ZERO;
1627 bodyB->velocity = PHYSAC_VECTOR_ZERO;
1628 return;
1629 }
1630
1631 for (unsigned int i = 0; i < manifold->contactsCount; i++)
1632 {
1633 // Calculate radius from center of mass to contact
1634 Vector2 radiusA = MathVector2Subtract(manifold->contacts[i], bodyA->position);
1635 Vector2 radiusB = MathVector2Subtract(manifold->contacts[i], bodyB->position);
1636
1637 // Calculate relative velocity
1638 Vector2 radiusV = { 0.0f, 0.0f };
1639 radiusV.x = bodyB->velocity.x + MathVector2Product(radiusB, bodyB->angularVelocity).x - bodyA->velocity.x - MathVector2Product(radiusA, bodyA->angularVelocity).x;
1640 radiusV.y = bodyB->velocity.y + MathVector2Product(radiusB, bodyB->angularVelocity).y - bodyA->velocity.y - MathVector2Product(radiusA, bodyA->angularVelocity).y;
1641
1642 // Relative velocity along the normal
1643 float contactVelocity = MathVector2DotProduct(radiusV, manifold->normal);
1644
1645 // Do not resolve if velocities are separating
1646 if (contactVelocity > 0.0f) return;
1647
1648 float raCrossN = MathVector2CrossProduct(radiusA, manifold->normal);
1649 float rbCrossN = MathVector2CrossProduct(radiusB, manifold->normal);
1650
1651 float inverseMassSum = bodyA->inverseMass + bodyB->inverseMass + (raCrossN*raCrossN)*bodyA->inverseInertia + (rbCrossN*rbCrossN)*bodyB->inverseInertia;
1652
1653 // Calculate impulse scalar value
1654 float impulse = -(1.0f + manifold->restitution)*contactVelocity;
1655 impulse /= inverseMassSum;
1656 impulse /= (float)manifold->contactsCount;
1657
1658 // Apply impulse to each physics body
1659 Vector2 impulseV = { manifold->normal.x*impulse, manifold->normal.y*impulse };
1660
1661 if (bodyA->enabled)
1662 {
1663 bodyA->velocity.x += bodyA->inverseMass*(-impulseV.x);
1664 bodyA->velocity.y += bodyA->inverseMass*(-impulseV.y);
1665 if (!bodyA->freezeOrient) bodyA->angularVelocity += bodyA->inverseInertia*MathVector2CrossProduct(radiusA, CLITERAL(Vector2){ -impulseV.x, -impulseV.y });
1666 }
1667
1668 if (bodyB->enabled)
1669 {
1670 bodyB->velocity.x += bodyB->inverseMass*(impulseV.x);
1671 bodyB->velocity.y += bodyB->inverseMass*(impulseV.y);
1672 if (!bodyB->freezeOrient) bodyB->angularVelocity += bodyB->inverseInertia*MathVector2CrossProduct(radiusB, impulseV);
1673 }
1674
1675 // Apply friction impulse to each physics body
1676 radiusV.x = bodyB->velocity.x + MathVector2Product(radiusB, bodyB->angularVelocity).x - bodyA->velocity.x - MathVector2Product(radiusA, bodyA->angularVelocity).x;
1677 radiusV.y = bodyB->velocity.y + MathVector2Product(radiusB, bodyB->angularVelocity).y - bodyA->velocity.y - MathVector2Product(radiusA, bodyA->angularVelocity).y;
1678
1679 Vector2 tangent = { radiusV.x - (manifold->normal.x*MathVector2DotProduct(radiusV, manifold->normal)), radiusV.y - (manifold->normal.y*MathVector2DotProduct(radiusV, manifold->normal)) };
1680 MathVector2Normalize(&tangent);
1681
1682 // Calculate impulse tangent magnitude
1683 float impulseTangent = -MathVector2DotProduct(radiusV, tangent);
1684 impulseTangent /= inverseMassSum;
1685 impulseTangent /= (float)manifold->contactsCount;
1686
1687 float absImpulseTangent = (float)fabs(impulseTangent);
1688
1689 // Don't apply tiny friction impulses
1690 if (absImpulseTangent <= PHYSAC_EPSILON) return;
1691
1692 // Apply coulumb's law
1693 Vector2 tangentImpulse = { 0.0f, 0.0f };
1694 if (absImpulseTangent < impulse*manifold->staticFriction) tangentImpulse = CLITERAL(Vector2){ tangent.x*impulseTangent, tangent.y*impulseTangent };
1695 else tangentImpulse = CLITERAL(Vector2){ tangent.x*-impulse*manifold->dynamicFriction, tangent.y*-impulse*manifold->dynamicFriction };
1696
1697 // Apply friction impulse
1698 if (bodyA->enabled)
1699 {
1700 bodyA->velocity.x += bodyA->inverseMass*(-tangentImpulse.x);
1701 bodyA->velocity.y += bodyA->inverseMass*(-tangentImpulse.y);
1702
1703 if (!bodyA->freezeOrient) bodyA->angularVelocity += bodyA->inverseInertia*MathVector2CrossProduct(radiusA, CLITERAL(Vector2){ -tangentImpulse.x, -tangentImpulse.y });
1704 }
1705
1706 if (bodyB->enabled)
1707 {
1708 bodyB->velocity.x += bodyB->inverseMass*(tangentImpulse.x);
1709 bodyB->velocity.y += bodyB->inverseMass*(tangentImpulse.y);
1710
1711 if (!bodyB->freezeOrient) bodyB->angularVelocity += bodyB->inverseInertia*MathVector2CrossProduct(radiusB, tangentImpulse);
1712 }
1713 }
1714}
1715
1716// Integrates physics velocity into position and forces
1717static void IntegratePhysicsVelocity(PhysicsBody body)
1718{
1719 if ((body == NULL) ||!body->enabled) return;
1720
1721 body->position.x += (float)(body->velocity.x*deltaTime);
1722 body->position.y += (float)(body->velocity.y*deltaTime);
1723
1724 if (!body->freezeOrient) body->orient += (float)(body->angularVelocity*deltaTime);
1725 body->shape.transform = MathMatFromRadians(body->orient);
1726
1727 IntegratePhysicsForces(body);
1728}
1729
1730// Corrects physics bodies positions based on manifolds collision information
1731static void CorrectPhysicsPositions(PhysicsManifold manifold)
1732{
1733 PhysicsBody bodyA = manifold->bodyA;
1734 PhysicsBody bodyB = manifold->bodyB;
1735
1736 if ((bodyA == NULL) || (bodyB == NULL)) return;
1737
1738 Vector2 correction = { 0.0f, 0.0f };
1739 correction.x = (PHYSAC_MAX(manifold->penetration - PHYSAC_PENETRATION_ALLOWANCE, 0.0f)/(bodyA->inverseMass + bodyB->inverseMass))*manifold->normal.x*PHYSAC_PENETRATION_CORRECTION;
1740 correction.y = (PHYSAC_MAX(manifold->penetration - PHYSAC_PENETRATION_ALLOWANCE, 0.0f)/(bodyA->inverseMass + bodyB->inverseMass))*manifold->normal.y*PHYSAC_PENETRATION_CORRECTION;
1741
1742 if (bodyA->enabled)
1743 {
1744 bodyA->position.x -= correction.x*bodyA->inverseMass;
1745 bodyA->position.y -= correction.y*bodyA->inverseMass;
1746 }
1747
1748 if (bodyB->enabled)
1749 {
1750 bodyB->position.x += correction.x*bodyB->inverseMass;
1751 bodyB->position.y += correction.y*bodyB->inverseMass;
1752 }
1753}
1754
1755// Returns the extreme point along a direction within a polygon
1756static Vector2 GetSupport(PhysicsShape shape, Vector2 dir)
1757{
1758 float bestProjection = -PHYSAC_FLT_MAX;
1759 Vector2 bestVertex = { 0.0f, 0.0f };
1760 PhysicsVertexData data = shape.vertexData;
1761
1762 for (unsigned int i = 0; i < data.vertexCount; i++)
1763 {
1764 Vector2 vertex = data.positions[i];
1765 float projection = MathVector2DotProduct(vertex, dir);
1766
1767 if (projection > bestProjection)
1768 {
1769 bestVertex = vertex;
1770 bestProjection = projection;
1771 }
1772 }
1773
1774 return bestVertex;
1775}
1776
1777// Finds polygon shapes axis least penetration
1778static float FindAxisLeastPenetration(int *faceIndex, PhysicsShape shapeA, PhysicsShape shapeB)
1779{
1780 float bestDistance = -PHYSAC_FLT_MAX;
1781 int bestIndex = 0;
1782
1783 PhysicsVertexData dataA = shapeA.vertexData;
1784 //PhysicsVertexData dataB = shapeB.vertexData;
1785
1786 for (unsigned int i = 0; i < dataA.vertexCount; i++)
1787 {
1788 // Retrieve a face normal from A shape
1789 Vector2 normal = dataA.normals[i];
1790 Vector2 transNormal = MathMatVector2Product(shapeA.transform, normal);
1791
1792 // Transform face normal into B shape's model space
1793 Matrix2x2 buT = MathMatTranspose(shapeB.transform);
1794 normal = MathMatVector2Product(buT, transNormal);
1795
1796 // Retrieve support point from B shape along -n
1797 Vector2 support = GetSupport(shapeB, CLITERAL(Vector2){ -normal.x, -normal.y });
1798
1799 // Retrieve vertex on face from A shape, transform into B shape's model space
1800 Vector2 vertex = dataA.positions[i];
1801 vertex = MathMatVector2Product(shapeA.transform, vertex);
1802 vertex = MathVector2Add(vertex, shapeA.body->position);
1803 vertex = MathVector2Subtract(vertex, shapeB.body->position);
1804 vertex = MathMatVector2Product(buT, vertex);
1805
1806 // Compute penetration distance in B shape's model space
1807 float distance = MathVector2DotProduct(normal, MathVector2Subtract(support, vertex));
1808
1809 // Store greatest distance
1810 if (distance > bestDistance)
1811 {
1812 bestDistance = distance;
1813 bestIndex = i;
1814 }
1815 }
1816
1817 *faceIndex = bestIndex;
1818 return bestDistance;
1819}
1820
1821// Finds two polygon shapes incident face
1822static void FindIncidentFace(Vector2 *v0, Vector2 *v1, PhysicsShape ref, PhysicsShape inc, int index)
1823{
1824 PhysicsVertexData refData = ref.vertexData;
1825 PhysicsVertexData incData = inc.vertexData;
1826
1827 Vector2 referenceNormal = refData.normals[index];
1828
1829 // Calculate normal in incident's frame of reference
1830 referenceNormal = MathMatVector2Product(ref.transform, referenceNormal); // To world space
1831 referenceNormal = MathMatVector2Product(MathMatTranspose(inc.transform), referenceNormal); // To incident's model space
1832
1833 // Find most anti-normal face on polygon
1834 int incidentFace = 0;
1835 float minDot = PHYSAC_FLT_MAX;
1836
1837 for (unsigned int i = 0; i < incData.vertexCount; i++)
1838 {
1839 float dot = MathVector2DotProduct(referenceNormal, incData.normals[i]);
1840
1841 if (dot < minDot)
1842 {
1843 minDot = dot;
1844 incidentFace = i;
1845 }
1846 }
1847
1848 // Assign face vertices for incident face
1849 *v0 = MathMatVector2Product(inc.transform, incData.positions[incidentFace]);
1850 *v0 = MathVector2Add(*v0, inc.body->position);
1851 incidentFace = (((incidentFace + 1) < (int)incData.vertexCount) ? (incidentFace + 1) : 0);
1852 *v1 = MathMatVector2Product(inc.transform, incData.positions[incidentFace]);
1853 *v1 = MathVector2Add(*v1, inc.body->position);
1854}
1855
1856// Returns clipping value based on a normal and two faces
1857static int MathVector2Clip(Vector2 normal, Vector2 *faceA, Vector2 *faceB, float clip)
1858{
1859 int sp = 0;
1860 Vector2 out[2] = { *faceA, *faceB };
1861
1862 // Retrieve distances from each endpoint to the line
1863 float distanceA = MathVector2DotProduct(normal, *faceA) - clip;
1864 float distanceB = MathVector2DotProduct(normal, *faceB) - clip;
1865
1866 // If negative (behind plane)
1867 if (distanceA <= 0.0f) out[sp++] = *faceA;
1868 if (distanceB <= 0.0f) out[sp++] = *faceB;
1869
1870 // If the points are on different sides of the plane
1871 if ((distanceA*distanceB) < 0.0f)
1872 {
1873 // Push intersection point
1874 float alpha = distanceA/(distanceA - distanceB);
1875 out[sp] = *faceA;
1876 Vector2 delta = MathVector2Subtract(*faceB, *faceA);
1877 delta.x *= alpha;
1878 delta.y *= alpha;
1879 out[sp] = MathVector2Add(out[sp], delta);
1880 sp++;
1881 }
1882
1883 // Assign the new converted values
1884 *faceA = out[0];
1885 *faceB = out[1];
1886
1887 return sp;
1888}
1889
1890// Returns the barycenter of a triangle given by 3 points
1891static Vector2 MathTriangleBarycenter(Vector2 v1, Vector2 v2, Vector2 v3)
1892{
1893 Vector2 result = { 0.0f, 0.0f };
1894
1895 result.x = (v1.x + v2.x + v3.x)/3;
1896 result.y = (v1.y + v2.y + v3.y)/3;
1897
1898 return result;
1899}
1900
1901// Returns the cross product of a vector and a value
1902static inline Vector2 MathVector2Product(Vector2 vector, float value)
1903{
1904 Vector2 result = { -value*vector.y, value*vector.x };
1905 return result;
1906}
1907
1908// Returns the cross product of two vectors
1909static inline float MathVector2CrossProduct(Vector2 v1, Vector2 v2)
1910{
1911 return (v1.x*v2.y - v1.y*v2.x);
1912}
1913
1914// Returns the len square root of a vector
1915static inline float MathVector2SqrLen(Vector2 vector)
1916{
1917 return (vector.x*vector.x + vector.y*vector.y);
1918}
1919
1920// Returns the dot product of two vectors
1921static inline float MathVector2DotProduct(Vector2 v1, Vector2 v2)
1922{
1923 return (v1.x*v2.x + v1.y*v2.y);
1924}
1925
1926// Returns the square root of distance between two vectors
1927static inline float MathVector2SqrDistance(Vector2 v1, Vector2 v2)
1928{
1929 Vector2 dir = MathVector2Subtract(v1, v2);
1930 return MathVector2DotProduct(dir, dir);
1931}
1932
1933// Returns the normalized values of a vector
1934static void MathVector2Normalize(Vector2 *vector)
1935{
1936 float length, ilength;
1937
1938 Vector2 aux = *vector;
1939 length = sqrtf(aux.x*aux.x + aux.y*aux.y);
1940
1941 if (length == 0) length = 1.0f;
1942
1943 ilength = 1.0f/length;
1944
1945 vector->x *= ilength;
1946 vector->y *= ilength;
1947}
1948
1949// Returns the sum of two given vectors
1950static inline Vector2 MathVector2Add(Vector2 v1, Vector2 v2)
1951{
1952 Vector2 result = { v1.x + v2.x, v1.y + v2.y };
1953 return result;
1954}
1955
1956// Returns the subtract of two given vectors
1957static inline Vector2 MathVector2Subtract(Vector2 v1, Vector2 v2)
1958{
1959 Vector2 result = { v1.x - v2.x, v1.y - v2.y };
1960 return result;
1961}
1962
1963// Creates a matrix 2x2 from a given radians value
1964static Matrix2x2 MathMatFromRadians(float radians)
1965{
1966 float cos = cosf(radians);
1967 float sin = sinf(radians);
1968
1969 Matrix2x2 result = { cos, -sin, sin, cos };
1970 return result;
1971}
1972
1973// Returns the transpose of a given matrix 2x2
1974static inline Matrix2x2 MathMatTranspose(Matrix2x2 matrix)
1975{
1976 Matrix2x2 result = { matrix.m00, matrix.m10, matrix.m01, matrix.m11 };
1977 return result;
1978}
1979
1980// Multiplies a vector by a matrix 2x2
1981static inline Vector2 MathMatVector2Product(Matrix2x2 matrix, Vector2 vector)
1982{
1983 Vector2 result = { matrix.m00*vector.x + matrix.m01*vector.y, matrix.m10*vector.x + matrix.m11*vector.y };
1984 return result;
1985}
1986
1987#endif // PHYSAC_IMPLEMENTATION
void * id
#define NULL
Definition: miniaudio.h:3718
#define PHYSAC_COLLISION_ITERATIONS
Definition: physac.h:108
PHYSACDEF void SetPhysicsTimeStep(double delta)
#define PHYSAC_MAX_BODIES
Definition: physac.h:103
PHYSACDEF PhysicsBody CreatePhysicsBodyCircle(Vector2 pos, float radius, float density)
struct PhysicsBodyData * PhysicsBody
Definition: physac.h:125
PHYSACDEF int GetPhysicsBodiesCount(void)
PHYSACDEF void SetPhysicsGravity(float x, float y)
#define PHYSAC_DEFAULT_CIRCLE_VERTICES
Definition: physac.h:106
PHYSACDEF void UpdatePhysics(void)
#define PHYSAC_FREE(ptr)
Definition: physac.h:97
struct PhysicsManifoldData * PhysicsManifold
PHYSACDEF int GetPhysicsShapeVerticesCount(int index)
PHYSACDEF void InitPhysics(void)
PHYSACDEF void SetPhysicsBodyRotation(PhysicsBody body, float radians)
struct Vector2 Vector2
PHYSACDEF void PhysicsShatter(PhysicsBody body, Vector2 position, float force)
PHYSACDEF void DestroyPhysicsBody(PhysicsBody body)
PHYSACDEF void PhysicsAddTorque(PhysicsBody body, float amount)
#define PHYSAC_MAX_MANIFOLDS
Definition: physac.h:104
PHYSACDEF void ClosePhysics(void)
#define PHYSAC_MAX_VERTICES
Definition: physac.h:105
#define PHYSAC_DEG2RAD
Definition: physac.h:113
PHYSACDEF PhysicsBody CreatePhysicsBodyRectangle(Vector2 pos, float width, float height, float density)
PHYSACDEF PhysicsBody GetPhysicsBody(int index)
#define PHYSAC_PENETRATION_CORRECTION
Definition: physac.h:110
PHYSACDEF Vector2 GetPhysicsShapeVertex(PhysicsBody body, int vertex)
PHYSACDEF void ResetPhysics(void)
#define PHYSACDEF
Physac v1.1 - 2D Physics library for videogames.
Definition: physac.h:86
#define PHYSAC_MALLOC(size)
Definition: physac.h:91
PHYSACDEF PhysicsBody CreatePhysicsBodyPolygon(Vector2 pos, float radius, int sides, float density)
#define PHYSAC_PENETRATION_ALLOWANCE
Definition: physac.h:109
PHYSACDEF int GetPhysicsShapeType(int index)
PhysicsShapeType
Definition: physac.h:122
@ PHYSICS_POLYGON
Definition: physac.h:122
@ PHYSICS_CIRCLE
Definition: physac.h:122
#define PHYSAC_CALLOC(size, n)
Definition: physac.h:94
PHYSACDEF void PhysicsAddForce(PhysicsBody body, Vector2 force)
#define TRACELOG(level,...)
Definition: raygui.h:222
#define CLITERAL(type)
Definition: raylib.h:131
float m10
Definition: physac.h:139
float m01
Definition: physac.h:138
float m11
Definition: physac.h:140
float m00
Definition: physac.h:137
Vector2 velocity
Definition: physac.h:161
PhysicsShape shape
Definition: physac.h:176
bool enabled
Definition: physac.h:159
float dynamicFriction
Definition: physac.h:171
bool useGravity
Definition: physac.h:173
float inertia
Definition: physac.h:166
bool isGrounded
Definition: physac.h:174
float angularVelocity
Definition: physac.h:163
float torque
Definition: physac.h:164
bool freezeOrient
Definition: physac.h:175
float mass
Definition: physac.h:168
Vector2 force
Definition: physac.h:162
float inverseInertia
Definition: physac.h:167
unsigned int id
Definition: physac.h:158
float inverseMass
Definition: physac.h:169
Vector2 position
Definition: physac.h:160
float orient
Definition: physac.h:165
float restitution
Definition: physac.h:172
float staticFriction
Definition: physac.h:170
unsigned int id
Definition: physac.h:180
float staticFriction
Definition: physac.h:189
float dynamicFriction
Definition: physac.h:188
Vector2 contacts[2]
Definition: physac.h:185
unsigned int contactsCount
Definition: physac.h:186
PhysicsBody bodyA
Definition: physac.h:181
PhysicsBody bodyB
Definition: physac.h:182
Vector2 normal
Definition: physac.h:184
PhysicsBody body
Definition: physac.h:151
Matrix2x2 transform
Definition: physac.h:154
PhysicsShapeType type
Definition: physac.h:150
float radius
Definition: physac.h:153
PhysicsVertexData vertexData
Definition: physac.h:152
unsigned int vertexCount
Definition: physac.h:144
Vector2 positions[PHYSAC_MAX_VERTICES]
Definition: physac.h:145
Vector2 normals[PHYSAC_MAX_VERTICES]
Definition: physac.h:146
float x
Definition: physac.h:130
float y
Definition: physac.h:131