From 8da566d6e7cb9f36d523e4d3b8f52e52079f27bc Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 6 Jun 2022 11:00:06 +0200 Subject: [PATCH] WARNING: Removed `physac` from raylib sources/examples `physac` is available on its own repo --- examples/Makefile | 11 +- examples/Makefile.Web | 31 +- examples/README.md | 12 - examples/physics/physics_demo.c | 128 -- examples/physics/physics_demo.png | Bin 23466 -> 0 bytes examples/physics/physics_friction.c | 142 -- examples/physics/physics_friction.png | Bin 18150 -> 0 bytes examples/physics/physics_movement.c | 128 -- examples/physics/physics_movement.png | Bin 15947 -> 0 bytes examples/physics/physics_restitution.c | 129 -- examples/physics/physics_restitution.png | Bin 17833 -> 0 bytes examples/physics/physics_shatter.c | 111 -- examples/physics/physics_shatter.png | Bin 23197 -> 0 bytes src/extras/physac.h | 1987 ---------------------- 14 files changed, 3 insertions(+), 2676 deletions(-) delete mode 100644 examples/physics/physics_demo.c delete mode 100644 examples/physics/physics_demo.png delete mode 100644 examples/physics/physics_friction.c delete mode 100644 examples/physics/physics_friction.png delete mode 100644 examples/physics/physics_movement.c delete mode 100644 examples/physics/physics_movement.png delete mode 100644 examples/physics/physics_restitution.c delete mode 100644 examples/physics/physics_restitution.png delete mode 100644 examples/physics/physics_shatter.c delete mode 100644 examples/physics/physics_shatter.png delete mode 100644 src/extras/physac.h diff --git a/examples/Makefile b/examples/Makefile index 1ab0b6c6..67df5989 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -494,20 +494,12 @@ AUDIO = \ audio/audio_sound_loading \ audio/audio_multichannel_sound -PHYSICS = \ - physics/physics_demo \ - physics/physics_friction \ - physics/physics_movement \ - physics/physics_restitution \ - physics/physics_shatter - - CURRENT_MAKEFILE = $(lastword $(MAKEFILE_LIST)) # Define processes to execute #------------------------------------------------------------------------------------------------ # Default target entry -all: $(CORE) $(SHAPES) $(TEXT) $(TEXTURES) $(MODELS) $(SHADERS) $(AUDIO) $(PHYSICS) +all: $(CORE) $(SHAPES) $(TEXT) $(TEXTURES) $(MODELS) $(SHADERS) $(AUDIO) core: $(CORE) shapes: $(SHAPES) @@ -516,7 +508,6 @@ text: $(TEXT) models: $(MODELS) shaders: $(SHADERS) audio: $(AUDIO) -physics: $(PHYSICS) # Generic compilation pattern # NOTE: Examples must be ready for Android compilation! diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 642527d1..a1a9d9b6 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -238,7 +238,7 @@ ifeq ($(PLATFORM),PLATFORM_DRM) endif # Define include paths for required headers -# NOTE: Some external/extras libraries could be required (stb, physac, easings...) +# NOTE: Some external/extras libraries could be required (stb, easings...) INCLUDE_PATHS = -I. -I$(RAYLIB_PATH)/src -I$(RAYLIB_PATH)/src/external -I$(RAYLIB_PATH)/src/extras # Define additional directories containing required header files @@ -324,8 +324,6 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) # Libraries for Windows desktop compilation # NOTE: WinMM library required to set high-res timer resolution LDLIBS = -lraylib -lopengl32 -lgdi32 -lwinmm - # Required for physac examples - LDLIBS += -static -lpthread endif ifeq ($(PLATFORM_OS),LINUX) # Libraries for Debian GNU/Linux desktop compiling @@ -508,17 +506,10 @@ AUDIO = \ audio/audio_sound_loading \ audio/audio_multichannel_sound -PHYSICS = \ - physics/physics_demo \ - physics/physics_friction \ - physics/physics_movement \ - physics/physics_restitution \ - physics/physics_shatter - CURRENT_MAKEFILE = $(lastword $(MAKEFILE_LIST)) # Default target entry -all: $(CORE) $(SHAPES) $(TEXT) $(TEXTURES) $(MODELS) $(SHADERS) $(AUDIO) $(PHYSICS) +all: $(CORE) $(SHAPES) $(TEXT) $(TEXTURES) $(MODELS) $(SHADERS) $(AUDIO) core: $(CORE) shapes: $(SHAPES) @@ -527,7 +518,6 @@ text: $(TEXT) models: $(MODELS) shaders: $(SHADERS) audio: $(AUDIO) -physics: $(PHYSICS) # Compile CORE examples core/core_basic_window: core/core_basic_window.c @@ -1007,23 +997,6 @@ audio/audio_multichannel_sound: audio/audio_multichannel_sound.c --preload-file audio/resources/sound.wav@resources/sound.wav \ --preload-file audio/resources/target.ogg@resources/target.ogg -# Compile PHYSICS examples -physics/physics_demo: physics/physics_demo.c - $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) -DPHYSAC_AVOID_TIMMING_SYSTEM - -physics/physics_friction: physics/physics_friction.c - $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) -DPHYSAC_AVOID_TIMMING_SYSTEM - -physics/physics_movement: physics/physics_movement.c - $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) -DPHYSAC_AVOID_TIMMING_SYSTEM - -physics/physics_restitution: physics/physics_restitution.c - $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) -DPHYSAC_AVOID_TIMMING_SYSTEM - -physics/physics_shatter: physics/physics_shatter.c - $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) -DPHYSAC_AVOID_TIMMING_SYSTEM - - # Clean everything clean: ifeq ($(PLATFORM),PLATFORM_DESKTOP) diff --git a/examples/README.md b/examples/README.md index 4fffb462..b0d0281b 100644 --- a/examples/README.md +++ b/examples/README.md @@ -176,18 +176,6 @@ Examples using raylib audio functionality, including sound/music loading and pla | 105 | [audio_sound_loading](audio/audio_sound_loading.c) | audio_sound_loading | ray | | | 106 | [audio_multichannel_sound](audio/audio_multichannel_sound.c) | audio_multichannel_sound | [Chris Camacho](https://github.com/codifies) | ⭐️ | -### category: physics - -Examples showing physics functionality with raylib. This functionality is provided by [physac](https://github.com/victorfisac/Physac) library, included with raylib [sources](../src/physac.h). Note this library is not linked with raylib by default, it should be manually included in user code. - -| ## | example | image | developer | new | -|----|----------|--------|:----------:|:---:| -| 107 | [physics_demo](physics/physics_demo.c) | physics_demo | [Victor Fisac](https://github.com/victorfisac) | | -| 108 | [physics_friction](physics/physics_friction.c) | physics_friction | [Victor Fisac](https://github.com/victorfisac) | | -| 109 | [physics_movement](physics/physics_movement.c) | physics_movement | [Victor Fisac](https://github.com/victorfisac) | | -| 110 | [physics_restitution](physics/physics_restitution.c) | physics_restitution | [Victor Fisac](https://github.com/victorfisac) | | -| 111 | [physics_shatter](physics/physics_shatter.c) | physics_shatter | [Victor Fisac](https://github.com/victorfisac) | | - ### category: others Examples showing raylib misc functionality that does not fit in other categories, like standalone modules usage or examples integrating external libraries. diff --git a/examples/physics/physics_demo.c b/examples/physics/physics_demo.c deleted file mode 100644 index dd7a216f..00000000 --- a/examples/physics/physics_demo.c +++ /dev/null @@ -1,128 +0,0 @@ -/******************************************************************************************* -* -* raylib [physac] example - physics demo -* -* This example has been created using raylib 1.5 (www.raylib.com) -* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) -* -* This example uses physac 1.1 (https://github.com/raysan5/raylib/blob/master/src/physac.h) -* -* Copyright (c) 2016-2021 Victor Fisac (@victorfisac) and Ramon Santamaria (@raysan5) -* -********************************************************************************************/ - -#include "raylib.h" - -#define PHYSAC_IMPLEMENTATION -#include "extras/physac.h" - -int main(void) -{ - // Initialization - //-------------------------------------------------------------------------------------- - const int screenWidth = 800; - const int screenHeight = 450; - - SetConfigFlags(FLAG_MSAA_4X_HINT); - InitWindow(screenWidth, screenHeight, "raylib [physac] example - physics demo"); - - // Physac logo drawing position - int logoX = screenWidth - MeasureText("Physac", 30) - 10; - int logoY = 15; - - // Initialize physics and default physics bodies - InitPhysics(); - - // Create floor rectangle physics body - PhysicsBody floor = CreatePhysicsBodyRectangle((Vector2){ screenWidth/2.0f, (float)screenHeight }, 500, 100, 10); - floor->enabled = false; // Disable body state to convert it to static (no dynamics, but collisions) - - // Create obstacle circle physics body - PhysicsBody circle = CreatePhysicsBodyCircle((Vector2){ screenWidth/2.0f, screenHeight/2.0f }, 45, 10); - circle->enabled = false; // Disable body state to convert it to static (no dynamics, but collisions) - - SetTargetFPS(60); // Set our game to run at 60 frames-per-second - //-------------------------------------------------------------------------------------- - - // Main game loop - while (!WindowShouldClose()) // Detect window close button or ESC key - { - // Update - //---------------------------------------------------------------------------------- - UpdatePhysics(); // Update physics system - - if (IsKeyPressed(KEY_R)) // Reset physics system - { - ResetPhysics(); - - floor = CreatePhysicsBodyRectangle((Vector2){ screenWidth/2.0f, (float)screenHeight }, 500, 100, 10); - floor->enabled = false; - - circle = CreatePhysicsBodyCircle((Vector2){ screenWidth/2.0f, screenHeight/2.0f }, 45, 10); - circle->enabled = false; - } - - // Physics body creation inputs - if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) CreatePhysicsBodyPolygon(GetMousePosition(), (float)GetRandomValue(20, 80), GetRandomValue(3, 8), 10); - else if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT)) CreatePhysicsBodyCircle(GetMousePosition(), (float)GetRandomValue(10, 45), 10); - - // Destroy falling physics bodies - int bodiesCount = GetPhysicsBodiesCount(); - for (int i = bodiesCount - 1; i >= 0; i--) - { - PhysicsBody body = GetPhysicsBody(i); - if (body != NULL && (body->position.y > screenHeight*2)) DestroyPhysicsBody(body); - } - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - BeginDrawing(); - - ClearBackground(BLACK); - - DrawFPS(screenWidth - 90, screenHeight - 30); - - // Draw created physics bodies - bodiesCount = GetPhysicsBodiesCount(); - for (int i = 0; i < bodiesCount; i++) - { - PhysicsBody body = GetPhysicsBody(i); - - if (body != NULL) - { - int vertexCount = GetPhysicsShapeVerticesCount(i); - for (int j = 0; j < vertexCount; j++) - { - // Get physics bodies shape vertices to draw lines - // Note: GetPhysicsShapeVertex() already calculates rotation transformations - Vector2 vertexA = GetPhysicsShapeVertex(body, j); - - int jj = (((j + 1) < vertexCount) ? (j + 1) : 0); // Get next vertex or first to close the shape - Vector2 vertexB = GetPhysicsShapeVertex(body, jj); - - DrawLineV(vertexA, vertexB, GREEN); // Draw a line between two vertex positions - } - } - } - - DrawText("Left mouse button to create a polygon", 10, 10, 10, WHITE); - DrawText("Right mouse button to create a circle", 10, 25, 10, WHITE); - DrawText("Press 'R' to reset example", 10, 40, 10, WHITE); - - DrawText("Physac", logoX, logoY, 30, WHITE); - DrawText("Powered by", logoX + 50, logoY - 7, 10, WHITE); - - EndDrawing(); - //---------------------------------------------------------------------------------- - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - ClosePhysics(); // Unitialize physics - - CloseWindow(); // Close window and OpenGL context - //-------------------------------------------------------------------------------------- - - return 0; -} diff --git a/examples/physics/physics_demo.png b/examples/physics/physics_demo.png deleted file mode 100644 index 12dc7e724c52ec20a5310c24c856bb2aa5b58d6b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23466 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 = false; // Disable body state to convert it to static (no dynamics, but collisions) - PhysicsBody wall = CreatePhysicsBodyRectangle((Vector2){ screenWidth/2.0f, screenHeight*0.8f }, 10, 80, 10); - wall->enabled = false; // Disable body state to convert it to static (no dynamics, but collisions) - - // Create left ramp physics body - PhysicsBody rectLeft = CreatePhysicsBodyRectangle((Vector2){ 25, (float)screenHeight - 5 }, 250, 250, 10); - rectLeft->enabled = false; // Disable body state to convert it to static (no dynamics, but collisions) - SetPhysicsBodyRotation(rectLeft, 30*DEG2RAD); - - // Create right ramp physics body - PhysicsBody rectRight = CreatePhysicsBodyRectangle((Vector2){ (float)screenWidth - 25, (float)screenHeight - 5 }, 250, 250, 10); - rectRight->enabled = false; // Disable body state to convert it to static (no dynamics, but collisions) - SetPhysicsBodyRotation(rectRight, 330*DEG2RAD); - - // Create dynamic physics bodies - PhysicsBody bodyA = CreatePhysicsBodyRectangle((Vector2){ 35, screenHeight*0.6f }, 40, 40, 10); - bodyA->staticFriction = 0.1f; - bodyA->dynamicFriction = 0.1f; - SetPhysicsBodyRotation(bodyA, 30*DEG2RAD); - - PhysicsBody bodyB = CreatePhysicsBodyRectangle((Vector2){ (float)screenWidth - 35, (float)screenHeight*0.6f }, 40, 40, 10); - bodyB->staticFriction = 1.0f; - bodyB->dynamicFriction = 1.0f; - SetPhysicsBodyRotation(bodyB, 330*DEG2RAD); - - SetTargetFPS(60); // Set our game to run at 60 frames-per-second - //-------------------------------------------------------------------------------------- - - // Main game loop - while (!WindowShouldClose()) // Detect window close button or ESC key - { - // Update - //---------------------------------------------------------------------------------- - UpdatePhysics(); // Update physics system - - if (IsKeyPressed(KEY_R)) // Reset physics system - { - // Reset dynamic physics bodies position, velocity and rotation - bodyA->position = (Vector2){ 35, screenHeight*0.6f }; - bodyA->velocity = (Vector2){ 0, 0 }; - bodyA->angularVelocity = 0; - SetPhysicsBodyRotation(bodyA, 30*DEG2RAD); - - bodyB->position = (Vector2){ (float)screenWidth - 35, screenHeight * 0.6f }; - bodyB->velocity = (Vector2){ 0, 0 }; - bodyB->angularVelocity = 0; - SetPhysicsBodyRotation(bodyB, 330*DEG2RAD); - } - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - BeginDrawing(); - - ClearBackground(BLACK); - - DrawFPS(screenWidth - 90, screenHeight - 30); - - // Draw created physics bodies - int bodiesCount = GetPhysicsBodiesCount(); - for (int i = 0; i < bodiesCount; i++) - { - PhysicsBody body = GetPhysicsBody(i); - - if (body != NULL) - { - int vertexCount = GetPhysicsShapeVerticesCount(i); - for (int j = 0; j < vertexCount; j++) - { - // Get physics bodies shape vertices to draw lines - // Note: GetPhysicsShapeVertex() already calculates rotation transformations - Vector2 vertexA = GetPhysicsShapeVertex(body, j); - - int jj = (((j + 1) < vertexCount) ? (j + 1) : 0); // Get next vertex or first to close the shape - Vector2 vertexB = GetPhysicsShapeVertex(body, jj); - - DrawLineV(vertexA, vertexB, GREEN); // Draw a line between two vertex positions - } - } - } - - DrawRectangle(0, screenHeight - 49, screenWidth, 49, BLACK); - - DrawText("Friction amount", (screenWidth - MeasureText("Friction amount", 30))/2.0f, 75, 30, WHITE); - DrawText("0.1", (int)bodyA->position.x - MeasureText("0.1", 20)/2, (int)bodyA->position.y - 7, 20, WHITE); - DrawText("1", (int)bodyB->position.x - MeasureText("1", 20)/2, (int)bodyB->position.y - 7, 20, WHITE); - - DrawText("Press 'R' to reset example", 10, 10, 10, WHITE); - - DrawText("Physac", logoX, logoY, 30, WHITE); - DrawText("Powered by", logoX + 50, logoY - 7, 10, WHITE); - - EndDrawing(); - //---------------------------------------------------------------------------------- - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - ClosePhysics(); // Unitialize physics - - CloseWindow(); // Close window and OpenGL context - //-------------------------------------------------------------------------------------- - - return 0; -} diff --git a/examples/physics/physics_friction.png b/examples/physics/physics_friction.png deleted file mode 100644 index e791ec2b901486fb5b5d49de1d93f7ba3c92bd3e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18150 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 M**+ep-5Cl019djzkpKVy diff --git a/examples/physics/physics_movement.c b/examples/physics/physics_movement.c deleted file mode 100644 index 068611ad..00000000 --- a/examples/physics/physics_movement.c +++ /dev/null @@ -1,128 +0,0 @@ -/******************************************************************************************* -* -* raylib [physac] example - physics movement -* -* This example has been created using raylib 1.5 (www.raylib.com) -* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) -* -* This example uses physac 1.1 (https://github.com/raysan5/raylib/blob/master/src/physac.h) -* -* Copyright (c) 2016-2021 Victor Fisac (@victorfisac) and Ramon Santamaria (@raysan5) -* -********************************************************************************************/ - -#include "raylib.h" - -#define PHYSAC_IMPLEMENTATION -#include "extras/physac.h" - -#define VELOCITY 0.5f - -int main(void) -{ - // Initialization - //-------------------------------------------------------------------------------------- - const int screenWidth = 800; - const int screenHeight = 450; - - SetConfigFlags(FLAG_MSAA_4X_HINT); - InitWindow(screenWidth, screenHeight, "raylib [physac] example - physics movement"); - - // Physac logo drawing position - int logoX = screenWidth - MeasureText("Physac", 30) - 10; - int logoY = 15; - - // Initialize physics and default physics bodies - InitPhysics(); - - // Create floor and walls rectangle physics body - PhysicsBody floor = CreatePhysicsBodyRectangle((Vector2){ screenWidth/2.0f, (float)screenHeight }, (float)screenWidth, 100, 10); - PhysicsBody platformLeft = CreatePhysicsBodyRectangle((Vector2){ screenWidth*0.25f, screenHeight*0.6f }, screenWidth*0.25f, 10, 10); - PhysicsBody platformRight = CreatePhysicsBodyRectangle((Vector2){ screenWidth*0.75f, screenHeight*0.6f }, screenWidth*0.25f, 10, 10); - PhysicsBody wallLeft = CreatePhysicsBodyRectangle((Vector2){ -5, screenHeight/2.0f }, 10, (float)screenHeight, 10); - PhysicsBody wallRight = CreatePhysicsBodyRectangle((Vector2){ (float)screenWidth + 5, screenHeight/2.0f }, 10, (float)screenHeight, 10); - - // Disable dynamics to floor and walls physics bodies - floor->enabled = false; - platformLeft->enabled = false; - platformRight->enabled = false; - wallLeft->enabled = false; - wallRight->enabled = false; - - // Create movement physics body - PhysicsBody body = CreatePhysicsBodyRectangle((Vector2){ screenWidth/2.0f, screenHeight/2.0f }, 50, 50, 1); - body->freezeOrient = true; // Constrain body rotation to avoid little collision torque amounts - - SetTargetFPS(60); // Set our game to run at 60 frames-per-second - //-------------------------------------------------------------------------------------- - - // Main game loop - while (!WindowShouldClose()) // Detect window close button or ESC key - { - // Update - //---------------------------------------------------------------------------------- - UpdatePhysics(); // Update physics system - - if (IsKeyPressed(KEY_R)) // Reset physics input - { - // Reset movement physics body position, velocity and rotation - body->position = (Vector2){ screenWidth/2.0f, screenHeight/2.0f }; - body->velocity = (Vector2){ 0, 0 }; - SetPhysicsBodyRotation(body, 0); - } - - // Horizontal movement input - if (IsKeyDown(KEY_RIGHT)) body->velocity.x = VELOCITY; - else if (IsKeyDown(KEY_LEFT)) body->velocity.x = -VELOCITY; - - // Vertical movement input checking if player physics body is grounded - if (IsKeyDown(KEY_UP) && body->isGrounded) body->velocity.y = -VELOCITY*4; - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - BeginDrawing(); - - ClearBackground(BLACK); - - DrawFPS(screenWidth - 90, screenHeight - 30); - - // Draw created physics bodies - int bodiesCount = GetPhysicsBodiesCount(); - for (int i = 0; i < bodiesCount; i++) - { - PhysicsBody body = GetPhysicsBody(i); - - int vertexCount = GetPhysicsShapeVerticesCount(i); - for (int j = 0; j < vertexCount; j++) - { - // Get physics bodies shape vertices to draw lines - // Note: GetPhysicsShapeVertex() already calculates rotation transformations - Vector2 vertexA = GetPhysicsShapeVertex(body, j); - - int jj = (((j + 1) < vertexCount) ? (j + 1) : 0); // Get next vertex or first to close the shape - Vector2 vertexB = GetPhysicsShapeVertex(body, jj); - - DrawLineV(vertexA, vertexB, GREEN); // Draw a line between two vertex positions - } - } - - DrawText("Use 'ARROWS' to move player", 10, 10, 10, WHITE); - DrawText("Press 'R' to reset example", 10, 30, 10, WHITE); - - DrawText("Physac", logoX, logoY, 30, WHITE); - DrawText("Powered by", logoX + 50, logoY - 7, 10, WHITE); - - EndDrawing(); - //---------------------------------------------------------------------------------- - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - ClosePhysics(); // Unitialize physics - - CloseWindow(); // Close window and OpenGL context - //-------------------------------------------------------------------------------------- - - return 0; -} diff --git a/examples/physics/physics_movement.png b/examples/physics/physics_movement.png deleted file mode 100644 index a88a7d79facfbfb5ca1a91b74cf02ebfd3f11847..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15947 zcmeHOdo)yQ8{ad;xHjZ4Gj214ZsdMKG%oGYO-dIhsv$8)NTN8{-p~6yzvuV9^E}Tl z&D)Enrc6=>06=Y-r^i|VkRt;CrXHsNeWJ6itO)>IG?#g}uKQ)nwjkf4p_7yzOv4<4 z8cT>rzF-R20_7PBB|@^nG&jYj2pEb%wq==Y0RzWHxL9)cP{CPs$bW?XpcY^&iZkQOBELj^uDCDx~Xe>SCKlaO74KVV*af=2*CiXD9jz+y2U!xWoZ}G{o-aF ziuDiQ5ZIRY(j_YJnBWY4kuzn($PZ)SB5oIPWVrGA>?Wn&0(Yzxrk5nWw6_QfG^Jg9aT>(Qj)s zd5!iW;Q+bqN&O2QUt@zCR@uL|n~4?%KAg3dGpG}&X>DP{3FYjrAW1{E4v#Iqc3Q!& zBO_EFKddnKE?+cUHDtFZr+Mi{&g!hr#zgaa1;2%wC!d}DV?)$k;_`0WO~ zakWjs8hLa@znyUvzWP$>!op$V!;So-;*TpDYV4zNOU9m%5M1kZt@oZLB{eaX*N zw1OO>V~XWXYdUg9>W#8BUsL}ayR$pX)>D0J2)@{Gqfxz1WpbxiSPfmzBV=>7_D!U0 z5pe*M@J*+j$ZdaBcfX!zA4d;tJCIb(^5!4z1Z`X@HPb_*$9i5bx%`uOPj1g1x4~Q6 zwQCkFu+luAVB4EL)fvDAd|~u+ZNIpg9l$GwD$fAR)lyxMy~SfuLC+jzOz01)d?8ZC zT3Wl&E99&TT8VS|>a4RY&XZQTB3U~-S;8IFNVK8)4o{A0*&UsK`+4Tt65$7X1ZJ3c z_pmZcsNTfbq$}n4&ly|jhvQn*kyeEvSz&A~@42}orB;>O_MjrN^h{7G!Qw5Cbfm&k z@uV&oLIqWh$xQsOGEa-SJa~wniA-LuhS-Wl57Q6lT@~*u(00BEl5cOVsEG)ORtTyP z5T{!VOsO3RSuEi=pv#ROt@MZyi0F@D3ibRS)TICPwmIhSD5seU_3{1~Ywt9S$bi?C z+&ROCW1vyhsOX-YSrcBNEuCkOFD_81tq`?@Y%9D_McY}}8}*nT(UcurD#J}_6l%VS zZ@Z&WRj^r;1}&Qq7_u2xnpCY@qJC&e%fK1Veqk4wuFLzFxw9m-wTf(C3uYWdcoya_ z3bjAfD9{v8=;+%bb}=iJOT6DuwK)BE0^5N}7-=+J7Znm%UX3{vC+u=l88dpHbT~Pw zxr}Tj@={!>RN}cxH1CAyT;38$ z8m!>PF8{b9y(98TN~aR*2ra@alNZO>KFD~ZhZL$46zXfA^70s5WajN&-P2~KqnGSz z`}D($M|DK@%N^s5 za4@O;Cv24FthvYWL3;&QZY$3C)=lzQfKRqX)7Hel6%Uo1c%g z^8x?HlWXJ>F9xKo$lBC1x|rFl9!RPa^~+VKJo;qv_+xvgf=veR=%rF)Es%daQ&_)U zip@cHW*eSxBQ?^t88L%@!x!G7o0SIVIu3E?lXsOZC^~4Uc+_E3Q|kdEL01hEMzM6f zZdG7`w6!rbuzY=1}9P%lhSK8ght3n&&Qe~m{o0?i0CBhZYPIG&?eK(T;g0in!|evd%EQ^H3D z)C;H=CSZVK0mZ_1#zHxlJtFCc033mGO1H)gjhSFxt5k;suR7jrwkBcah*&c_B0}n4cC&Ps&=F7X4X>-ah05OC*X4xykVg{TxRweU#isVxNNxfGkuL0H34QH)C;H= z(4?Hq!DvQ&r;P9gjbnHz&?Y3DLtI87H{TN!-f0$;C&n?}7i{^I`io`363PA$2@NfM zv?{O%-GRM0?jysbc`@*e!b&0L++r;UT1Iw`7MA9sI`dg;gJEH<)l&h<+z`4q4!)N^ zcblzzBnN(gc|-L6Uvr=K26YvGg-oS z+geU@;c=_Gj?*<(ryaMF%vvA};7oMv6UKMJb2P~@58?8Ef!eSEukK(wxbVNk=1+VI z(^;OnPcHg?9b;6|s(yaYnEzIvTaqQj3!ozb?3Q%MEp=KZg(^6jt}lP-i*bjocm(>~ zX5gNy!#CN+Kn@**9jdUopKu&Q3|nIztMZPa@x_@`FG+m*f+e|?nk;GBu9cn$`s^&U zX$y}|pk6?|FfoRTVgbbhiiL^26vYCH1r!TY1q$dMf${>%3n(w3ynr;GkFw*pvLiF6 zyZF!j?Dx-TN%50wVN>e&3|(ycF;%_|nV%*tY5IIGGlC+(p7;orcSs_c<$Gvqy#w!C zBxw@dp7N3}zlwDv1Lr<}V`lvyZ@No#J8DQ%|B}yCZ{p$d$f}1jT@ejQ?jXqyvP1=r zA1wJRnIL&-n0G@?f&x++D=ThLKrG>A3Zmp^+$^XQV>=-sk~Z`MB%)CWvRyBwikeVU zz|tOQ3@}ZGz7Gm0+=)^664)s}vA0T^OC|l2iG1=(F<(^|{nNTeI_~ZRGYdklgoY%J%5iv aJYcu*6}QKoNq|J+z_O)Y9v9r`iT?wVkXms7 diff --git a/examples/physics/physics_restitution.c b/examples/physics/physics_restitution.c deleted file mode 100644 index 27241b68..00000000 --- a/examples/physics/physics_restitution.c +++ /dev/null @@ -1,129 +0,0 @@ -/******************************************************************************************* -* -* raylib [physac] example - physics restitution -* -* This example has been created using raylib 1.5 (www.raylib.com) -* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) -* -* This example uses physac 1.1 (https://github.com/raysan5/raylib/blob/master/src/physac.h) -* -* Copyright (c) 2016-2021 Victor Fisac (@victorfisac) and Ramon Santamaria (@raysan5) -* -********************************************************************************************/ - -#include "raylib.h" - -#define PHYSAC_IMPLEMENTATION -#include "extras/physac.h" - -int main(void) -{ - // Initialization - //-------------------------------------------------------------------------------------- - const int screenWidth = 800; - const int screenHeight = 450; - - SetConfigFlags(FLAG_MSAA_4X_HINT); - InitWindow(screenWidth, screenHeight, "raylib [physac] example - physics restitution"); - - // Physac logo drawing position - int logoX = screenWidth - MeasureText("Physac", 30) - 10; - int logoY = 15; - - // Initialize physics and default physics bodies - InitPhysics(); - - // Create floor rectangle physics body - PhysicsBody floor = CreatePhysicsBodyRectangle((Vector2){ screenWidth/2.0f, (float)screenHeight }, (float)screenWidth, 100, 10); - floor->enabled = false; // Disable body state to convert it to static (no dynamics, but collisions) - floor->restitution = 1; - - // Create circles physics body - PhysicsBody circleA = CreatePhysicsBodyCircle((Vector2){ screenWidth*0.25f, screenHeight/2.0f }, 30, 10); - circleA->restitution = 0; - PhysicsBody circleB = CreatePhysicsBodyCircle((Vector2){ screenWidth*0.5f, screenHeight/2.0f }, 30, 10); - circleB->restitution = 0.5f; - PhysicsBody circleC = CreatePhysicsBodyCircle((Vector2){ screenWidth*0.75f, screenHeight/2.0f }, 30, 10); - circleC->restitution = 1; - - // Restitution demo needs a very tiny physics time step for a proper simulation - SetPhysicsTimeStep(1.0/60.0/100*1000); - - SetTargetFPS(60); // Set our game to run at 60 frames-per-second - //-------------------------------------------------------------------------------------- - - // Main game loop - while (!WindowShouldClose()) // Detect window close button or ESC key - { - // Update - //---------------------------------------------------------------------------------- - UpdatePhysics(); // Update physics system - - if (IsKeyPressed(KEY_R)) // Reset physics input - { - // Reset circles physics bodies position and velocity - circleA->position = (Vector2){ screenWidth*0.25f, screenHeight/2.0f }; - circleA->velocity = (Vector2){ 0, 0 }; - circleB->position = (Vector2){ screenWidth*0.5f, screenHeight/2.0f }; - circleB->velocity = (Vector2){ 0, 0 }; - circleC->position = (Vector2){ screenWidth*0.75f, screenHeight/2.0f }; - circleC->velocity = (Vector2){ 0, 0 }; - } - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - BeginDrawing(); - - ClearBackground(BLACK); - - DrawFPS(screenWidth - 90, screenHeight - 30); - - // Draw created physics bodies - int bodiesCount = GetPhysicsBodiesCount(); - for (int i = 0; i < bodiesCount; i++) - { - PhysicsBody body = GetPhysicsBody(i); - - int vertexCount = GetPhysicsShapeVerticesCount(i); - for (int j = 0; j < vertexCount; j++) - { - // Get physics bodies shape vertices to draw lines - // Note: GetPhysicsShapeVertex() already calculates rotation transformations - Vector2 vertexA = GetPhysicsShapeVertex(body, j); - - int jj = (((j + 1) < vertexCount) ? (j + 1) : 0); // Get next vertex or first to close the shape - Vector2 vertexB = GetPhysicsShapeVertex(body, jj); - - DrawLineV(vertexA, vertexB, GREEN); // Draw a line between two vertex positions - } - } - - DrawText("Restitution amount", (screenWidth - MeasureText("Restitution amount", 30))/2, 75, 30, WHITE); - DrawText("0", (int)circleA->position.x - MeasureText("0", 20)/2, circleA->position.y - 7, 20, WHITE); - DrawText("0.5", (int)circleB->position.x - MeasureText("0.5", 20)/2, circleB->position.y - 7, 20, WHITE); - DrawText("1", (int)circleC->position.x - MeasureText("1", 20)/2, circleC->position.y - 7, 20, WHITE); - - DrawText("Press 'R' to reset example", 10, 10, 10, WHITE); - - DrawText("Physac", logoX, logoY, 30, WHITE); - DrawText("Powered by", logoX + 50, logoY - 7, 10, WHITE); - - EndDrawing(); - //---------------------------------------------------------------------------------- - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - DestroyPhysicsBody(circleA); - DestroyPhysicsBody(circleB); - DestroyPhysicsBody(circleC); - DestroyPhysicsBody(floor); - - ClosePhysics(); // Unitialize physics - - CloseWindow(); // Close window and OpenGL context - //-------------------------------------------------------------------------------------- - - return 0; -} diff --git a/examples/physics/physics_restitution.png b/examples/physics/physics_restitution.png deleted file mode 100644 index 8ec4b3f3270063659472bd5e21ffb39f29af6303..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17833 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 0; i--) - { - PhysicsBody currentBody = GetPhysicsBody(i); - - if (currentBody != NULL) PhysicsShatter(currentBody, GetMousePosition(), 10/currentBody->inverseMass); - } - } - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - BeginDrawing(); - - ClearBackground(BLACK); - - // Draw created physics bodies - int bodiesCount = GetPhysicsBodiesCount(); - for (int i = 0; i < bodiesCount; i++) - { - PhysicsBody currentBody = GetPhysicsBody(i); - - int vertexCount = GetPhysicsShapeVerticesCount(i); - for (int j = 0; j < vertexCount; j++) - { - // Get physics bodies shape vertices to draw lines - // Note: GetPhysicsShapeVertex() already calculates rotation transformations - Vector2 vertexA = GetPhysicsShapeVertex(currentBody, j); - - int jj = (((j + 1) < vertexCount) ? (j + 1) : 0); // Get next vertex or first to close the shape - Vector2 vertexB = GetPhysicsShapeVertex(currentBody, jj); - - DrawLineV(vertexA, vertexB, GREEN); // Draw a line between two vertex positions - } - } - - DrawText("Left mouse button in polygon area to shatter body\nPress 'R' to reset example", 10, 10, 10, WHITE); - - DrawText("Physac", logoX, logoY, 30, WHITE); - DrawText("Powered by", logoX + 50, logoY - 7, 10, WHITE); - - EndDrawing(); - //---------------------------------------------------------------------------------- - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - ClosePhysics(); // Unitialize physics - - CloseWindow(); // Close window and OpenGL context - //-------------------------------------------------------------------------------------- - - return 0; -} diff --git a/examples/physics/physics_shatter.png b/examples/physics/physics_shatter.png deleted file mode 100644 index 68f9a1b7d2ea6a0043828131342c6e2f641e858e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23197 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 diff --git a/src/extras/physac.h b/src/extras/physac.h deleted file mode 100644 index 3ab427ac..00000000 --- a/src/extras/physac.h +++ /dev/null @@ -1,1987 +0,0 @@ -/********************************************************************************************** -* -* Physac v1.1 - 2D Physics library for videogames -* -* DESCRIPTION: -* -* Physac is a small 2D physics engine written in pure C. The engine uses a fixed time-step thread loop -* to simulate physics. A physics step contains the following phases: get collision information, -* apply dynamics, collision solving and position correction. It uses a very simple struct for physic -* bodies with a position vector to be used in any 3D rendering API. -* -* CONFIGURATION: -* -* #define PHYSAC_IMPLEMENTATION -* Generates the implementation of the library into the included file. -* If not defined, the library is in header only mode and can be included in other headers -* or source files without problems. But only ONE file should hold the implementation. -* -* #define PHYSAC_DEBUG -* Show debug traces log messages about physic bodies creation/destruction, physic system errors, -* some calculations results and NULL reference exceptions. -* -* #define PHYSAC_AVOID_TIMMING_SYSTEM -* Disables internal timming system, used by UpdatePhysics() to launch timmed physic steps, -* it allows just running UpdatePhysics() automatically on a separate thread at a desired time step. -* In case physics steps update needs to be controlled by user with a custom timming mechanism, -* just define this flag and the internal timming mechanism will be avoided, in that case, -* timming libraries are neither required by the module. -* -* #define PHYSAC_MALLOC() -* #define PHYSAC_CALLOC() -* #define PHYSAC_FREE() -* You can define your own malloc/free implementation replacing stdlib.h malloc()/free() functions. -* Otherwise it will include stdlib.h and use the C standard library malloc()/free() function. -* -* COMPILATION: -* -* Use the following code to compile with GCC: -* gcc -o $(NAME_PART).exe $(FILE_NAME) -s -static -lraylib -lopengl32 -lgdi32 -lwinmm -std=c99 -* -* VERSIONS HISTORY: -* 1.1 (20-Jan-2021) @raysan5: Library general revision -* Removed threading system (up to the user) -* Support MSVC C++ compilation using CLITERAL() -* Review DEBUG mechanism for TRACELOG() and all TRACELOG() messages -* Review internal variables/functions naming for consistency -* Allow option to avoid internal timming system, to allow app manage the steps -* 1.0 (12-Jun-2017) First release of the library -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2016-2022 Victor Fisac (@victorfisac) and Ramon Santamaria (@raysan5) -* -* This software is provided "as-is", without any express or implied warranty. In no event -* will the authors be held liable for any damages arising from the use of this software. -* -* Permission is granted to anyone to use this software for any purpose, including commercial -* applications, and to alter it and redistribute it freely, subject to the following restrictions: -* -* 1. The origin of this software must not be misrepresented; you must not claim that you -* wrote the original software. If you use this software in a product, an acknowledgment -* in the product documentation would be appreciated but is not required. -* -* 2. Altered source versions must be plainly marked as such, and must not be misrepresented -* as being the original software. -* -* 3. This notice may not be removed or altered from any source distribution. -* -**********************************************************************************************/ - -#if !defined(PHYSAC_H) -#define PHYSAC_H - -// Function specifiers in case library is build/used as a shared library (Windows) -// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll -#if defined(_WIN32) - #if defined(BUILD_LIBTYPE_SHARED) - #define PHYSACDEF __declspec(dllexport) // We are building the library as a Win32 shared library (.dll) - #elif defined(USE_LIBTYPE_SHARED) - #define PHYSACDEF __declspec(dllimport) // We are using the library as a Win32 shared library (.dll) - #endif -#endif - -#ifndef PHYSACDEF - #define PHYSACDEF // We are building or using physac as a static library -#endif - -// Allow custom memory allocators -#ifndef PHYSAC_MALLOC - #define PHYSAC_MALLOC(size) malloc(size) -#endif -#ifndef PHYSAC_CALLOC - #define PHYSAC_CALLOC(size, n) calloc(size, n) -#endif -#ifndef PHYSAC_FREE - #define PHYSAC_FREE(ptr) free(ptr) -#endif - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#define PHYSAC_MAX_BODIES 64 // Maximum number of physic bodies supported -#define PHYSAC_MAX_MANIFOLDS 4096 // Maximum number of physic bodies interactions (64x64) -#define PHYSAC_MAX_VERTICES 24 // Maximum number of vertex for polygons shapes -#define PHYSAC_DEFAULT_CIRCLE_VERTICES 24 // Default number of vertices for circle shapes - -#define PHYSAC_COLLISION_ITERATIONS 100 -#define PHYSAC_PENETRATION_ALLOWANCE 0.05f -#define PHYSAC_PENETRATION_CORRECTION 0.4f - -#define PHYSAC_PI 3.14159265358979323846f -#define PHYSAC_DEG2RAD (PHYSAC_PI/180.0f) - -//---------------------------------------------------------------------------------- -// Data Types Structure Definition -//---------------------------------------------------------------------------------- -#if defined(__STDC__) && __STDC_VERSION__ >= 199901L - #include -#endif - -typedef enum PhysicsShapeType { PHYSICS_CIRCLE = 0, PHYSICS_POLYGON } PhysicsShapeType; - -// Previously defined to be used in PhysicsShape struct as circular dependencies -typedef struct PhysicsBodyData *PhysicsBody; - -#if !defined(RL_VECTOR2_TYPE) -// Vector2 type -typedef struct Vector2 { - float x; - float y; -} Vector2; -#endif - -// Matrix2x2 type (used for polygon shape rotation matrix) -typedef struct Matrix2x2 { - float m00; - float m01; - float m10; - float m11; -} Matrix2x2; - -typedef struct PhysicsVertexData { - unsigned int vertexCount; // Vertex count (positions and normals) - Vector2 positions[PHYSAC_MAX_VERTICES]; // Vertex positions vectors - Vector2 normals[PHYSAC_MAX_VERTICES]; // Vertex normals vectors -} PhysicsVertexData; - -typedef struct PhysicsShape { - PhysicsShapeType type; // Shape type (circle or polygon) - PhysicsBody body; // Shape physics body data pointer - PhysicsVertexData vertexData; // Shape vertices data (used for polygon shapes) - float radius; // Shape radius (used for circle shapes) - Matrix2x2 transform; // Vertices transform matrix 2x2 -} PhysicsShape; - -typedef struct PhysicsBodyData { - unsigned int id; // Unique identifier - bool enabled; // Enabled dynamics state (collisions are calculated anyway) - Vector2 position; // Physics body shape pivot - Vector2 velocity; // Current linear velocity applied to position - Vector2 force; // Current linear force (reset to 0 every step) - float angularVelocity; // Current angular velocity applied to orient - float torque; // Current angular force (reset to 0 every step) - float orient; // Rotation in radians - float inertia; // Moment of inertia - float inverseInertia; // Inverse value of inertia - float mass; // Physics body mass - float inverseMass; // Inverse value of mass - float staticFriction; // Friction when the body has not movement (0 to 1) - float dynamicFriction; // Friction when the body has movement (0 to 1) - float restitution; // Restitution coefficient of the body (0 to 1) - bool useGravity; // Apply gravity force to dynamics - bool isGrounded; // Physics grounded on other body state - bool freezeOrient; // Physics rotation constraint - PhysicsShape shape; // Physics body shape information (type, radius, vertices, transform) -} PhysicsBodyData; - -typedef struct PhysicsManifoldData { - unsigned int id; // Unique identifier - PhysicsBody bodyA; // Manifold first physics body reference - PhysicsBody bodyB; // Manifold second physics body reference - float penetration; // Depth of penetration from collision - Vector2 normal; // Normal direction vector from 'a' to 'b' - Vector2 contacts[2]; // Points of contact during collision - unsigned int contactsCount; // Current collision number of contacts - float restitution; // Mixed restitution during collision - float dynamicFriction; // Mixed dynamic friction during collision - float staticFriction; // Mixed static friction during collision -} PhysicsManifoldData, *PhysicsManifold; - -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- - -#if defined(__cplusplus) -extern "C" { // Prevents name mangling of functions -#endif -// Physics system management -PHYSACDEF void InitPhysics(void); // Initializes physics system -PHYSACDEF void UpdatePhysics(void); // Update physics system -PHYSACDEF void ResetPhysics(void); // Reset physics system (global variables) -PHYSACDEF void ClosePhysics(void); // Close physics system and unload used memory -PHYSACDEF void SetPhysicsTimeStep(double delta); // Sets physics fixed time step in milliseconds. 1.666666 by default -PHYSACDEF void SetPhysicsGravity(float x, float y); // Sets physics global gravity force - -// Physic body creation/destroy -PHYSACDEF PhysicsBody CreatePhysicsBodyCircle(Vector2 pos, float radius, float density); // Creates a new circle physics body with generic parameters -PHYSACDEF PhysicsBody CreatePhysicsBodyRectangle(Vector2 pos, float width, float height, float density); // Creates a new rectangle physics body with generic parameters -PHYSACDEF PhysicsBody CreatePhysicsBodyPolygon(Vector2 pos, float radius, int sides, float density); // Creates a new polygon physics body with generic parameters -PHYSACDEF void DestroyPhysicsBody(PhysicsBody body); // Destroy a physics body - -// Physic body forces -PHYSACDEF void PhysicsAddForce(PhysicsBody body, Vector2 force); // Adds a force to a physics body -PHYSACDEF void PhysicsAddTorque(PhysicsBody body, float amount); // Adds an angular force to a physics body -PHYSACDEF void PhysicsShatter(PhysicsBody body, Vector2 position, float force); // Shatters a polygon shape physics body to little physics bodies with explosion force -PHYSACDEF void SetPhysicsBodyRotation(PhysicsBody body, float radians); // Sets physics body shape transform based on radians parameter - -// Query physics info -PHYSACDEF PhysicsBody GetPhysicsBody(int index); // Returns a physics body of the bodies pool at a specific index -PHYSACDEF int GetPhysicsBodiesCount(void); // Returns the current amount of created physics bodies -PHYSACDEF int GetPhysicsShapeType(int index); // Returns the physics body shape type (PHYSICS_CIRCLE or PHYSICS_POLYGON) -PHYSACDEF int GetPhysicsShapeVerticesCount(int index); // Returns the amount of vertices of a physics body shape -PHYSACDEF Vector2 GetPhysicsShapeVertex(PhysicsBody body, int vertex); // Returns transformed position of a body shape (body position + vertex transformed position) -#if defined(__cplusplus) -} -#endif - -#endif // PHYSAC_H - -/*********************************************************************************** -* -* PHYSAC IMPLEMENTATION -* -************************************************************************************/ - -#if defined(PHYSAC_IMPLEMENTATION) - -// Support TRACELOG macros -#if defined(PHYSAC_DEBUG) - #include // Required for: printf() - #define TRACELOG(...) printf(__VA_ARGS__) -#else - #define TRACELOG(...) (void)0; -#endif - -#include // Required for: malloc(), calloc(), free() -#include // Required for: cosf(), sinf(), fabs(), sqrtf() - -#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) - // Time management functionality - #include // Required for: time(), clock_gettime() - #if defined(_WIN32) - #if defined(__cplusplus) - extern "C" { // Prevents name mangling of functions - #endif - // Functions required to query time on Windows - int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount); - int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency); - #if defined(__cplusplus) - } - #endif - #endif - #if defined(__linux__) || defined(__FreeBSD__) - #if _POSIX_C_SOURCE < 199309L - #undef _POSIX_C_SOURCE - #define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext. - #endif - #include // Required for: timespec - #endif - #if defined(__APPLE__) // macOS also defines __MACH__ - #include // Required for: mach_absolute_time() - #endif -#endif - -// NOTE: MSVC C++ compiler does not support compound literals (C99 feature) -// Plain structures in C++ (without constructors) can be initialized from { } initializers. -#if defined(__cplusplus) - #define CLITERAL(type) type -#else - #define CLITERAL(type) (type) -#endif - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#define PHYSAC_MIN(a,b) (((a)<(b))?(a):(b)) -#define PHYSAC_MAX(a,b) (((a)>(b))?(a):(b)) -#define PHYSAC_FLT_MAX 3.402823466e+38f -#define PHYSAC_EPSILON 0.000001f -#define PHYSAC_K 1.0f/3.0f -#define PHYSAC_VECTOR_ZERO CLITERAL(Vector2){ 0.0f, 0.0f } - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -static double deltaTime = 1.0/60.0/10.0 * 1000; // Delta time in milliseconds used for physics steps - -#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) -// Time measure variables -static double baseClockTicks = 0.0; // Offset clock ticks for MONOTONIC clock -static unsigned long long int frequency = 0; // Hi-res clock frequency -static double startTime = 0.0; // Start time in milliseconds -static double currentTime = 0.0; // Current time in milliseconds -#endif - -// Physics system configuration -static PhysicsBody bodies[PHYSAC_MAX_BODIES]; // Physics bodies pointers array -static unsigned int physicsBodiesCount = 0; // Physics world current bodies counter -static PhysicsManifold contacts[PHYSAC_MAX_MANIFOLDS]; // Physics bodies pointers array -static unsigned int physicsManifoldsCount = 0; // Physics world current manifolds counter - -static Vector2 gravityForce = { 0.0f, 9.81f }; // Physics world gravity force - -// Utilities variables -static unsigned int usedMemory = 0; // Total allocated dynamic memory - -//---------------------------------------------------------------------------------- -// Module Internal Functions Declaration -//---------------------------------------------------------------------------------- -#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) -// Timming measure functions -static void InitTimerHiRes(void); // Initializes hi-resolution MONOTONIC timer -static unsigned long long int GetClockTicks(void); // Get hi-res MONOTONIC time measure in mseconds -static double GetCurrentTime(void); // Get current time measure in milliseconds -#endif - -static void UpdatePhysicsStep(void); // Update physics step (dynamics, collisions and position corrections) - -static int FindAvailableBodyIndex(); // Finds a valid index for a new physics body initialization -static int FindAvailableManifoldIndex(); // Finds a valid index for a new manifold initialization -static PhysicsVertexData CreateDefaultPolygon(float radius, int sides); // Creates a random polygon shape with max vertex distance from polygon pivot -static PhysicsVertexData CreateRectanglePolygon(Vector2 pos, Vector2 size); // Creates a rectangle polygon shape based on a min and max positions - -static void InitializePhysicsManifolds(PhysicsManifold manifold); // Initializes physics manifolds to solve collisions -static PhysicsManifold CreatePhysicsManifold(PhysicsBody a, PhysicsBody b); // Creates a new physics manifold to solve collision -static void DestroyPhysicsManifold(PhysicsManifold manifold); // Unitializes and destroys a physics manifold - -static void SolvePhysicsManifold(PhysicsManifold manifold); // Solves a created physics manifold between two physics bodies -static void SolveCircleToCircle(PhysicsManifold manifold); // Solves collision between two circle shape physics bodies -static void SolveCircleToPolygon(PhysicsManifold manifold); // Solves collision between a circle to a polygon shape physics bodies -static void SolvePolygonToCircle(PhysicsManifold manifold); // Solves collision between a polygon to a circle shape physics bodies -static void SolvePolygonToPolygon(PhysicsManifold manifold); // Solves collision between two polygons shape physics bodies -static void IntegratePhysicsForces(PhysicsBody body); // Integrates physics forces into velocity -static void IntegratePhysicsVelocity(PhysicsBody body); // Integrates physics velocity into position and forces -static void IntegratePhysicsImpulses(PhysicsManifold manifold); // Integrates physics collisions impulses to solve collisions -static void CorrectPhysicsPositions(PhysicsManifold manifold); // Corrects physics bodies positions based on manifolds collision information -static void FindIncidentFace(Vector2 *v0, Vector2 *v1, PhysicsShape ref, PhysicsShape inc, int index); // Finds two polygon shapes incident face -static float FindAxisLeastPenetration(int *faceIndex, PhysicsShape shapeA, PhysicsShape shapeB); // Finds polygon shapes axis least penetration - -// Math required functions -static Vector2 MathVector2Product(Vector2 vector, float value); // Returns the product of a vector and a value -static float MathVector2CrossProduct(Vector2 v1, Vector2 v2); // Returns the cross product of two vectors -static float MathVector2SqrLen(Vector2 vector); // Returns the len square root of a vector -static float MathVector2DotProduct(Vector2 v1, Vector2 v2); // Returns the dot product of two vectors -static inline float MathVector2SqrDistance(Vector2 v1, Vector2 v2); // Returns the square root of distance between two vectors -static void MathVector2Normalize(Vector2 *vector); // Returns the normalized values of a vector -static Vector2 MathVector2Add(Vector2 v1, Vector2 v2); // Returns the sum of two given vectors -static Vector2 MathVector2Subtract(Vector2 v1, Vector2 v2); // Returns the subtract of two given vectors -static Matrix2x2 MathMatFromRadians(float radians); // Returns a matrix 2x2 from a given radians value -static inline Matrix2x2 MathMatTranspose(Matrix2x2 matrix); // Returns the transpose of a given matrix 2x2 -static inline Vector2 MathMatVector2Product(Matrix2x2 matrix, Vector2 vector); // Returns product between matrix 2x2 and vector -static int MathVector2Clip(Vector2 normal, Vector2 *faceA, Vector2 *faceB, float clip); // Returns clipping value based on a normal and two faces -static Vector2 MathTriangleBarycenter(Vector2 v1, Vector2 v2, Vector2 v3); // Returns the barycenter of a triangle given by 3 points - -//---------------------------------------------------------------------------------- -// Module Functions Definition -//---------------------------------------------------------------------------------- - -// Initializes physics values, pointers and creates physics loop thread -void InitPhysics(void) -{ -#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) - // Initialize high resolution timer - InitTimerHiRes(); -#endif - - TRACELOG("[PHYSAC] Physics module initialized successfully\n"); -} - -// Sets physics global gravity force -void SetPhysicsGravity(float x, float y) -{ - gravityForce.x = x; - gravityForce.y = y; -} - -// Creates a new circle physics body with generic parameters -PhysicsBody CreatePhysicsBodyCircle(Vector2 pos, float radius, float density) -{ - PhysicsBody body = CreatePhysicsBodyPolygon(pos, radius, PHYSAC_DEFAULT_CIRCLE_VERTICES, density); - return body; -} - -// Creates a new rectangle physics body with generic parameters -PhysicsBody CreatePhysicsBodyRectangle(Vector2 pos, float width, float height, float density) -{ - // NOTE: Make sure body data is initialized to 0 - PhysicsBody body = (PhysicsBody)PHYSAC_CALLOC(sizeof(PhysicsBodyData), 1); - usedMemory += sizeof(PhysicsBodyData); - - int id = FindAvailableBodyIndex(); - if (id != -1) - { - // Initialize new body with generic values - body->id = id; - body->enabled = true; - body->position = pos; - body->shape.type = PHYSICS_POLYGON; - body->shape.body = body; - body->shape.transform = MathMatFromRadians(0.0f); - body->shape.vertexData = CreateRectanglePolygon(pos, CLITERAL(Vector2){ width, height }); - - // Calculate centroid and moment of inertia - Vector2 center = { 0.0f, 0.0f }; - float area = 0.0f; - float inertia = 0.0f; - - for (unsigned int i = 0; i < body->shape.vertexData.vertexCount; i++) - { - // Triangle vertices, third vertex implied as (0, 0) - Vector2 p1 = body->shape.vertexData.positions[i]; - unsigned int nextIndex = (((i + 1) < body->shape.vertexData.vertexCount) ? (i + 1) : 0); - Vector2 p2 = body->shape.vertexData.positions[nextIndex]; - - float D = MathVector2CrossProduct(p1, p2); - float triangleArea = D/2; - - area += triangleArea; - - // Use area to weight the centroid average, not just vertex position - center.x += triangleArea*PHYSAC_K*(p1.x + p2.x); - center.y += triangleArea*PHYSAC_K*(p1.y + p2.y); - - float intx2 = p1.x*p1.x + p2.x*p1.x + p2.x*p2.x; - float inty2 = p1.y*p1.y + p2.y*p1.y + p2.y*p2.y; - inertia += (0.25f*PHYSAC_K*D)*(intx2 + inty2); - } - - center.x *= 1.0f/area; - center.y *= 1.0f/area; - - // Translate vertices to centroid (make the centroid (0, 0) for the polygon in model space) - // Note: this is not really necessary - for (unsigned int i = 0; i < body->shape.vertexData.vertexCount; i++) - { - body->shape.vertexData.positions[i].x -= center.x; - body->shape.vertexData.positions[i].y -= center.y; - } - - body->mass = density*area; - body->inverseMass = ((body->mass != 0.0f) ? 1.0f/body->mass : 0.0f); - body->inertia = density*inertia; - body->inverseInertia = ((body->inertia != 0.0f) ? 1.0f/body->inertia : 0.0f); - body->staticFriction = 0.4f; - body->dynamicFriction = 0.2f; - body->restitution = 0.0f; - body->useGravity = true; - body->isGrounded = false; - body->freezeOrient = false; - - // Add new body to bodies pointers array and update bodies count - bodies[physicsBodiesCount] = body; - physicsBodiesCount++; - - TRACELOG("[PHYSAC] Physic body created successfully (id: %i)\n", body->id); - } - else TRACELOG("[PHYSAC] Physic body could not be created, PHYSAC_MAX_BODIES reached\n"); - - return body; -} - -// Creates a new polygon physics body with generic parameters -PhysicsBody CreatePhysicsBodyPolygon(Vector2 pos, float radius, int sides, float density) -{ - PhysicsBody body = (PhysicsBody)PHYSAC_MALLOC(sizeof(PhysicsBodyData)); - usedMemory += sizeof(PhysicsBodyData); - - int id = FindAvailableBodyIndex(); - if (id != -1) - { - // Initialize new body with generic values - body->id = id; - body->enabled = true; - body->position = pos; - body->velocity = PHYSAC_VECTOR_ZERO; - body->force = PHYSAC_VECTOR_ZERO; - body->angularVelocity = 0.0f; - body->torque = 0.0f; - body->orient = 0.0f; - body->shape.type = PHYSICS_POLYGON; - body->shape.body = body; - body->shape.transform = MathMatFromRadians(0.0f); - body->shape.vertexData = CreateDefaultPolygon(radius, sides); - - // Calculate centroid and moment of inertia - Vector2 center = { 0.0f, 0.0f }; - float area = 0.0f; - float inertia = 0.0f; - - for (unsigned int i = 0; i < body->shape.vertexData.vertexCount; i++) - { - // Triangle vertices, third vertex implied as (0, 0) - Vector2 position1 = body->shape.vertexData.positions[i]; - unsigned int nextIndex = (((i + 1) < body->shape.vertexData.vertexCount) ? (i + 1) : 0); - Vector2 position2 = body->shape.vertexData.positions[nextIndex]; - - float cross = MathVector2CrossProduct(position1, position2); - float triangleArea = cross/2; - - area += triangleArea; - - // Use area to weight the centroid average, not just vertex position - center.x += triangleArea*PHYSAC_K*(position1.x + position2.x); - center.y += triangleArea*PHYSAC_K*(position1.y + position2.y); - - float intx2 = position1.x*position1.x + position2.x*position1.x + position2.x*position2.x; - float inty2 = position1.y*position1.y + position2.y*position1.y + position2.y*position2.y; - inertia += (0.25f*PHYSAC_K*cross)*(intx2 + inty2); - } - - center.x *= 1.0f/area; - center.y *= 1.0f/area; - - // Translate vertices to centroid (make the centroid (0, 0) for the polygon in model space) - // Note: this is not really necessary - for (unsigned int i = 0; i < body->shape.vertexData.vertexCount; i++) - { - body->shape.vertexData.positions[i].x -= center.x; - body->shape.vertexData.positions[i].y -= center.y; - } - - body->mass = density*area; - body->inverseMass = ((body->mass != 0.0f) ? 1.0f/body->mass : 0.0f); - body->inertia = density*inertia; - body->inverseInertia = ((body->inertia != 0.0f) ? 1.0f/body->inertia : 0.0f); - body->staticFriction = 0.4f; - body->dynamicFriction = 0.2f; - body->restitution = 0.0f; - body->useGravity = true; - body->isGrounded = false; - body->freezeOrient = false; - - // Add new body to bodies pointers array and update bodies count - bodies[physicsBodiesCount] = body; - physicsBodiesCount++; - - TRACELOG("[PHYSAC] Physic body created successfully (id: %i)\n", body->id); - } - else TRACELOG("[PHYSAC] Physics body could not be created, PHYSAC_MAX_BODIES reached\n"); - - return body; -} - -// Adds a force to a physics body -void PhysicsAddForce(PhysicsBody body, Vector2 force) -{ - if (body != NULL) body->force = MathVector2Add(body->force, force); -} - -// Adds an angular force to a physics body -void PhysicsAddTorque(PhysicsBody body, float amount) -{ - if (body != NULL) body->torque += amount; -} - -// Shatters a polygon shape physics body to little physics bodies with explosion force -void PhysicsShatter(PhysicsBody body, Vector2 position, float force) -{ - if (body != NULL) - { - if (body->shape.type == PHYSICS_POLYGON) - { - PhysicsVertexData vertexData = body->shape.vertexData; - bool collision = false; - - for (unsigned int i = 0; i < vertexData.vertexCount; i++) - { - Vector2 positionA = body->position; - Vector2 positionB = MathMatVector2Product(body->shape.transform, MathVector2Add(body->position, vertexData.positions[i])); - unsigned int nextIndex = (((i + 1) < vertexData.vertexCount) ? (i + 1) : 0); - Vector2 positionC = MathMatVector2Product(body->shape.transform, MathVector2Add(body->position, vertexData.positions[nextIndex])); - - // Check collision between each triangle - float alpha = ((positionB.y - positionC.y)*(position.x - positionC.x) + (positionC.x - positionB.x)*(position.y - positionC.y))/ - ((positionB.y - positionC.y)*(positionA.x - positionC.x) + (positionC.x - positionB.x)*(positionA.y - positionC.y)); - - float beta = ((positionC.y - positionA.y)*(position.x - positionC.x) + (positionA.x - positionC.x)*(position.y - positionC.y))/ - ((positionB.y - positionC.y)*(positionA.x - positionC.x) + (positionC.x - positionB.x)*(positionA.y - positionC.y)); - - float gamma = 1.0f - alpha - beta; - - if ((alpha > 0.0f) && (beta > 0.0f) & (gamma > 0.0f)) - { - collision = true; - break; - } - } - - if (collision) - { - int count = vertexData.vertexCount; - Vector2 bodyPos = body->position; - Vector2 *vertices = (Vector2 *)PHYSAC_MALLOC(sizeof(Vector2)*count); - Matrix2x2 trans = body->shape.transform; - for (int i = 0; i < count; i++) vertices[i] = vertexData.positions[i]; - - // Destroy shattered physics body - DestroyPhysicsBody(body); - - for (int i = 0; i < count; i++) - { - int nextIndex = (((i + 1) < count) ? (i + 1) : 0); - Vector2 center = MathTriangleBarycenter(vertices[i], vertices[nextIndex], PHYSAC_VECTOR_ZERO); - center = MathVector2Add(bodyPos, center); - Vector2 offset = MathVector2Subtract(center, bodyPos); - - PhysicsBody body = CreatePhysicsBodyPolygon(center, 10, 3, 10); // Create polygon physics body with relevant values - - PhysicsVertexData vertexData = { 0 }; - vertexData.vertexCount = 3; - - vertexData.positions[0] = MathVector2Subtract(vertices[i], offset); - vertexData.positions[1] = MathVector2Subtract(vertices[nextIndex], offset); - vertexData.positions[2] = MathVector2Subtract(position, center); - - // Separate vertices to avoid unnecessary physics collisions - vertexData.positions[0].x *= 0.95f; - vertexData.positions[0].y *= 0.95f; - vertexData.positions[1].x *= 0.95f; - vertexData.positions[1].y *= 0.95f; - vertexData.positions[2].x *= 0.95f; - vertexData.positions[2].y *= 0.95f; - - // Calculate polygon faces normals - for (unsigned int j = 0; j < vertexData.vertexCount; j++) - { - unsigned int nextVertex = (((j + 1) < vertexData.vertexCount) ? (j + 1) : 0); - Vector2 face = MathVector2Subtract(vertexData.positions[nextVertex], vertexData.positions[j]); - - vertexData.normals[j] = CLITERAL(Vector2){ face.y, -face.x }; - MathVector2Normalize(&vertexData.normals[j]); - } - - // Apply computed vertex data to new physics body shape - body->shape.vertexData = vertexData; - body->shape.transform = trans; - - // Calculate centroid and moment of inertia - center = PHYSAC_VECTOR_ZERO; - float area = 0.0f; - float inertia = 0.0f; - - for (unsigned int j = 0; j < body->shape.vertexData.vertexCount; j++) - { - // Triangle vertices, third vertex implied as (0, 0) - Vector2 p1 = body->shape.vertexData.positions[j]; - unsigned int nextVertex = (((j + 1) < body->shape.vertexData.vertexCount) ? (j + 1) : 0); - Vector2 p2 = body->shape.vertexData.positions[nextVertex]; - - float D = MathVector2CrossProduct(p1, p2); - float triangleArea = D/2; - - area += triangleArea; - - // Use area to weight the centroid average, not just vertex position - center.x += triangleArea*PHYSAC_K*(p1.x + p2.x); - center.y += triangleArea*PHYSAC_K*(p1.y + p2.y); - - float intx2 = p1.x*p1.x + p2.x*p1.x + p2.x*p2.x; - float inty2 = p1.y*p1.y + p2.y*p1.y + p2.y*p2.y; - inertia += (0.25f*PHYSAC_K*D)*(intx2 + inty2); - } - - center.x *= 1.0f/area; - center.y *= 1.0f/area; - - body->mass = area; - body->inverseMass = ((body->mass != 0.0f) ? 1.0f/body->mass : 0.0f); - body->inertia = inertia; - body->inverseInertia = ((body->inertia != 0.0f) ? 1.0f/body->inertia : 0.0f); - - // Calculate explosion force direction - Vector2 pointA = body->position; - Vector2 pointB = MathVector2Subtract(vertexData.positions[1], vertexData.positions[0]); - pointB.x /= 2.0f; - pointB.y /= 2.0f; - Vector2 forceDirection = MathVector2Subtract(MathVector2Add(pointA, MathVector2Add(vertexData.positions[0], pointB)), body->position); - MathVector2Normalize(&forceDirection); - forceDirection.x *= force; - forceDirection.y *= force; - - // Apply force to new physics body - PhysicsAddForce(body, forceDirection); - } - - PHYSAC_FREE(vertices); - } - } - } - else TRACELOG("[PHYSAC] WARNING: PhysicsShatter: NULL physic body\n"); -} - -// Returns the current amount of created physics bodies -int GetPhysicsBodiesCount(void) -{ - return physicsBodiesCount; -} - -// Returns a physics body of the bodies pool at a specific index -PhysicsBody GetPhysicsBody(int index) -{ - PhysicsBody body = NULL; - - if (index < (int)physicsBodiesCount) - { - body = bodies[index]; - - if (body == NULL) TRACELOG("[PHYSAC] WARNING: GetPhysicsBody: NULL physic body\n"); - } - else TRACELOG("[PHYSAC] WARNING: Physic body index is out of bounds\n"); - - return body; -} - -// Returns the physics body shape type (PHYSICS_CIRCLE or PHYSICS_POLYGON) -int GetPhysicsShapeType(int index) -{ - int result = -1; - - if (index < (int)physicsBodiesCount) - { - PhysicsBody body = bodies[index]; - - if (body != NULL) result = body->shape.type; - else TRACELOG("[PHYSAC] WARNING: GetPhysicsShapeType: NULL physic body\n"); - } - else TRACELOG("[PHYSAC] WARNING: Physic body index is out of bounds\n"); - - return result; -} - -// Returns the amount of vertices of a physics body shape -int GetPhysicsShapeVerticesCount(int index) -{ - int result = 0; - - if (index < (int)physicsBodiesCount) - { - PhysicsBody body = bodies[index]; - - if (body != NULL) - { - switch (body->shape.type) - { - case PHYSICS_CIRCLE: result = PHYSAC_DEFAULT_CIRCLE_VERTICES; break; - case PHYSICS_POLYGON: result = body->shape.vertexData.vertexCount; break; - default: break; - } - } - else TRACELOG("[PHYSAC] WARNING: GetPhysicsShapeVerticesCount: NULL physic body\n"); - } - else TRACELOG("[PHYSAC] WARNING: Physic body index is out of bounds\n"); - - return result; -} - -// Returns transformed position of a body shape (body position + vertex transformed position) -Vector2 GetPhysicsShapeVertex(PhysicsBody body, int vertex) -{ - Vector2 position = { 0.0f, 0.0f }; - - if (body != NULL) - { - switch (body->shape.type) - { - case PHYSICS_CIRCLE: - { - position.x = body->position.x + cosf(360.0f/PHYSAC_DEFAULT_CIRCLE_VERTICES*vertex*PHYSAC_DEG2RAD)*body->shape.radius; - position.y = body->position.y + sinf(360.0f/PHYSAC_DEFAULT_CIRCLE_VERTICES*vertex*PHYSAC_DEG2RAD)*body->shape.radius; - } break; - case PHYSICS_POLYGON: - { - PhysicsVertexData vertexData = body->shape.vertexData; - position = MathVector2Add(body->position, MathMatVector2Product(body->shape.transform, vertexData.positions[vertex])); - } break; - default: break; - } - } - else TRACELOG("[PHYSAC] WARNING: GetPhysicsShapeVertex: NULL physic body\n"); - - return position; -} - -// Sets physics body shape transform based on radians parameter -void SetPhysicsBodyRotation(PhysicsBody body, float radians) -{ - if (body != NULL) - { - body->orient = radians; - - if (body->shape.type == PHYSICS_POLYGON) body->shape.transform = MathMatFromRadians(radians); - } -} - -// Unitializes and destroys a physics body -void DestroyPhysicsBody(PhysicsBody body) -{ - if (body != NULL) - { - int id = body->id; - int index = -1; - - for (unsigned int i = 0; i < physicsBodiesCount; i++) - { - if (bodies[i]->id == id) - { - index = i; - break; - } - } - - if (index == -1) - { - TRACELOG("[PHYSAC] WARNING: Requested body (id: %i) can not be found\n", id); - return; // Prevent access to index -1 - } - - // Free body allocated memory - PHYSAC_FREE(body); - usedMemory -= sizeof(PhysicsBodyData); - bodies[index] = NULL; - - // Reorder physics bodies pointers array and its catched index - for (unsigned int i = index; i < physicsBodiesCount; i++) - { - if ((i + 1) < physicsBodiesCount) bodies[i] = bodies[i + 1]; - } - - // Update physics bodies count - physicsBodiesCount--; - - TRACELOG("[PHYSAC] Physic body destroyed successfully (id: %i)\n", id); - } - else TRACELOG("[PHYSAC] WARNING: DestroyPhysicsBody: NULL physic body\n"); -} - -// Destroys created physics bodies and manifolds and resets global values -void ResetPhysics(void) -{ - if (physicsBodiesCount > 0) - { - // Unitialize physics bodies dynamic memory allocations - for (int i = physicsBodiesCount - 1; i >= 0; i--) - { - PhysicsBody body = bodies[i]; - - if (body != NULL) - { - PHYSAC_FREE(body); - bodies[i] = NULL; - usedMemory -= sizeof(PhysicsBodyData); - } - } - - physicsBodiesCount = 0; - } - - if (physicsManifoldsCount > 0) - { - // Unitialize physics manifolds dynamic memory allocations - for (int i = physicsManifoldsCount - 1; i >= 0; i--) - { - PhysicsManifold manifold = contacts[i]; - - if (manifold != NULL) - { - PHYSAC_FREE(manifold); - contacts[i] = NULL; - usedMemory -= sizeof(PhysicsManifoldData); - } - } - - physicsManifoldsCount = 0; - } - - TRACELOG("[PHYSAC] Physics module reseted successfully\n"); -} - -// Unitializes physics pointers and exits physics loop thread -void ClosePhysics(void) -{ - // Unitialize physics manifolds dynamic memory allocations - if (physicsManifoldsCount > 0) - { - for (int i = physicsManifoldsCount - 1; i >= 0; i--) DestroyPhysicsManifold(contacts[i]); - } - - // Unitialize physics bodies dynamic memory allocations - if (physicsBodiesCount > 0) - { - for (int i = physicsBodiesCount - 1; i >= 0; i--) DestroyPhysicsBody(bodies[i]); - } - - // Trace log info - if ((physicsBodiesCount > 0) || (usedMemory != 0)) - { - TRACELOG("[PHYSAC] WARNING: Physics module closed with unallocated bodies (BODIES: %i, MEMORY: %i bytes)\n", physicsBodiesCount, usedMemory); - } - else if ((physicsManifoldsCount > 0) || (usedMemory != 0)) - { - TRACELOG("[PHYSAC] WARNING: Pysics module closed with unallocated manifolds (MANIFOLDS: %i, MEMORY: %i bytes)\n", physicsManifoldsCount, usedMemory); - } - else TRACELOG("[PHYSAC] Physics module closed successfully\n"); -} - -// 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 -//---------------------------------------------------------------------------------- -#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 - -// Update physics step (dynamics, collisions and position corrections) -static void UpdatePhysicsStep(void) -{ - // Clear previous generated collisions information - for (int i = (int)physicsManifoldsCount - 1; i >= 0; i--) - { - PhysicsManifold manifold = contacts[i]; - if (manifold != NULL) DestroyPhysicsManifold(manifold); - } - - // Reset physics bodies grounded state - for (unsigned int i = 0; i < physicsBodiesCount; i++) - { - PhysicsBody body = bodies[i]; - body->isGrounded = false; - } - - // Generate new collision information - for (unsigned int i = 0; i < physicsBodiesCount; i++) - { - PhysicsBody bodyA = bodies[i]; - - if (bodyA != NULL) - { - for (unsigned int j = i + 1; j < physicsBodiesCount; j++) - { - PhysicsBody bodyB = bodies[j]; - - if (bodyB != NULL) - { - if ((bodyA->inverseMass == 0) && (bodyB->inverseMass == 0)) continue; - - PhysicsManifold manifold = CreatePhysicsManifold(bodyA, bodyB); - SolvePhysicsManifold(manifold); - - if (manifold->contactsCount > 0) - { - // Create a new manifold with same information as previously solved manifold and add it to the manifolds pool last slot - PhysicsManifold manifold = CreatePhysicsManifold(bodyA, bodyB); - manifold->penetration = manifold->penetration; - manifold->normal = manifold->normal; - manifold->contacts[0] = manifold->contacts[0]; - manifold->contacts[1] = manifold->contacts[1]; - manifold->contactsCount = manifold->contactsCount; - manifold->restitution = manifold->restitution; - manifold->dynamicFriction = manifold->dynamicFriction; - manifold->staticFriction = manifold->staticFriction; - } - } - } - } - } - - // Integrate forces to physics bodies - for (unsigned int i = 0; i < physicsBodiesCount; i++) - { - PhysicsBody body = bodies[i]; - if (body != NULL) IntegratePhysicsForces(body); - } - - // Initialize physics manifolds to solve collisions - for (unsigned int i = 0; i < physicsManifoldsCount; i++) - { - PhysicsManifold manifold = contacts[i]; - if (manifold != NULL) InitializePhysicsManifolds(manifold); - } - - // Integrate physics collisions impulses to solve collisions - for (unsigned int i = 0; i < PHYSAC_COLLISION_ITERATIONS; i++) - { - for (unsigned int j = 0; j < physicsManifoldsCount; j++) - { - PhysicsManifold manifold = contacts[i]; - if (manifold != NULL) IntegratePhysicsImpulses(manifold); - } - } - - // Integrate velocity to physics bodies - for (unsigned int i = 0; i < physicsBodiesCount; i++) - { - PhysicsBody body = bodies[i]; - if (body != NULL) IntegratePhysicsVelocity(body); - } - - // Correct physics bodies positions based on manifolds collision information - for (unsigned int i = 0; i < physicsManifoldsCount; i++) - { - PhysicsManifold manifold = contacts[i]; - if (manifold != NULL) CorrectPhysicsPositions(manifold); - } - - // Clear physics bodies forces - for (unsigned int i = 0; i < physicsBodiesCount; i++) - { - PhysicsBody body = bodies[i]; - if (body != NULL) - { - body->force = PHYSAC_VECTOR_ZERO; - body->torque = 0.0f; - } - } -} - -// Finds a valid index for a new physics body initialization -static int FindAvailableBodyIndex() -{ - int index = -1; - for (int i = 0; i < PHYSAC_MAX_BODIES; i++) - { - int currentId = i; - - // Check if current id already exist in other physics body - for (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; - } - } - - return index; -} - -// Creates a default polygon shape with max vertex distance from polygon pivot -static PhysicsVertexData CreateDefaultPolygon(float radius, int sides) -{ - 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 -static int FindAvailableManifoldIndex() -{ - int index = -1; - for (int i = 0; i < PHYSAC_MAX_MANIFOLDS; i++) - { - int currentId = i; - - // Check if current id already exist in other physics body - for (unsigned int k = 0; k < physicsManifoldsCount; k++) - { - if (contacts[k]->id == currentId) - { - currentId++; - break; - } - } - - // If it is not used, use it as new physics body id - if (currentId == i) - { - index = i; - break; - } - } - - return index; -} - -// Creates a new physics manifold to solve collision -static PhysicsManifold CreatePhysicsManifold(PhysicsBody a, PhysicsBody b) -{ - PhysicsManifold manifold = (PhysicsManifold)PHYSAC_MALLOC(sizeof(PhysicsManifoldData)); - usedMemory += sizeof(PhysicsManifoldData); - - int id = FindAvailableManifoldIndex(); - if (id != -1) - { - // Initialize new manifold with generic values - manifold->id = id; - manifold->bodyA = a; - manifold->bodyB = b; - manifold->penetration = 0; - manifold->normal = PHYSAC_VECTOR_ZERO; - manifold->contacts[0] = PHYSAC_VECTOR_ZERO; - manifold->contacts[1] = PHYSAC_VECTOR_ZERO; - manifold->contactsCount = 0; - manifold->restitution = 0.0f; - manifold->dynamicFriction = 0.0f; - manifold->staticFriction = 0.0f; - - // Add new body to bodies pointers array and update bodies count - contacts[physicsManifoldsCount] = manifold; - physicsManifoldsCount++; - } - else TRACELOG("[PHYSAC] Physic manifold could not be created, PHYSAC_MAX_MANIFOLDS reached\n"); - - return manifold; -} - -// Unitializes and destroys a physics manifold -static void DestroyPhysicsManifold(PhysicsManifold manifold) -{ - if (manifold != NULL) - { - int id = manifold->id; - int index = -1; - - for (unsigned int i = 0; i < physicsManifoldsCount; i++) - { - if (contacts[i]->id == id) - { - index = i; - break; - } - } - - if (index == -1) return; // Prevent access to index -1 - - // Free manifold allocated memory - PHYSAC_FREE(manifold); - usedMemory -= sizeof(PhysicsManifoldData); - contacts[index] = NULL; - - // Reorder physics manifolds pointers array and its catched index - for (unsigned int i = index; i < physicsManifoldsCount; i++) - { - if ((i + 1) < physicsManifoldsCount) contacts[i] = contacts[i + 1]; - } - - // Update physics manifolds count - physicsManifoldsCount--; - } - else TRACELOG("[PHYSAC] WARNING: DestroyPhysicsManifold: NULL physic manifold\n"); -} - -// Solves a created physics manifold between two physics bodies -static void SolvePhysicsManifold(PhysicsManifold manifold) -{ - switch (manifold->bodyA->shape.type) - { - case PHYSICS_CIRCLE: - { - switch (manifold->bodyB->shape.type) - { - case PHYSICS_CIRCLE: SolveCircleToCircle(manifold); break; - case PHYSICS_POLYGON: SolveCircleToPolygon(manifold); break; - default: break; - } - } break; - case PHYSICS_POLYGON: - { - switch (manifold->bodyB->shape.type) - { - case PHYSICS_CIRCLE: SolvePolygonToCircle(manifold); break; - case PHYSICS_POLYGON: SolvePolygonToPolygon(manifold); break; - default: break; - } - } break; - default: break; - } - - // Update physics body grounded state if normal direction is down and grounded state is not set yet in previous manifolds - if (!manifold->bodyB->isGrounded) manifold->bodyB->isGrounded = (manifold->normal.y < 0); -} - -// Solves collision between two circle shape physics bodies -static void SolveCircleToCircle(PhysicsManifold manifold) -{ - PhysicsBody bodyA = manifold->bodyA; - PhysicsBody bodyB = manifold->bodyB; - - if ((bodyA == NULL) || (bodyB == NULL)) return; - - // Calculate translational vector, which is normal - Vector2 normal = MathVector2Subtract(bodyB->position, bodyA->position); - - float distSqr = MathVector2SqrLen(normal); - float radius = bodyA->shape.radius + bodyB->shape.radius; - - // Check if circles are not in contact - if (distSqr >= radius*radius) - { - manifold->contactsCount = 0; - return; - } - - float distance = sqrtf(distSqr); - manifold->contactsCount = 1; - - if (distance == 0.0f) - { - manifold->penetration = bodyA->shape.radius; - manifold->normal = CLITERAL(Vector2){ 1.0f, 0.0f }; - manifold->contacts[0] = bodyA->position; - } - else - { - manifold->penetration = radius - distance; - manifold->normal = CLITERAL(Vector2){ normal.x/distance, normal.y/distance }; // Faster than using MathVector2Normalize() due to sqrt is already performed - manifold->contacts[0] = CLITERAL(Vector2){ manifold->normal.x*bodyA->shape.radius + bodyA->position.x, manifold->normal.y*bodyA->shape.radius + bodyA->position.y }; - } - - // Update physics body grounded state if normal direction is down - if (!bodyA->isGrounded) bodyA->isGrounded = (manifold->normal.y < 0); -} - -// Solves collision between a circle to a polygon shape physics bodies -static void SolveCircleToPolygon(PhysicsManifold manifold) -{ - PhysicsBody bodyA = manifold->bodyA; - PhysicsBody bodyB = manifold->bodyB; - - if ((bodyA == NULL) || (bodyB == NULL)) return; - - manifold->contactsCount = 0; - - // Transform circle center to polygon transform space - Vector2 center = bodyA->position; - center = MathMatVector2Product(MathMatTranspose(bodyB->shape.transform), MathVector2Subtract(center, bodyB->position)); - - // Find edge with minimum penetration - // It is the same concept as using support points in SolvePolygonToPolygon - float separation = -PHYSAC_FLT_MAX; - int faceNormal = 0; - PhysicsVertexData vertexData = bodyB->shape.vertexData; - - for (unsigned int i = 0; i < vertexData.vertexCount; i++) - { - float currentSeparation = MathVector2DotProduct(vertexData.normals[i], MathVector2Subtract(center, vertexData.positions[i])); - - if (currentSeparation > bodyA->shape.radius) return; - - if (currentSeparation > separation) - { - separation = currentSeparation; - faceNormal = i; - } - } - - // Grab face's vertices - Vector2 v1 = vertexData.positions[faceNormal]; - int nextIndex = (((faceNormal + 1) < (int)vertexData.vertexCount) ? (faceNormal + 1) : 0); - Vector2 v2 = vertexData.positions[nextIndex]; - - // Check to see if center is within polygon - if (separation < PHYSAC_EPSILON) - { - manifold->contactsCount = 1; - Vector2 normal = MathMatVector2Product(bodyB->shape.transform, vertexData.normals[faceNormal]); - manifold->normal = CLITERAL(Vector2){ -normal.x, -normal.y }; - manifold->contacts[0] = CLITERAL(Vector2){ manifold->normal.x*bodyA->shape.radius + bodyA->position.x, manifold->normal.y*bodyA->shape.radius + bodyA->position.y }; - manifold->penetration = bodyA->shape.radius; - return; - } - - // Determine which voronoi region of the edge center of circle lies within - float dot1 = MathVector2DotProduct(MathVector2Subtract(center, v1), MathVector2Subtract(v2, v1)); - float dot2 = MathVector2DotProduct(MathVector2Subtract(center, v2), MathVector2Subtract(v1, v2)); - manifold->penetration = bodyA->shape.radius - separation; - - if (dot1 <= 0.0f) // Closest to v1 - { - if (MathVector2SqrDistance(center, v1) > bodyA->shape.radius*bodyA->shape.radius) return; - - manifold->contactsCount = 1; - Vector2 normal = MathVector2Subtract(v1, center); - normal = MathMatVector2Product(bodyB->shape.transform, normal); - MathVector2Normalize(&normal); - manifold->normal = normal; - v1 = MathMatVector2Product(bodyB->shape.transform, v1); - v1 = MathVector2Add(v1, bodyB->position); - manifold->contacts[0] = v1; - } - else if (dot2 <= 0.0f) // Closest to v2 - { - if (MathVector2SqrDistance(center, v2) > bodyA->shape.radius*bodyA->shape.radius) return; - - manifold->contactsCount = 1; - Vector2 normal = MathVector2Subtract(v2, center); - v2 = MathMatVector2Product(bodyB->shape.transform, v2); - v2 = MathVector2Add(v2, bodyB->position); - manifold->contacts[0] = v2; - normal = MathMatVector2Product(bodyB->shape.transform, normal); - MathVector2Normalize(&normal); - manifold->normal = normal; - } - else // Closest to face - { - Vector2 normal = vertexData.normals[faceNormal]; - - if (MathVector2DotProduct(MathVector2Subtract(center, v1), normal) > bodyA->shape.radius) return; - - normal = MathMatVector2Product(bodyB->shape.transform, normal); - manifold->normal = CLITERAL(Vector2){ -normal.x, -normal.y }; - manifold->contacts[0] = CLITERAL(Vector2){ manifold->normal.x*bodyA->shape.radius + bodyA->position.x, manifold->normal.y*bodyA->shape.radius + bodyA->position.y }; - manifold->contactsCount = 1; - } -} - -// Solves collision between a polygon to a circle shape physics bodies -static void SolvePolygonToCircle(PhysicsManifold manifold) -{ - PhysicsBody bodyA = manifold->bodyA; - PhysicsBody bodyB = manifold->bodyB; - - if ((bodyA == NULL) || (bodyB == NULL)) return; - - manifold->bodyA = bodyB; - manifold->bodyB = bodyA; - SolveCircleToPolygon(manifold); - - manifold->normal.x *= -1.0f; - manifold->normal.y *= -1.0f; -} - -// Solves collision between two polygons shape physics bodies -static void SolvePolygonToPolygon(PhysicsManifold manifold) -{ - if ((manifold->bodyA == NULL) || (manifold->bodyB == NULL)) return; - - PhysicsShape bodyA = manifold->bodyA->shape; - PhysicsShape bodyB = manifold->bodyB->shape; - manifold->contactsCount = 0; - - // Check for separating axis with A shape's face planes - int faceA = 0; - float penetrationA = FindAxisLeastPenetration(&faceA, bodyA, bodyB); - if (penetrationA >= 0.0f) return; - - // Check for separating axis with B shape's face planes - int faceB = 0; - float penetrationB = FindAxisLeastPenetration(&faceB, bodyB, bodyA); - if (penetrationB >= 0.0f) return; - - int referenceIndex = 0; - bool flip = false; // Always point from A shape to B shape - - PhysicsShape refPoly; // Reference - PhysicsShape incPoly; // Incident - - // Determine which shape contains reference face - // Checking bias range for penetration - if (penetrationA >= (penetrationB*0.95f + penetrationA*0.01f)) - { - refPoly = bodyA; - incPoly = bodyB; - referenceIndex = faceA; - } - else - { - refPoly = bodyB; - incPoly = bodyA; - referenceIndex = faceB; - flip = true; - } - - // World space incident face - Vector2 incidentFace[2]; - FindIncidentFace(&incidentFace[0], &incidentFace[1], refPoly, incPoly, referenceIndex); - - // Setup reference face vertices - PhysicsVertexData refData = refPoly.vertexData; - Vector2 v1 = refData.positions[referenceIndex]; - referenceIndex = (((referenceIndex + 1) < (int)refData.vertexCount) ? (referenceIndex + 1) : 0); - Vector2 v2 = refData.positions[referenceIndex]; - - // Transform vertices to world space - v1 = MathMatVector2Product(refPoly.transform, v1); - v1 = MathVector2Add(v1, refPoly.body->position); - v2 = MathMatVector2Product(refPoly.transform, v2); - v2 = MathVector2Add(v2, refPoly.body->position); - - // Calculate reference face side normal in world space - Vector2 sidePlaneNormal = MathVector2Subtract(v2, v1); - MathVector2Normalize(&sidePlaneNormal); - - // Orthogonalize - Vector2 refFaceNormal = { sidePlaneNormal.y, -sidePlaneNormal.x }; - float refC = MathVector2DotProduct(refFaceNormal, v1); - float negSide = MathVector2DotProduct(sidePlaneNormal, v1)*-1; - float posSide = MathVector2DotProduct(sidePlaneNormal, v2); - - // MathVector2Clip incident face to reference face side planes (due to floating point error, possible to not have required points - if (MathVector2Clip(CLITERAL(Vector2){ -sidePlaneNormal.x, -sidePlaneNormal.y }, &incidentFace[0], &incidentFace[1], negSide) < 2) return; - if (MathVector2Clip(sidePlaneNormal, &incidentFace[0], &incidentFace[1], posSide) < 2) return; - - // Flip normal if required - manifold->normal = (flip ? CLITERAL(Vector2){ -refFaceNormal.x, -refFaceNormal.y } : refFaceNormal); - - // Keep points behind reference face - int currentPoint = 0; // MathVector2Clipped points behind reference face - float separation = MathVector2DotProduct(refFaceNormal, incidentFace[0]) - refC; - if (separation <= 0.0f) - { - manifold->contacts[currentPoint] = incidentFace[0]; - manifold->penetration = -separation; - currentPoint++; - } - else manifold->penetration = 0.0f; - - separation = MathVector2DotProduct(refFaceNormal, incidentFace[1]) - refC; - - if (separation <= 0.0f) - { - manifold->contacts[currentPoint] = incidentFace[1]; - manifold->penetration += -separation; - currentPoint++; - - // Calculate total penetration average - manifold->penetration /= currentPoint; - } - - manifold->contactsCount = currentPoint; -} - -// Integrates physics forces into velocity -static void IntegratePhysicsForces(PhysicsBody body) -{ - if ((body == NULL) || (body->inverseMass == 0.0f) || !body->enabled) return; - - body->velocity.x += (float)((body->force.x*body->inverseMass)*(deltaTime/2.0)); - body->velocity.y += (float)((body->force.y*body->inverseMass)*(deltaTime/2.0)); - - if (body->useGravity) - { - body->velocity.x += (float)(gravityForce.x*(deltaTime/1000/2.0)); - body->velocity.y += (float)(gravityForce.y*(deltaTime/1000/2.0)); - } - - if (!body->freezeOrient) body->angularVelocity += (float)(body->torque*body->inverseInertia*(deltaTime/2.0)); -} - -// Initializes physics manifolds to solve collisions -static void InitializePhysicsManifolds(PhysicsManifold manifold) -{ - PhysicsBody bodyA = manifold->bodyA; - PhysicsBody bodyB = manifold->bodyB; - - if ((bodyA == NULL) || (bodyB == NULL)) return; - - // Calculate average restitution, static and dynamic friction - manifold->restitution = sqrtf(bodyA->restitution*bodyB->restitution); - manifold->staticFriction = sqrtf(bodyA->staticFriction*bodyB->staticFriction); - manifold->dynamicFriction = sqrtf(bodyA->dynamicFriction*bodyB->dynamicFriction); - - for (unsigned int i = 0; i < manifold->contactsCount; i++) - { - // Caculate radius from center of mass to contact - Vector2 radiusA = MathVector2Subtract(manifold->contacts[i], bodyA->position); - Vector2 radiusB = MathVector2Subtract(manifold->contacts[i], bodyB->position); - - Vector2 crossA = MathVector2Product(radiusA, bodyA->angularVelocity); - Vector2 crossB = MathVector2Product(radiusB, bodyB->angularVelocity); - - Vector2 radiusV = { 0.0f, 0.0f }; - radiusV.x = bodyB->velocity.x + crossB.x - bodyA->velocity.x - crossA.x; - radiusV.y = bodyB->velocity.y + crossB.y - bodyA->velocity.y - crossA.y; - - // Determine if we should perform a resting collision or not; - // The idea is if the only thing moving this object is gravity, then the collision should be performed without any restitution - if (MathVector2SqrLen(radiusV) < (MathVector2SqrLen(CLITERAL(Vector2){ (float)(gravityForce.x*deltaTime/1000), (float)(gravityForce.y*deltaTime/1000) }) + PHYSAC_EPSILON)) manifold->restitution = 0; - } -} - -// Integrates physics collisions impulses to solve collisions -static void IntegratePhysicsImpulses(PhysicsManifold manifold) -{ - PhysicsBody bodyA = manifold->bodyA; - PhysicsBody bodyB = manifold->bodyB; - - if ((bodyA == NULL) || (bodyB == NULL)) return; - - // Early out and positional correct if both objects have infinite mass - if (fabs(bodyA->inverseMass + bodyB->inverseMass) <= PHYSAC_EPSILON) - { - bodyA->velocity = PHYSAC_VECTOR_ZERO; - bodyB->velocity = PHYSAC_VECTOR_ZERO; - return; - } - - for (unsigned int i = 0; i < manifold->contactsCount; i++) - { - // Calculate radius from center of mass to contact - Vector2 radiusA = MathVector2Subtract(manifold->contacts[i], bodyA->position); - Vector2 radiusB = MathVector2Subtract(manifold->contacts[i], bodyB->position); - - // Calculate relative velocity - Vector2 radiusV = { 0.0f, 0.0f }; - radiusV.x = bodyB->velocity.x + MathVector2Product(radiusB, bodyB->angularVelocity).x - bodyA->velocity.x - MathVector2Product(radiusA, bodyA->angularVelocity).x; - radiusV.y = bodyB->velocity.y + MathVector2Product(radiusB, bodyB->angularVelocity).y - bodyA->velocity.y - MathVector2Product(radiusA, bodyA->angularVelocity).y; - - // Relative velocity along the normal - float contactVelocity = MathVector2DotProduct(radiusV, manifold->normal); - - // Do not resolve if velocities are separating - if (contactVelocity > 0.0f) return; - - float raCrossN = MathVector2CrossProduct(radiusA, manifold->normal); - float rbCrossN = MathVector2CrossProduct(radiusB, manifold->normal); - - float inverseMassSum = bodyA->inverseMass + bodyB->inverseMass + (raCrossN*raCrossN)*bodyA->inverseInertia + (rbCrossN*rbCrossN)*bodyB->inverseInertia; - - // Calculate impulse scalar value - float impulse = -(1.0f + manifold->restitution)*contactVelocity; - impulse /= inverseMassSum; - impulse /= (float)manifold->contactsCount; - - // Apply impulse to each physics body - Vector2 impulseV = { manifold->normal.x*impulse, manifold->normal.y*impulse }; - - if (bodyA->enabled) - { - bodyA->velocity.x += bodyA->inverseMass*(-impulseV.x); - bodyA->velocity.y += bodyA->inverseMass*(-impulseV.y); - if (!bodyA->freezeOrient) bodyA->angularVelocity += bodyA->inverseInertia*MathVector2CrossProduct(radiusA, CLITERAL(Vector2){ -impulseV.x, -impulseV.y }); - } - - if (bodyB->enabled) - { - bodyB->velocity.x += bodyB->inverseMass*(impulseV.x); - bodyB->velocity.y += bodyB->inverseMass*(impulseV.y); - if (!bodyB->freezeOrient) bodyB->angularVelocity += bodyB->inverseInertia*MathVector2CrossProduct(radiusB, impulseV); - } - - // Apply friction impulse to each physics body - radiusV.x = bodyB->velocity.x + MathVector2Product(radiusB, bodyB->angularVelocity).x - bodyA->velocity.x - MathVector2Product(radiusA, bodyA->angularVelocity).x; - radiusV.y = bodyB->velocity.y + MathVector2Product(radiusB, bodyB->angularVelocity).y - bodyA->velocity.y - MathVector2Product(radiusA, bodyA->angularVelocity).y; - - Vector2 tangent = { radiusV.x - (manifold->normal.x*MathVector2DotProduct(radiusV, manifold->normal)), radiusV.y - (manifold->normal.y*MathVector2DotProduct(radiusV, manifold->normal)) }; - MathVector2Normalize(&tangent); - - // Calculate impulse tangent magnitude - float impulseTangent = -MathVector2DotProduct(radiusV, tangent); - impulseTangent /= inverseMassSum; - impulseTangent /= (float)manifold->contactsCount; - - float absImpulseTangent = (float)fabs(impulseTangent); - - // Don't apply tiny friction impulses - if (absImpulseTangent <= PHYSAC_EPSILON) return; - - // Apply coulumb's law - Vector2 tangentImpulse = { 0.0f, 0.0f }; - if (absImpulseTangent < impulse*manifold->staticFriction) tangentImpulse = CLITERAL(Vector2){ tangent.x*impulseTangent, tangent.y*impulseTangent }; - else tangentImpulse = CLITERAL(Vector2){ tangent.x*-impulse*manifold->dynamicFriction, tangent.y*-impulse*manifold->dynamicFriction }; - - // Apply friction impulse - if (bodyA->enabled) - { - bodyA->velocity.x += bodyA->inverseMass*(-tangentImpulse.x); - bodyA->velocity.y += bodyA->inverseMass*(-tangentImpulse.y); - - if (!bodyA->freezeOrient) bodyA->angularVelocity += bodyA->inverseInertia*MathVector2CrossProduct(radiusA, CLITERAL(Vector2){ -tangentImpulse.x, -tangentImpulse.y }); - } - - if (bodyB->enabled) - { - bodyB->velocity.x += bodyB->inverseMass*(tangentImpulse.x); - bodyB->velocity.y += bodyB->inverseMass*(tangentImpulse.y); - - if (!bodyB->freezeOrient) bodyB->angularVelocity += bodyB->inverseInertia*MathVector2CrossProduct(radiusB, tangentImpulse); - } - } -} - -// Integrates physics velocity into position and forces -static void IntegratePhysicsVelocity(PhysicsBody body) -{ - if ((body == NULL) ||!body->enabled) return; - - body->position.x += (float)(body->velocity.x*deltaTime); - body->position.y += (float)(body->velocity.y*deltaTime); - - if (!body->freezeOrient) body->orient += (float)(body->angularVelocity*deltaTime); - body->shape.transform = MathMatFromRadians(body->orient); - - IntegratePhysicsForces(body); -} - -// Corrects physics bodies positions based on manifolds collision information -static void CorrectPhysicsPositions(PhysicsManifold manifold) -{ - PhysicsBody bodyA = manifold->bodyA; - PhysicsBody bodyB = manifold->bodyB; - - if ((bodyA == NULL) || (bodyB == NULL)) return; - - Vector2 correction = { 0.0f, 0.0f }; - correction.x = (PHYSAC_MAX(manifold->penetration - PHYSAC_PENETRATION_ALLOWANCE, 0.0f)/(bodyA->inverseMass + bodyB->inverseMass))*manifold->normal.x*PHYSAC_PENETRATION_CORRECTION; - correction.y = (PHYSAC_MAX(manifold->penetration - PHYSAC_PENETRATION_ALLOWANCE, 0.0f)/(bodyA->inverseMass + bodyB->inverseMass))*manifold->normal.y*PHYSAC_PENETRATION_CORRECTION; - - if (bodyA->enabled) - { - bodyA->position.x -= correction.x*bodyA->inverseMass; - bodyA->position.y -= correction.y*bodyA->inverseMass; - } - - if (bodyB->enabled) - { - bodyB->position.x += correction.x*bodyB->inverseMass; - bodyB->position.y += correction.y*bodyB->inverseMass; - } -} - -// Returns the extreme point along a direction within a polygon -static Vector2 GetSupport(PhysicsShape shape, Vector2 dir) -{ - float bestProjection = -PHYSAC_FLT_MAX; - Vector2 bestVertex = { 0.0f, 0.0f }; - PhysicsVertexData data = shape.vertexData; - - for (unsigned int i = 0; i < data.vertexCount; i++) - { - Vector2 vertex = data.positions[i]; - float projection = MathVector2DotProduct(vertex, dir); - - if (projection > bestProjection) - { - bestVertex = vertex; - bestProjection = projection; - } - } - - return bestVertex; -} - -// Finds polygon shapes axis least penetration -static float FindAxisLeastPenetration(int *faceIndex, PhysicsShape shapeA, PhysicsShape shapeB) -{ - float bestDistance = -PHYSAC_FLT_MAX; - int bestIndex = 0; - - PhysicsVertexData dataA = shapeA.vertexData; - //PhysicsVertexData dataB = shapeB.vertexData; - - for (unsigned int i = 0; i < dataA.vertexCount; i++) - { - // Retrieve a face normal from A shape - Vector2 normal = dataA.normals[i]; - Vector2 transNormal = MathMatVector2Product(shapeA.transform, normal); - - // Transform face normal into B shape's model space - Matrix2x2 buT = MathMatTranspose(shapeB.transform); - normal = MathMatVector2Product(buT, transNormal); - - // Retrieve support point from B shape along -n - Vector2 support = GetSupport(shapeB, CLITERAL(Vector2){ -normal.x, -normal.y }); - - // Retrieve vertex on face from A shape, transform into B shape's model space - Vector2 vertex = dataA.positions[i]; - vertex = MathMatVector2Product(shapeA.transform, vertex); - vertex = MathVector2Add(vertex, shapeA.body->position); - vertex = MathVector2Subtract(vertex, shapeB.body->position); - vertex = MathMatVector2Product(buT, vertex); - - // Compute penetration distance in B shape's model space - float distance = MathVector2DotProduct(normal, MathVector2Subtract(support, vertex)); - - // Store greatest distance - if (distance > bestDistance) - { - bestDistance = distance; - bestIndex = i; - } - } - - *faceIndex = bestIndex; - return bestDistance; -} - -// Finds two polygon shapes incident face -static void FindIncidentFace(Vector2 *v0, Vector2 *v1, PhysicsShape ref, PhysicsShape inc, int index) -{ - PhysicsVertexData refData = ref.vertexData; - PhysicsVertexData incData = inc.vertexData; - - Vector2 referenceNormal = refData.normals[index]; - - // Calculate normal in incident's frame of reference - referenceNormal = MathMatVector2Product(ref.transform, referenceNormal); // To world space - referenceNormal = MathMatVector2Product(MathMatTranspose(inc.transform), referenceNormal); // To incident's model space - - // Find most anti-normal face on polygon - int incidentFace = 0; - float minDot = PHYSAC_FLT_MAX; - - for (unsigned int i = 0; i < incData.vertexCount; i++) - { - float dot = MathVector2DotProduct(referenceNormal, incData.normals[i]); - - if (dot < minDot) - { - minDot = dot; - incidentFace = i; - } - } - - // Assign face vertices for incident face - *v0 = MathMatVector2Product(inc.transform, incData.positions[incidentFace]); - *v0 = MathVector2Add(*v0, inc.body->position); - incidentFace = (((incidentFace + 1) < (int)incData.vertexCount) ? (incidentFace + 1) : 0); - *v1 = MathMatVector2Product(inc.transform, incData.positions[incidentFace]); - *v1 = MathVector2Add(*v1, inc.body->position); -} - -// Returns clipping value based on a normal and two faces -static int MathVector2Clip(Vector2 normal, Vector2 *faceA, Vector2 *faceB, float clip) -{ - int sp = 0; - Vector2 out[2] = { *faceA, *faceB }; - - // Retrieve distances from each endpoint to the line - float distanceA = MathVector2DotProduct(normal, *faceA) - clip; - float distanceB = MathVector2DotProduct(normal, *faceB) - clip; - - // If negative (behind plane) - if (distanceA <= 0.0f) out[sp++] = *faceA; - if (distanceB <= 0.0f) out[sp++] = *faceB; - - // If the points are on different sides of the plane - if ((distanceA*distanceB) < 0.0f) - { - // Push intersection point - float alpha = distanceA/(distanceA - distanceB); - out[sp] = *faceA; - Vector2 delta = MathVector2Subtract(*faceB, *faceA); - delta.x *= alpha; - delta.y *= alpha; - out[sp] = MathVector2Add(out[sp], delta); - sp++; - } - - // Assign the new converted values - *faceA = out[0]; - *faceB = out[1]; - - return sp; -} - -// Returns the barycenter of a triangle given by 3 points -static Vector2 MathTriangleBarycenter(Vector2 v1, Vector2 v2, Vector2 v3) -{ - Vector2 result = { 0.0f, 0.0f }; - - result.x = (v1.x + v2.x + v3.x)/3; - result.y = (v1.y + v2.y + v3.y)/3; - - return result; -} - -// Returns the cross product of a vector and a value -static inline Vector2 MathVector2Product(Vector2 vector, float value) -{ - Vector2 result = { -value*vector.y, value*vector.x }; - return result; -} - -// Returns the cross product of two vectors -static inline float MathVector2CrossProduct(Vector2 v1, Vector2 v2) -{ - return (v1.x*v2.y - v1.y*v2.x); -} - -// Returns the len square root of a vector -static inline float MathVector2SqrLen(Vector2 vector) -{ - return (vector.x*vector.x + vector.y*vector.y); -} - -// Returns the dot product of two vectors -static inline float MathVector2DotProduct(Vector2 v1, Vector2 v2) -{ - return (v1.x*v2.x + v1.y*v2.y); -} - -// Returns the square root of distance between two vectors -static inline float MathVector2SqrDistance(Vector2 v1, Vector2 v2) -{ - Vector2 dir = MathVector2Subtract(v1, v2); - return MathVector2DotProduct(dir, dir); -} - -// Returns the normalized values of a vector -static void MathVector2Normalize(Vector2 *vector) -{ - float length, ilength; - - Vector2 aux = *vector; - length = sqrtf(aux.x*aux.x + aux.y*aux.y); - - if (length == 0) length = 1.0f; - - ilength = 1.0f/length; - - vector->x *= ilength; - vector->y *= ilength; -} - -// Returns the sum of two given vectors -static inline Vector2 MathVector2Add(Vector2 v1, Vector2 v2) -{ - Vector2 result = { v1.x + v2.x, v1.y + v2.y }; - return result; -} - -// Returns the subtract of two given vectors -static inline Vector2 MathVector2Subtract(Vector2 v1, Vector2 v2) -{ - Vector2 result = { v1.x - v2.x, v1.y - v2.y }; - return result; -} - -// Creates a matrix 2x2 from a given radians value -static Matrix2x2 MathMatFromRadians(float radians) -{ - float cos = cosf(radians); - float sin = sinf(radians); - - Matrix2x2 result = { cos, -sin, sin, cos }; - return result; -} - -// Returns the transpose of a given matrix 2x2 -static inline Matrix2x2 MathMatTranspose(Matrix2x2 matrix) -{ - Matrix2x2 result = { matrix.m00, matrix.m10, matrix.m01, matrix.m11 }; - return result; -} - -// Multiplies a vector by a matrix 2x2 -static inline Vector2 MathMatVector2Product(Matrix2x2 matrix, Vector2 vector) -{ - Vector2 result = { matrix.m00*vector.x + matrix.m01*vector.y, matrix.m10*vector.x + matrix.m11*vector.y }; - return result; -} - -#endif // PHYSAC_IMPLEMENTATION