REVIEWED: PHYSACDEF definition and C++ issues #1918

This commit is contained in:
raysan5 2021-08-15 12:52:12 +02:00
parent 092435d51c
commit 760cfd361e

View File

@ -16,16 +16,9 @@
* If not defined, the library is in header only mode and can be included in other headers * 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. * 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_DEBUG * #define PHYSAC_DEBUG
* Show debug traces log messages about physic bodies creation/destruction, physic system errors, * Show debug traces log messages about physic bodies creation/destruction, physic system errors,
* some calculations results and NULL reference exceptions * some calculations results and NULL reference exceptions.
*
* #define PHYSAC_DEFINE_VECTOR2_TYPE
* Forces library to define struct Vector2 data type (float x; float y)
* *
* #define PHYSAC_AVOID_TIMMING_SYSTEM * #define PHYSAC_AVOID_TIMMING_SYSTEM
* Disables internal timming system, used by UpdatePhysics() to launch timmed physic steps, * Disables internal timming system, used by UpdatePhysics() to launch timmed physic steps,
@ -79,14 +72,8 @@
#if !defined(PHYSAC_H) #if !defined(PHYSAC_H)
#define PHYSAC_H #define PHYSAC_H
#if defined(PHYSAC_STATIC) #ifndef PHYSACDEF
#define PHYSACDEF static // Functions just visible to module including this file #define PHYSACDEF // We are building or using physac as a static library
#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 #endif
// Allow custom memory allocators // Allow custom memory allocators
@ -127,7 +114,7 @@ typedef enum PhysicsShapeType { PHYSICS_CIRCLE = 0, PHYSICS_POLYGON } PhysicsSha
// Previously defined to be used in PhysicsShape struct as circular dependencies // Previously defined to be used in PhysicsShape struct as circular dependencies
typedef struct PhysicsBodyData *PhysicsBody; typedef struct PhysicsBodyData *PhysicsBody;
#if defined(PHYSAC_DEFINE_VECTOR2_TYPE) #if !defined(RL_VECTOR2_TYPE)
// Vector2 type // Vector2 type
typedef struct Vector2 { typedef struct Vector2 {
float x; float x;
@ -192,13 +179,13 @@ typedef struct PhysicsManifoldData {
float staticFriction; // Mixed static friction during collision float staticFriction; // Mixed static friction during collision
} PhysicsManifoldData, *PhysicsManifold; } PhysicsManifoldData, *PhysicsManifold;
#if defined(__cplusplus)
extern "C" { // Prevents name mangling of functions
#endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Functions Declaration // Module Functions Declaration
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(__cplusplus)
extern "C" { // Prevents name mangling of functions
#endif
// Physics system management // Physics system management
PHYSACDEF void InitPhysics(void); // Initializes physics system PHYSACDEF void InitPhysics(void); // Initializes physics system
PHYSACDEF void UpdatePhysics(void); // Update physics system PHYSACDEF void UpdatePhysics(void); // Update physics system
@ -225,7 +212,6 @@ PHYSACDEF int GetPhysicsBodiesCount(void);
PHYSACDEF int GetPhysicsShapeType(int index); // Returns the physics body shape type (PHYSICS_CIRCLE or PHYSICS_POLYGON) 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 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 Vector2 GetPhysicsShapeVertex(PhysicsBody body, int vertex); // Returns transformed position of a body shape (body position + vertex transformed position)
#if defined(__cplusplus) #if defined(__cplusplus)
} }
#endif #endif
@ -253,11 +239,17 @@ PHYSACDEF Vector2 GetPhysicsShapeVertex(PhysicsBody body, int vertex);
#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) #if !defined(PHYSAC_AVOID_TIMMING_SYSTEM)
// Time management functionality // Time management functionality
#include <time.h> // Required for: time(), clock_gettime() #include <time.h> // Required for: time(), clock_gettime()
#if defined(_WIN32) #if defined(_WIN32)
#if defined(__cplusplus)
extern "C" { // Prevents name mangling of functions
#endif
// Functions required to query time on Windows // Functions required to query time on Windows
int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount); int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount);
int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency); int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency);
#if defined(__cplusplus)
}
#endif
#endif #endif
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__linux__) || defined(__FreeBSD__)
#if _POSIX_C_SOURCE < 199309L #if _POSIX_C_SOURCE < 199309L
@ -366,7 +358,7 @@ static Vector2 MathTriangleBarycenter(Vector2 v1, Vector2 v2, Vector2 v3);
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Initializes physics values, pointers and creates physics loop thread // Initializes physics values, pointers and creates physics loop thread
PHYSACDEF void InitPhysics(void) void InitPhysics(void)
{ {
#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) #if !defined(PHYSAC_AVOID_TIMMING_SYSTEM)
// Initialize high resolution timer // Initialize high resolution timer
@ -377,21 +369,21 @@ PHYSACDEF void InitPhysics(void)
} }
// Sets physics global gravity force // Sets physics global gravity force
PHYSACDEF void SetPhysicsGravity(float x, float y) void SetPhysicsGravity(float x, float y)
{ {
gravityForce.x = x; gravityForce.x = x;
gravityForce.y = y; gravityForce.y = y;
} }
// Creates a new circle physics body with generic parameters // Creates a new circle physics body with generic parameters
PHYSACDEF PhysicsBody CreatePhysicsBodyCircle(Vector2 pos, float radius, float density) PhysicsBody CreatePhysicsBodyCircle(Vector2 pos, float radius, float density)
{ {
PhysicsBody body = CreatePhysicsBodyPolygon(pos, radius, PHYSAC_DEFAULT_CIRCLE_VERTICES, density); PhysicsBody body = CreatePhysicsBodyPolygon(pos, radius, PHYSAC_DEFAULT_CIRCLE_VERTICES, density);
return body; return body;
} }
// Creates a new rectangle physics body with generic parameters // Creates a new rectangle physics body with generic parameters
PHYSACDEF PhysicsBody CreatePhysicsBodyRectangle(Vector2 pos, float width, float height, float density) PhysicsBody CreatePhysicsBodyRectangle(Vector2 pos, float width, float height, float density)
{ {
// NOTE: Make sure body data is initialized to 0 // NOTE: Make sure body data is initialized to 0
PhysicsBody body = (PhysicsBody)PHYSAC_CALLOC(sizeof(PhysicsBodyData), 1); PhysicsBody body = (PhysicsBody)PHYSAC_CALLOC(sizeof(PhysicsBodyData), 1);
@ -469,7 +461,7 @@ PHYSACDEF PhysicsBody CreatePhysicsBodyRectangle(Vector2 pos, float width, float
} }
// Creates a new polygon physics body with generic parameters // Creates a new polygon physics body with generic parameters
PHYSACDEF PhysicsBody CreatePhysicsBodyPolygon(Vector2 pos, float radius, int sides, float density) PhysicsBody CreatePhysicsBodyPolygon(Vector2 pos, float radius, int sides, float density)
{ {
PhysicsBody body = (PhysicsBody)PHYSAC_MALLOC(sizeof(PhysicsBodyData)); PhysicsBody body = (PhysicsBody)PHYSAC_MALLOC(sizeof(PhysicsBodyData));
usedMemory += sizeof(PhysicsBodyData); usedMemory += sizeof(PhysicsBodyData);
@ -551,19 +543,19 @@ PHYSACDEF PhysicsBody CreatePhysicsBodyPolygon(Vector2 pos, float radius, int si
} }
// Adds a force to a physics body // Adds a force to a physics body
PHYSACDEF void PhysicsAddForce(PhysicsBody body, Vector2 force) void PhysicsAddForce(PhysicsBody body, Vector2 force)
{ {
if (body != NULL) body->force = MathVector2Add(body->force, force); if (body != NULL) body->force = MathVector2Add(body->force, force);
} }
// Adds an angular force to a physics body // Adds an angular force to a physics body
PHYSACDEF void PhysicsAddTorque(PhysicsBody body, float amount) void PhysicsAddTorque(PhysicsBody body, float amount)
{ {
if (body != NULL) body->torque += amount; if (body != NULL) body->torque += amount;
} }
// Shatters a polygon shape physics body to little physics bodies with explosion force // Shatters a polygon shape physics body to little physics bodies with explosion force
PHYSACDEF void PhysicsShatter(PhysicsBody body, Vector2 position, float force) void PhysicsShatter(PhysicsBody body, Vector2 position, float force)
{ {
if (body != NULL) if (body != NULL)
{ {
@ -700,13 +692,13 @@ PHYSACDEF void PhysicsShatter(PhysicsBody body, Vector2 position, float force)
} }
// Returns the current amount of created physics bodies // Returns the current amount of created physics bodies
PHYSACDEF int GetPhysicsBodiesCount(void) int GetPhysicsBodiesCount(void)
{ {
return physicsBodiesCount; return physicsBodiesCount;
} }
// Returns a physics body of the bodies pool at a specific index // Returns a physics body of the bodies pool at a specific index
PHYSACDEF PhysicsBody GetPhysicsBody(int index) PhysicsBody GetPhysicsBody(int index)
{ {
PhysicsBody body = NULL; PhysicsBody body = NULL;
@ -722,7 +714,7 @@ PHYSACDEF PhysicsBody GetPhysicsBody(int index)
} }
// Returns the physics body shape type (PHYSICS_CIRCLE or PHYSICS_POLYGON) // Returns the physics body shape type (PHYSICS_CIRCLE or PHYSICS_POLYGON)
PHYSACDEF int GetPhysicsShapeType(int index) int GetPhysicsShapeType(int index)
{ {
int result = -1; int result = -1;
@ -739,7 +731,7 @@ PHYSACDEF int GetPhysicsShapeType(int index)
} }
// Returns the amount of vertices of a physics body shape // Returns the amount of vertices of a physics body shape
PHYSACDEF int GetPhysicsShapeVerticesCount(int index) int GetPhysicsShapeVerticesCount(int index)
{ {
int result = 0; int result = 0;
@ -764,7 +756,7 @@ PHYSACDEF int GetPhysicsShapeVerticesCount(int index)
} }
// Returns transformed position of a body shape (body position + vertex transformed position) // Returns transformed position of a body shape (body position + vertex transformed position)
PHYSACDEF Vector2 GetPhysicsShapeVertex(PhysicsBody body, int vertex) Vector2 GetPhysicsShapeVertex(PhysicsBody body, int vertex)
{ {
Vector2 position = { 0.0f, 0.0f }; Vector2 position = { 0.0f, 0.0f };
@ -791,7 +783,7 @@ PHYSACDEF Vector2 GetPhysicsShapeVertex(PhysicsBody body, int vertex)
} }
// Sets physics body shape transform based on radians parameter // Sets physics body shape transform based on radians parameter
PHYSACDEF void SetPhysicsBodyRotation(PhysicsBody body, float radians) void SetPhysicsBodyRotation(PhysicsBody body, float radians)
{ {
if (body != NULL) if (body != NULL)
{ {
@ -802,7 +794,7 @@ PHYSACDEF void SetPhysicsBodyRotation(PhysicsBody body, float radians)
} }
// Unitializes and destroys a physics body // Unitializes and destroys a physics body
PHYSACDEF void DestroyPhysicsBody(PhysicsBody body) void DestroyPhysicsBody(PhysicsBody body)
{ {
if (body != NULL) if (body != NULL)
{ {
@ -844,7 +836,7 @@ PHYSACDEF void DestroyPhysicsBody(PhysicsBody body)
} }
// Destroys created physics bodies and manifolds and resets global values // Destroys created physics bodies and manifolds and resets global values
PHYSACDEF void ResetPhysics(void) void ResetPhysics(void)
{ {
if (physicsBodiesCount > 0) if (physicsBodiesCount > 0)
{ {
@ -886,7 +878,7 @@ PHYSACDEF void ResetPhysics(void)
} }
// Unitializes physics pointers and exits physics loop thread // Unitializes physics pointers and exits physics loop thread
PHYSACDEF void ClosePhysics(void) void ClosePhysics(void)
{ {
// Unitialize physics manifolds dynamic memory allocations // Unitialize physics manifolds dynamic memory allocations
if (physicsManifoldsCount > 0) if (physicsManifoldsCount > 0)
@ -912,91 +904,98 @@ PHYSACDEF void ClosePhysics(void)
else TRACELOG("[PHYSAC] Physics module closed successfully\n"); else TRACELOG("[PHYSAC] Physics module closed successfully\n");
} }
// Update physics system
// Physics steps are launched at a fixed time step if enabled
void UpdatePhysics(void)
{
#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM)
static double deltaTimeAccumulator = 0.0;
// Calculate current time (ms)
currentTime = GetCurrentTime();
// Calculate current delta time (ms)
const double delta = currentTime - startTime;
// Store the time elapsed since the last frame began
deltaTimeAccumulator += delta;
// Fixed time stepping loop
while (deltaTimeAccumulator >= deltaTime)
{
UpdatePhysicsStep();
deltaTimeAccumulator -= deltaTime;
}
// Record the starting of this frame
startTime = currentTime;
#else
UpdatePhysicsStep();
#endif
}
void SetPhysicsTimeStep(double delta)
{
deltaTime = delta;
}
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Internal Functions Definition // Module Internal Functions Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Finds a valid index for a new physics body initialization #if !defined(PHYSAC_AVOID_TIMMING_SYSTEM)
static int FindAvailableBodyIndex() // Initializes hi-resolution MONOTONIC timer
static void InitTimerHiRes(void)
{ {
int index = -1; #if defined(_WIN32)
for (int i = 0; i < PHYSAC_MAX_BODIES; i++) QueryPerformanceFrequency((unsigned long long int *) &frequency);
{ #endif
int currentId = i;
// Check if current id already exist in other physics body #if defined(__EMSCRIPTEN__) || defined(__linux__)
for (unsigned int k = 0; k < physicsBodiesCount; k++) struct timespec now;
{ if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) frequency = 1000000000;
if (bodies[k]->id == currentId) #endif
{
currentId++;
break;
}
}
// If it is not used, use it as new physics body id #if defined(__APPLE__)
if (currentId == (int)i) mach_timebase_info_data_t timebase;
{ mach_timebase_info(&timebase);
index = (int)i; frequency = (timebase.denom*1e9)/timebase.numer;
break; #endif
}
}
return index; baseClockTicks = (double)GetClockTicks(); // Get MONOTONIC clock time offset
startTime = GetCurrentTime(); // Get current time in milliseconds
} }
// Creates a default polygon shape with max vertex distance from polygon pivot // Get hi-res MONOTONIC time measure in clock ticks
static PhysicsVertexData CreateDefaultPolygon(float radius, int sides) static unsigned long long int GetClockTicks(void)
{ {
PhysicsVertexData data = { 0 }; unsigned long long int value = 0;
data.vertexCount = sides;
// Calculate polygon vertices positions #if defined(_WIN32)
for (unsigned int i = 0; i < data.vertexCount; i++) QueryPerformanceCounter((unsigned long long int *) &value);
{ #endif
data.positions[i].x = (float)cosf(360.0f/sides*i*PHYSAC_DEG2RAD)*radius;
data.positions[i].y = (float)sinf(360.0f/sides*i*PHYSAC_DEG2RAD)*radius;
}
// Calculate polygon faces normals #if defined(__linux__)
for (int i = 0; i < (int)data.vertexCount; i++) struct timespec now;
{ clock_gettime(CLOCK_MONOTONIC, &now);
int nextIndex = (((i + 1) < sides) ? (i + 1) : 0); value = (unsigned long long int)now.tv_sec*(unsigned long long int)1000000000 + (unsigned long long int)now.tv_nsec;
Vector2 face = MathVector2Subtract(data.positions[nextIndex], data.positions[i]); #endif
data.normals[i] = CLITERAL(Vector2){ face.y, -face.x }; #if defined(__APPLE__)
MathVector2Normalize(&data.normals[i]); value = mach_absolute_time();
} #endif
return data; return value;
} }
// Creates a rectangle polygon shape based on a min and max positions // Get current time in milliseconds
static PhysicsVertexData CreateRectanglePolygon(Vector2 pos, Vector2 size) static double GetCurrentTime(void)
{ {
PhysicsVertexData data = { 0 }; return (double)(GetClockTicks() - baseClockTicks)/frequency*1000;
data.vertexCount = 4;
// Calculate polygon vertices positions
data.positions[0] = CLITERAL(Vector2){ pos.x + size.x/2, pos.y - size.y/2 };
data.positions[1] = CLITERAL(Vector2){ pos.x + size.x/2, pos.y + size.y/2 };
data.positions[2] = CLITERAL(Vector2){ pos.x - size.x/2, pos.y + size.y/2 };
data.positions[3] = CLITERAL(Vector2){ pos.x - size.x/2, pos.y - size.y/2 };
// Calculate polygon faces normals
for (unsigned int i = 0; i < data.vertexCount; i++)
{
int nextIndex = (((i + 1) < data.vertexCount) ? (i + 1) : 0);
Vector2 face = MathVector2Subtract(data.positions[nextIndex], data.positions[i]);
data.normals[i] = CLITERAL(Vector2){ face.y, -face.x };
MathVector2Normalize(&data.normals[i]);
}
return data;
} }
#endif // !PHYSAC_AVOID_TIMMING_SYSTEM
// Update physics step (dynamics, collisions and position corrections) // Update physics step (dynamics, collisions and position corrections)
void UpdatePhysicsStep(void) static void UpdatePhysicsStep(void)
{ {
// Clear previous generated collisions information // Clear previous generated collisions information
for (int i = (int)physicsManifoldsCount - 1; i >= 0; i--) for (int i = (int)physicsManifoldsCount - 1; i >= 0; i--)
@ -1098,39 +1097,84 @@ void UpdatePhysicsStep(void)
} }
} }
// Update physics system // Finds a valid index for a new physics body initialization
// Physics steps are launched at a fixed time step if enabled static int FindAvailableBodyIndex()
PHYSACDEF void UpdatePhysics(void)
{ {
#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) int index = -1;
static double deltaTimeAccumulator = 0.0; for (int i = 0; i < PHYSAC_MAX_BODIES; i++)
// Calculate current time (ms)
currentTime = GetCurrentTime();
// Calculate current delta time (ms)
const double delta = currentTime - startTime;
// Store the time elapsed since the last frame began
deltaTimeAccumulator += delta;
// Fixed time stepping loop
while (deltaTimeAccumulator >= deltaTime)
{ {
UpdatePhysicsStep(); int currentId = i;
deltaTimeAccumulator -= deltaTime;
// Check if current id already exist in other physics body
for (unsigned int k = 0; k < physicsBodiesCount; k++)
{
if (bodies[k]->id == currentId)
{
currentId++;
break;
}
}
// If it is not used, use it as new physics body id
if (currentId == (int)i)
{
index = (int)i;
break;
}
} }
// Record the starting of this frame return index;
startTime = currentTime;
#else
UpdatePhysicsStep();
#endif
} }
PHYSACDEF void SetPhysicsTimeStep(double delta) // Creates a default polygon shape with max vertex distance from polygon pivot
static PhysicsVertexData CreateDefaultPolygon(float radius, int sides)
{ {
deltaTime = delta; PhysicsVertexData data = { 0 };
data.vertexCount = sides;
// Calculate polygon vertices positions
for (unsigned int i = 0; i < data.vertexCount; i++)
{
data.positions[i].x = (float)cosf(360.0f/sides*i*PHYSAC_DEG2RAD)*radius;
data.positions[i].y = (float)sinf(360.0f/sides*i*PHYSAC_DEG2RAD)*radius;
}
// Calculate polygon faces normals
for (int i = 0; i < (int)data.vertexCount; i++)
{
int nextIndex = (((i + 1) < sides) ? (i + 1) : 0);
Vector2 face = MathVector2Subtract(data.positions[nextIndex], data.positions[i]);
data.normals[i] = CLITERAL(Vector2){ face.y, -face.x };
MathVector2Normalize(&data.normals[i]);
}
return data;
}
// Creates a rectangle polygon shape based on a min and max positions
static PhysicsVertexData CreateRectanglePolygon(Vector2 pos, Vector2 size)
{
PhysicsVertexData data = { 0 };
data.vertexCount = 4;
// Calculate polygon vertices positions
data.positions[0] = CLITERAL(Vector2){ pos.x + size.x/2, pos.y - size.y/2 };
data.positions[1] = CLITERAL(Vector2){ pos.x + size.x/2, pos.y + size.y/2 };
data.positions[2] = CLITERAL(Vector2){ pos.x - size.x/2, pos.y + size.y/2 };
data.positions[3] = CLITERAL(Vector2){ pos.x - size.x/2, pos.y - size.y/2 };
// Calculate polygon faces normals
for (unsigned int i = 0; i < data.vertexCount; i++)
{
int nextIndex = (((i + 1) < data.vertexCount) ? (i + 1) : 0);
Vector2 face = MathVector2Subtract(data.positions[nextIndex], data.positions[i]);
data.normals[i] = CLITERAL(Vector2){ face.y, -face.x };
MathVector2Normalize(&data.normals[i]);
}
return data;
} }
// Finds a valid index for a new manifold initialization // Finds a valid index for a new manifold initialization
@ -1844,59 +1888,6 @@ static Vector2 MathTriangleBarycenter(Vector2 v1, Vector2 v2, Vector2 v3)
return result; return result;
} }
#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM)
// Initializes hi-resolution MONOTONIC timer
static void InitTimerHiRes(void)
{
#if defined(_WIN32)
QueryPerformanceFrequency((unsigned long long int *) &frequency);
#endif
#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
baseClockTicks = (double)GetClockTicks(); // Get MONOTONIC clock time offset
startTime = GetCurrentTime(); // Get current time in milliseconds
}
// Get hi-res MONOTONIC time measure in clock ticks
static unsigned long long int GetClockTicks(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)(GetClockTicks() - baseClockTicks)/frequency*1000;
}
#endif // !PHYSAC_AVOID_TIMMING_SYSTEM
// Returns the cross product of a vector and a value // Returns the cross product of a vector and a value
static inline Vector2 MathVector2Product(Vector2 vector, float value) static inline Vector2 MathVector2Product(Vector2 vector, float value)
{ {