Selaa lähdekoodia

WIP rcamera redesign vector (#2563)

* core functionality CAMERA_FREE

* fix example

* add remaining camera modes

* add view bobbing

* view bobbing

* catch curser in SetCameraMode

* adjust examples

* fix compilation on linux

* fix example text_draw_3d

* actually fix text_draw_3d

* Updated camera API

* Improve Vector3RotateByAxisAngle() function

* remove camera.mode dependency from low-level functions

* remove camera.mode from struct

* fixes after rebase

* adjust examples for new UpdateCamera function

* adjust example models_loading_m3d

---------

Co-authored-by: Ray <[email protected]>
Crydsch Cube 2 vuotta sitten
vanhempi
commit
73989a4981

+ 83 - 11
examples/core/core_3d_camera_first_person.c

@@ -12,6 +12,7 @@
 ********************************************************************************************/
 
 #include "raylib.h"
+#include "rcamera.h"
 
 #define MAX_COLUMNS 20
 
@@ -29,11 +30,14 @@ int main(void)
 
     // Define the camera to look into our 3d world (position, target, up vector)
     Camera camera = { 0 };
-    camera.position = (Vector3){ 4.0f, 2.0f, 4.0f };
-    camera.target = (Vector3){ 0.0f, 1.8f, 0.0f };
+    camera.position = (Vector3){ 0.0f, 2.0f, 4.0f };
+    camera.target = (Vector3){ 0.0f, 2.0f, 0.0f };
     camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
     camera.fovy = 60.0f;
     camera.projection = CAMERA_PERSPECTIVE;
+    camera.swingCounter = 1; // Enable view bobbing
+    
+    int cameraMode = CAMERA_FIRST_PERSON;
 
     // Generates some random columns
     float heights[MAX_COLUMNS] = { 0 };
@@ -47,8 +51,7 @@ int main(void)
         colors[i] = (Color){ GetRandomValue(20, 255), GetRandomValue(10, 55), 30, 255 };
     }
 
-    SetCameraMode(camera, CAMERA_FIRST_PERSON); // Set a first person camera mode
-
+    DisableCursor();                            // Catch cursor
     SetTargetFPS(60);                           // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -57,7 +60,51 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        // Switch camera mode
+        if (IsKeyPressed(KEY_ONE)) {
+            cameraMode = CAMERA_FREE;
+            camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Reset roll
+        }
+        if (IsKeyPressed(KEY_TWO)) {
+            cameraMode = CAMERA_FIRST_PERSON;
+            camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Reset roll
+        }
+        if (IsKeyPressed(KEY_THREE)) {
+            cameraMode = CAMERA_THIRD_PERSON;
+            camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Reset roll
+        }
+        if (IsKeyPressed(KEY_FOUR)) {
+            cameraMode = CAMERA_ORBITAL;
+            camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Reset roll
+        }
+
+        // Switch camera projection
+        if (IsKeyPressed(KEY_P)) {
+            if (camera.projection == CAMERA_PERSPECTIVE) {
+                // Create isometric view
+                cameraMode = CAMERA_THIRD_PERSON;
+                // Note: The target distance is related to the render distance in the orthographic projection
+                camera.position = (Vector3){ 0.0f, 2.0f, -100.0f };
+                camera.target = (Vector3){ 0.0f, 2.0f, 0.0f };
+                camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
+                camera.projection = CAMERA_ORTHOGRAPHIC;
+                camera.fovy = 20.0f; // near plane width in CAMERA_ORTHOGRAPHIC
+                CameraYaw(&camera, -135 * DEG2RAD, true);
+                CameraPitch(&camera, -45 * DEG2RAD, true, true, false);
+            }
+            else if (camera.projection == CAMERA_ORTHOGRAPHIC)
+            {
+                // Reset to default view
+                cameraMode = CAMERA_THIRD_PERSON;
+                camera.position = (Vector3){ 0.0f, 2.0f, 10.0f };
+                camera.target = (Vector3){ 0.0f, 2.0f, 0.0f };
+                camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
+                camera.projection = CAMERA_PERSPECTIVE;
+                camera.fovy = 60.0f;
+            }
+        }
+
+        UpdateCamera(&camera, cameraMode);                  // Update camera
         //----------------------------------------------------------------------------------
 
         // Draw
@@ -80,14 +127,39 @@ int main(void)
                     DrawCubeWires(positions[i], 2.0f, heights[i], 2.0f, MAROON);
                 }
 
-            EndMode3D();
+                // Draw player cube
+                if (cameraMode == CAMERA_THIRD_PERSON)
+                {
+                    DrawCube(camera.target, 0.5f, 0.5f, 0.5f, PURPLE);
+                    DrawCubeWires(camera.target, 0.5f, 0.5f, 0.5f, DARKPURPLE);
+                }
 
-            DrawRectangle( 10, 10, 220, 70, Fade(SKYBLUE, 0.5f));
-            DrawRectangleLines( 10, 10, 220, 70, BLUE);
+            EndMode3D();
 
-            DrawText("First person camera default controls:", 20, 20, 10, BLACK);
-            DrawText("- Move with keys: W, A, S, D", 40, 40, 10, DARKGRAY);
-            DrawText("- Mouse move to look around", 40, 60, 10, DARKGRAY);
+            // Draw info boxes
+            DrawRectangle(5, 5, 330, 100, Fade(SKYBLUE, 0.5f));
+            DrawRectangleLines(5, 5, 330, 100, BLUE);
+
+            DrawText("Camera controls:", 15, 15, 10, BLACK);
+            DrawText("- Move keys: W, A, S, D, Space, Left-Ctrl", 15, 30, 10, BLACK);
+            DrawText("- Look around: arrow keys or mouse", 15, 45, 10, BLACK);
+            DrawText("- Camera mode keys: 1, 2, 3, 4", 15, 60, 10, BLACK);
+            DrawText("- Zoom keys: num-plus, num-minus or mouse scroll", 15, 75, 10, BLACK);
+            DrawText("- Camera projection key: P", 15, 90, 10, BLACK);
+
+            DrawRectangle(600, 5, 195, 100, Fade(SKYBLUE, 0.5f));
+            DrawRectangleLines(600, 5, 195, 100, BLUE);
+
+            DrawText("Camera status:", 610, 15, 10, BLACK);
+            DrawText(TextFormat("- Mode: %s", (cameraMode == CAMERA_FREE) ? "FREE" :
+                                              (cameraMode == CAMERA_FIRST_PERSON) ? "FIRST_PERSON" :
+                                              (cameraMode == CAMERA_THIRD_PERSON) ? "THIRD_PERSON" :
+                                              (cameraMode == CAMERA_ORBITAL) ? "ORBITAL" : "CUSTOM"), 610, 30, 10, BLACK);
+            DrawText(TextFormat("- Projection: %s", (camera.projection == CAMERA_PERSPECTIVE) ? "PERSPECTIVE" :
+                                                    (camera.projection == CAMERA_ORTHOGRAPHIC) ? "ORTHOGRAPHIC" : "CUSTOM"), 610, 45, 10, BLACK);
+            DrawText(TextFormat("- Position: (%06.3f, %06.3f, %06.3f)", camera.position.x, camera.position.y, camera.position.z), 610, 60, 10, BLACK);
+            DrawText(TextFormat("- Target: (%06.3f, %06.3f, %06.3f)", camera.target.x, camera.target.y, camera.target.z), 610, 75, 10, BLACK);
+            DrawText(TextFormat("- Up: (%06.3f, %06.3f, %06.3f)", camera.up.x, camera.up.y, camera.up.z), 610, 90, 10, BLACK);
 
         EndDrawing();
         //----------------------------------------------------------------------------------

+ 1 - 3
examples/core/core_3d_camera_free.c

@@ -35,8 +35,6 @@ int main(void)
 
     Vector3 cubePosition = { 0.0f, 0.0f, 0.0f };
 
-    SetCameraMode(camera, CAMERA_FREE); // Set a free camera mode
-
     SetTargetFPS(60);                   // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -45,7 +43,7 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        UpdateCamera(&camera, CAMERA_FREE);
 
         if (IsKeyDown('Z')) camera.target = (Vector3){ 0.0f, 0.0f, 0.0f };
         //----------------------------------------------------------------------------------

+ 12 - 3
examples/core/core_3d_picking.c

@@ -40,7 +40,7 @@ int main(void)
 
     RayCollision collision = { 0 };
 
-    SetCameraMode(camera, CAMERA_FREE); // Set a free camera mode
+    EnableCursor();                     // Disable camera controls
 
     SetTargetFPS(60);                   // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
@@ -50,7 +50,14 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        if (IsCursorHidden()) UpdateCamera(&camera, CAMERA_FIRST_PERSON);          // Update camera
+
+        // Toggle camera controls
+        if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT))
+        {
+            if (IsCursorHidden()) EnableCursor();
+            else DisableCursor();
+        }
 
         if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT))
         {
@@ -93,10 +100,12 @@ int main(void)
 
             EndMode3D();
 
-            DrawText("Try selecting the box with mouse!", 240, 10, 20, DARKGRAY);
+            DrawText("Try clicking on the box with your mouse!", 240, 10, 20, DARKGRAY);
 
             if (collision.hit) DrawText("BOX SELECTED", (screenWidth - MeasureText("BOX SELECTED", 30)) / 2, (int)(screenHeight * 0.1f), 30, GREEN);
 
+            DrawText("Right click mouse to toggle camera controls", 10, 430, 10, GRAY);
+
             DrawFPS(10, 10);
 
         EndDrawing();

+ 3 - 3
examples/core/core_vr_simulator.c

@@ -96,11 +96,11 @@ int main(void)
     camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };          // Camera up vector
     camera.fovy = 60.0f;                                // Camera field-of-view Y
     camera.projection = CAMERA_PERSPECTIVE;             // Camera type
+    camera.swingCounter = 1;                            // Enable view bobbing
 
     Vector3 cubePosition = { 0.0f, 0.0f, 0.0f };
 
-    SetCameraMode(camera, CAMERA_FIRST_PERSON);         // Set first person camera mode
-
+    DisableCursor();                    // Catch cursor
     SetTargetFPS(90);                   // Set our game to run at 90 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -109,7 +109,7 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        UpdateCamera(&camera, CAMERA_FIRST_PERSON);
         //----------------------------------------------------------------------------------
 
         // Draw

+ 3 - 4
examples/core/core_world_screen.c

@@ -23,7 +23,7 @@ int main(void)
     const int screenWidth = 800;
     const int screenHeight = 450;
 
-    InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera free");
+    InitWindow(screenWidth, screenHeight, "raylib [core] example - core world screen");
 
     // Define the camera to look into our 3d world
     Camera camera = { 0 };
@@ -36,8 +36,7 @@ int main(void)
     Vector3 cubePosition = { 0.0f, 0.0f, 0.0f };
     Vector2 cubeScreenPosition = { 0.0f, 0.0f };
 
-    SetCameraMode(camera, CAMERA_FREE); // Set a free camera mode
-
+    DisableCursor();                            // Catch cursor
     SetTargetFPS(60);                   // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -46,7 +45,7 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        UpdateCamera(&camera, CAMERA_THIRD_PERSON);
 
         // Calculate cube screen space position (with a little offset to be in top)
         cubeScreenPosition = GetWorldToScreen((Vector3){cubePosition.x, cubePosition.y + 2.5f, cubePosition.z}, camera);

+ 2 - 3
examples/models/models_animation.c

@@ -54,8 +54,7 @@ int main(void)
     ModelAnimation *anims = LoadModelAnimations("resources/models/iqm/guyanim.iqm", &animsCount);
     int animFrameCounter = 0;
 
-    SetCameraMode(camera, CAMERA_FREE); // Set free camera mode
-
+    DisableCursor();                    // Catch cursor
     SetTargetFPS(60);                   // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -64,7 +63,7 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        UpdateCamera(&camera, CAMERA_FIRST_PERSON);
 
         // Play animation when spacebar is held down
         if (IsKeyDown(KEY_SPACE))

+ 3 - 3
examples/models/models_billboard.c

@@ -48,14 +48,13 @@ int main(void)
     // Here we choose to rotate around the image center
     // NOTE: (-1, 1) is the range where origin.x, origin.y is inside the texture
     Vector2 rotateOrigin = { 0.0f };
-    SetCameraMode(camera, CAMERA_ORBITAL);  // Set an orbital camera mode
 
     // Distance is needed for the correct billboard draw order
     // Larger distance (further away from the camera) should be drawn prior to smaller distance.
     float distanceStatic;
     float distanceRotating;
-
     float rotation = 0.0f;
+
     SetTargetFPS(60);                       // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -64,7 +63,8 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        UpdateCamera(&camera, CAMERA_ORBITAL);
+
         rotation += 0.4f;
         distanceStatic = Vector3Distance(camera.position, billPositionStatic);
         distanceRotating = Vector3Distance(camera.position, billPositionRotating);

+ 2 - 3
examples/models/models_cubicmap.c

@@ -42,8 +42,7 @@ int main(void)
 
     UnloadImage(image);     // Unload cubesmap image from RAM, already uploaded to VRAM
 
-    SetCameraMode(camera, CAMERA_ORBITAL);  // Set an orbital camera mode
-
+    DisableCursor();                        // Catch cursor
     SetTargetFPS(60);                       // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -52,7 +51,7 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        UpdateCamera(&camera, CAMERA_ORBITAL);
         //----------------------------------------------------------------------------------
 
         // Draw

+ 2 - 3
examples/models/models_first_person_maze.c

@@ -45,8 +45,7 @@ int main(void)
 
     Vector3 mapPosition = { -16.0f, 0.0f, -8.0f };  // Set model position
 
-    SetCameraMode(camera, CAMERA_FIRST_PERSON);     // Set camera mode
-
+    DisableCursor();                // Catch cursor
     SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -57,7 +56,7 @@ int main(void)
         //----------------------------------------------------------------------------------
         Vector3 oldCamPos = camera.position;    // Store old camera position
 
-        UpdateCamera(&camera);
+        UpdateCamera(&camera, CAMERA_FIRST_PERSON);
 
         // Check player collision (we simplify to 2D collision detection)
         Vector2 playerPos = { camera.position.x, camera.position.z };

+ 2 - 3
examples/models/models_heightmap.c

@@ -39,8 +39,7 @@ int main(void)
 
     UnloadImage(image);                     // Unload heightmap image from RAM, already uploaded to VRAM
 
-    SetCameraMode(camera, CAMERA_ORBITAL);  // Set an orbital camera mode
-
+    DisableCursor();                        // Catch cursor
     SetTargetFPS(60);                       // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -49,7 +48,7 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        UpdateCamera(&camera, CAMERA_ORBITAL);
         //----------------------------------------------------------------------------------
 
         // Draw

+ 2 - 3
examples/models/models_loading.c

@@ -57,10 +57,9 @@ int main(void)
     // NOTE: bounds are calculated from the original size of the model,
     // if model is scaled on drawing, bounds must be also scaled
 
-    SetCameraMode(camera, CAMERA_FREE);     // Set a free camera mode
-
     bool selected = false;          // Selected object flag
 
+    DisableCursor();                // Catch cursor
     SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -69,7 +68,7 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        UpdateCamera(&camera, CAMERA_FIRST_PERSON);
 
         // Load new models/textures on drag&drop
         if (IsFileDropped())

+ 1 - 5
examples/models/models_loading_gltf.c

@@ -51,8 +51,6 @@ int main(void)
 
     Vector3 position = { 0.0f, 0.0f, 0.0f };    // Set model position
 
-    SetCameraMode(camera, CAMERA_FREE);     // Set free camera mode
-
     SetTargetFPS(60);                       // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -61,6 +59,7 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
+        UpdateCamera(&camera, CAMERA_THIRD_PERSON);
         // Select current animation
         if (IsKeyPressed(KEY_UP)) animIndex = (animIndex + 1)%animsCount;
         else if (IsKeyPressed(KEY_DOWN)) animIndex = (animIndex + animsCount - 1)%animsCount;
@@ -69,9 +68,6 @@ int main(void)
         ModelAnimation anim = modelAnimations[animIndex];
         animCurrentFrame = (animCurrentFrame + 1)%anim.frameCount;
         UpdateModelAnimation(model, anim, animCurrentFrame);
-        
-        // Update camera
-        UpdateCamera(&camera);
         //----------------------------------------------------------------------------------
 
         // Draw

+ 2 - 3
examples/models/models_loading_m3d.c

@@ -53,8 +53,7 @@ int main(void)
     int animFrameCounter = 0, animId = 0;
     ModelAnimation *anims = LoadModelAnimations(modelFileName, &animsCount); // Load skeletal animation data
 
-    SetCameraMode(camera, CAMERA_FREE);     // Set free camera mode
-
+    DisableCursor();                        // Catch cursor
     SetTargetFPS(60);                       // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -63,7 +62,7 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        UpdateCamera(&camera, CAMERA_FIRST_PERSON);
 
         if (animsCount)
         {

+ 2 - 3
examples/models/models_loading_vox.c

@@ -69,8 +69,7 @@ int main(void)
 
     int currentModel = 0;
 
-    SetCameraMode(camera, CAMERA_ORBITAL);  // Set a orbital camera mode
-
+    DisableCursor();                            // Catch cursor
     SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -79,7 +78,7 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        UpdateCamera(&camera, CAMERA_ORBITAL);
 
         // Cycle between models on mouse click
         if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) currentModel = (currentModel + 1)%MAX_VOX_FILES;

+ 2 - 3
examples/models/models_mesh_generation.c

@@ -68,8 +68,7 @@ int main(void)
 
     int currentModel = 0;
 
-    SetCameraMode(camera, CAMERA_ORBITAL);  // Set a orbital camera mode
-
+    DisableCursor();                // Catch cursor
     SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -78,7 +77,7 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        UpdateCamera(&camera, CAMERA_ORBITAL);
 
         if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT))
         {

+ 10 - 4
examples/models/models_mesh_picking.c

@@ -64,8 +64,7 @@ int main(void)
     Vector3 sp = (Vector3){ -30.0f, 5.0f, 5.0f };
     float sr = 4.0f;
 
-    SetCameraMode(camera, CAMERA_FREE); // Set a free camera mode
-
+    EnableCursor();                     // Disable camera controls
     SetTargetFPS(60);                   // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
     // Main game loop
@@ -73,7 +72,14 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        if (IsCursorHidden()) UpdateCamera(&camera, CAMERA_FIRST_PERSON);          // Update camera
+
+        // Toggle camera controls
+        if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT))
+        {
+            if (IsCursorHidden()) EnableCursor();
+            else DisableCursor();
+        }
 
         // Display information about closest hit
         RayCollision collision = { 0 };
@@ -219,7 +225,7 @@ int main(void)
                     DrawText(TextFormat("Barycenter: %3.2f %3.2f %3.2f",  bary.x, bary.y, bary.z), 10, ypos + 45, 10, BLACK);
             }
 
-            DrawText("Use Mouse to Move Camera", 10, 430, 10, GRAY);
+            DrawText("Right click mouse to toggle camera controls", 10, 430, 10, GRAY);
 
             DrawText("(c) Turret 3D model by Alberto Cano", screenWidth - 200, screenHeight - 20, 10, GRAY);
 

+ 2 - 3
examples/models/models_rlgl_solar_system.c

@@ -49,8 +49,6 @@ int main(void)
     camera.fovy = 45.0f;
     camera.projection = CAMERA_PERSPECTIVE;
 
-    SetCameraMode(camera, CAMERA_FREE);
-
     float rotationSpeed = 0.2f;         // General system rotation speed
 
     float earthRotation = 0.0f;         // Rotation of earth around itself (days) in degrees
@@ -58,6 +56,7 @@ int main(void)
     float moonRotation = 0.0f;          // Rotation of moon around itself
     float moonOrbitRotation = 0.0f;     // Rotation of moon around earth in degrees
 
+    DisableCursor();                    // Catch cursor
     SetTargetFPS(60);                   // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -66,7 +65,7 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        UpdateCamera(&camera, CAMERA_ORBITAL);
 
         earthRotation += (5.0f*rotationSpeed);
         earthOrbitRotation += (365/360.0f*(5.0f*rotationSpeed)*rotationSpeed);

+ 2 - 3
examples/models/models_skybox.c

@@ -87,8 +87,7 @@ int main(void)
         UnloadImage(img);
     }
 
-    SetCameraMode(camera, CAMERA_FIRST_PERSON);  // Set a first person camera mode
-
+    DisableCursor();                        // Catch cursor
     SetTargetFPS(60);                       // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -97,7 +96,7 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        UpdateCamera(&camera, CAMERA_FIRST_PERSON);
 
         // Load new cubemap texture on drag&drop
         if (IsFileDropped())

+ 2 - 3
examples/shaders/shaders_basic_lighting.c

@@ -80,8 +80,7 @@ int main(void)
     lights[2] = CreateLight(LIGHT_POINT, (Vector3){ -2, 1, 2 }, Vector3Zero(), GREEN, shader);
     lights[3] = CreateLight(LIGHT_POINT, (Vector3){ 2, 1, -2 }, Vector3Zero(), BLUE, shader);
 
-    SetCameraMode(camera, CAMERA_ORBITAL);  // Set an orbital camera mode
-
+    DisableCursor();                        // Catch cursor
     SetTargetFPS(60);                       // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -90,7 +89,7 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        UpdateCamera(&camera, CAMERA_ORBITAL);
 
         // Update the shader with the camera view vector (points towards { 0.0f, 0.0f, 0.0f })
         float cameraPos[3] = { camera.position.x, camera.position.y, camera.position.z };

+ 2 - 4
examples/shaders/shaders_custom_uniform.c

@@ -67,9 +67,7 @@ int main(void)
     // Create a RenderTexture2D to be used for render to texture
     RenderTexture2D target = LoadRenderTexture(screenWidth, screenHeight);
 
-    // Setup orbital camera
-    SetCameraMode(camera, CAMERA_ORBITAL);  // Set an orbital camera mode
-
+    DisableCursor();                    // Catch cursor
     SetTargetFPS(60);                   // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -78,7 +76,7 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        UpdateCamera(&camera, CAMERA_ORBITAL);
         
         Vector2 mousePosition = GetMousePosition();
 

+ 2 - 3
examples/shaders/shaders_fog.c

@@ -84,8 +84,7 @@ int main(void)
     // Using just 1 point lights
     CreateLight(LIGHT_POINT, (Vector3){ 0, 2, 6 }, Vector3Zero(), WHITE, shader);
 
-    SetCameraMode(camera, CAMERA_ORBITAL);  // Set an orbital camera mode
-
+    DisableCursor();                        // Catch cursor
     SetTargetFPS(60);                       // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -94,7 +93,7 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        UpdateCamera(&camera, CAMERA_ORBITAL);
 
         if (IsKeyDown(KEY_UP))
         {

+ 2 - 4
examples/shaders/shaders_mesh_instancing.c

@@ -94,9 +94,7 @@ int main(void)
     Material matDefault = LoadMaterialDefault();
     matDefault.maps[MATERIAL_MAP_DIFFUSE].color = BLUE;
 
-    // Set an orbital camera mode
-    SetCameraMode(camera, CAMERA_ORBITAL);  
-
+    DisableCursor();                       // Catch cursor
     SetTargetFPS(60);                      // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -105,7 +103,7 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        UpdateCamera(&camera, CAMERA_ORBITAL);
 
         // Update the light shader with the camera view position
         float cameraPos[3] = { camera.position.x, camera.position.y, camera.position.z };

+ 2 - 3
examples/shaders/shaders_model_shader.c

@@ -60,8 +60,7 @@ int main(void)
 
     Vector3 position = { 0.0f, 0.0f, 0.0f };    // Set model position
 
-    SetCameraMode(camera, CAMERA_FREE);         // Set an orbital camera mode
-
+    DisableCursor();                            // Catch cursor
     SetTargetFPS(60);                           // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -70,7 +69,7 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        UpdateCamera(&camera, CAMERA_FIRST_PERSON);
         //----------------------------------------------------------------------------------
 
         // Draw

+ 2 - 4
examples/shaders/shaders_postprocessing.c

@@ -107,9 +107,7 @@ int main(void)
     // Create a RenderTexture2D to be used for render to texture
     RenderTexture2D target = LoadRenderTexture(screenWidth, screenHeight);
 
-    // Setup orbital camera
-    SetCameraMode(camera, CAMERA_ORBITAL);  // Set an orbital camera mode
-
+    DisableCursor();                        // Catch cursor
     SetTargetFPS(60);                       // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -118,7 +116,7 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        UpdateCamera(&camera, CAMERA_ORBITAL);
 
         if (IsKeyPressed(KEY_RIGHT)) currentShader++;
         else if (IsKeyPressed(KEY_LEFT)) currentShader--;

+ 2 - 3
examples/shaders/shaders_raymarching.c

@@ -41,8 +41,6 @@ int main(void)
     camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };          // Camera up vector (rotation towards target)
     camera.fovy = 65.0f;                                // Camera field-of-view Y
 
-    SetCameraMode(camera, CAMERA_FREE);                 // Set camera mode
-
     // Load raymarching shader
     // NOTE: Defining 0 (NULL) for vertex shader forces usage of internal default vertex shader
     Shader shader = LoadShader(0, TextFormat("resources/shaders/glsl%i/raymarching.fs", GLSL_VERSION));
@@ -58,6 +56,7 @@ int main(void)
 
     float runTime = 0.0f;
 
+    DisableCursor();                            // Catch cursor
     SetTargetFPS(60);                       // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -66,7 +65,7 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        UpdateCamera(&camera, CAMERA_FIRST_PERSON);
 
         float cameraPos[3] = { camera.position.x, camera.position.y, camera.position.z };
         float cameraTarget[3] = { camera.target.x, camera.target.y, camera.target.z };

+ 2 - 1
examples/shaders/shaders_simple_mask.c

@@ -85,6 +85,7 @@ int main(void)
     int framesCounter = 0;
     Vector3 rotation = { 0 };       // Model rotation angles
 
+    DisableCursor();                            // Catch cursor
     SetTargetFPS(60);               // Set  to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -93,7 +94,7 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        UpdateCamera(&camera, CAMERA_FIRST_PERSON);
         
         framesCounter++;
         rotation.x += 0.01f;

+ 5 - 4
examples/text/text_draw_3d.c

@@ -98,11 +98,12 @@ int main(void)
     camera.fovy = 45.0f;                                    // Camera field-of-view Y
     camera.projection = CAMERA_PERSPECTIVE;                 // Camera mode type
 
-    SetCameraMode(camera, CAMERA_ORBITAL);
+    int camera_mode = CAMERA_ORBITAL;
 
     Vector3 cubePosition = { 0.0f, 1.0f, 0.0f };
     Vector3 cubeSize = { 2.0f, 2.0f, 2.0f };
 
+    DisableCursor();                    // Catch cursor
     SetTargetFPS(60);                   // Set our game to run at 60 frames-per-second
 
     // Use the default font
@@ -141,7 +142,7 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);
+        UpdateCamera(&camera, camera_mode);
         
         // Handle font files dropped
         if (IsFileDropped())
@@ -181,12 +182,12 @@ int main(void)
             if (spin)
             {
                 camera.position = (Vector3){ -10.0f, 15.0f, -10.0f };   // Camera position
-                SetCameraMode(camera, CAMERA_ORBITAL);
+                camera_mode = CAMERA_ORBITAL;
             }
             else
             {
                 camera.position = (Vector3){ 10.0f, 10.0f, -10.0f };   // Camera position
-                SetCameraMode(camera, CAMERA_FREE);
+                camera_mode = CAMERA_FREE;
             }
         }
 

+ 1 - 7
src/raylib.h

@@ -1156,13 +1156,7 @@ RLAPI float GetGesturePinchAngle(void);                 // Get gesture pinch ang
 //------------------------------------------------------------------------------------
 // Camera System Functions (Module: rcamera)
 //------------------------------------------------------------------------------------
-RLAPI void SetCameraMode(Camera camera, int mode);      // Set camera mode (multiple camera modes available)
-RLAPI void UpdateCamera(Camera *camera);                // Update camera position for selected mode
-
-RLAPI void SetCameraPanControl(int keyPan);             // Set camera pan key to combine with mouse movement (free camera)
-RLAPI void SetCameraAltControl(int keyAlt);             // Set camera alt key to combine with mouse movement (free camera)
-RLAPI void SetCameraSmoothZoomControl(int keySmoothZoom); // Set camera smooth zoom key to combine with mouse (free camera)
-RLAPI void SetCameraMoveControls(int keyFront, int keyBack, int keyRight, int keyLeft, int keyUp, int keyDown); // Set camera move controls (1st person and 3rd person cameras)
+RLAPI void UpdateCamera(Camera3D *camera, int mode);              // Update camera position for selected mode
 
 //------------------------------------------------------------------------------------
 // Basic Shapes Drawing Functions (Module: shapes)

+ 283 - 387
src/rcamera.h

@@ -2,8 +2,6 @@
 *
 *   rcamera - Basic camera system for multiple camera modes
 *
-*   NOTE: Memory footprint of this library is aproximately 52 bytes (global variables)
-*
 *   CONFIGURATION:
 *
 *   #define CAMERA_IMPLEMENTATION
@@ -17,6 +15,7 @@
 *
 *   CONTRIBUTORS:
 *       Ramon Santamaria:   Supervision, review, update and maintenance
+*       Christoph Wagner:   Redesign (2022)
 *       Marc Palau:         Initial implementation (2014)
 *
 *
@@ -44,15 +43,26 @@
 #ifndef RCAMERA_H
 #define RCAMERA_H
 
+// The only dependency // TODO review standalone mode
+#include "raymath.h"
+
 //----------------------------------------------------------------------------------
 // Defines and Macros
 //----------------------------------------------------------------------------------
 //...
+#if defined(CAMERA_STANDALONE)
+#define CAMERA_CULL_DISTANCE_NEAR 0.01
+#define CAMERA_CULL_DISTANCE_FAR 1000.0
+#else
+#define CAMERA_CULL_DISTANCE_NEAR  RL_CULL_DISTANCE_NEAR
+#define CAMERA_CULL_DISTANCE_FAR  RL_CULL_DISTANCE_FAR
+#endif
 
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
 // NOTE: Below types are required for CAMERA_STANDALONE usage
 //----------------------------------------------------------------------------------
+// TODO review
 #if defined(CAMERA_STANDALONE)
     // Vector2 type
     typedef struct Vector2 {
@@ -76,8 +86,6 @@
         int projection;         // Camera type, defines projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC
     } Camera3D;
 
-    typedef Camera3D Camera;    // Camera type fallback, defaults to Camera3D
-
     // Camera system modes
     typedef enum {
         CAMERA_CUSTOM = 0,
@@ -97,7 +105,7 @@
 //----------------------------------------------------------------------------------
 // Global Variables Definition
 //----------------------------------------------------------------------------------
-//...
+
 
 //----------------------------------------------------------------------------------
 // Module Functions Declaration
@@ -107,17 +115,19 @@
 extern "C" {            // Prevents name mangling of functions
 #endif
 
-#if defined(CAMERA_STANDALONE)
-void SetCameraMode(Camera camera, int mode);                // Set camera mode (multiple camera modes available)
-void UpdateCamera(Camera *camera);                          // Update camera position for selected mode
-
-void SetCameraPanControl(int keyPan);                       // Set camera pan key to combine with mouse movement (free camera)
-void SetCameraAltControl(int keyAlt);                       // Set camera alt key to combine with mouse movement (free camera)
-void SetCameraSmoothZoomControl(int szoomKey);              // Set camera smooth zoom key to combine with mouse (free camera)
-void SetCameraMoveControls(int keyFront, int keyBack,
-                           int keyRight, int keyLeft,
-                           int keyUp, int keyDown);         // Set camera move controls (1st person and 3rd person cameras)
-#endif
+Vector3 GetCameraForward(Camera3D* camera);
+Vector3 GetCameraUp(Camera3D* camera);
+Vector3 GetCameraRight(Camera3D* camera);
+void CameraMoveForward(Camera3D* camera, float distance, bool moveInWorldPlane);
+void CameraMoveUp(Camera3D* camera, float distance);
+void CameraMoveRight(Camera3D* camera, float distance, bool moveInWorldPlane);
+void CameraZoom(Camera3D* camera, float delta);
+void CameraYaw(Camera3D* camera, float angle, bool rotateAroundTarget);
+void CameraPitch(Camera3D* camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp);
+void CameraRoll(Camera3D* camera, float angle);
+void CameraViewBobbing(Camera3D* camera);
+Matrix GetCameraViewMatrix(Camera3D* camera);
+Matrix GetCameraProjectionMatrix(Camera3D* camera, float aspect);
 
 #if defined(__cplusplus)
 }
@@ -134,424 +144,310 @@ void SetCameraMoveControls(int keyFront, int keyBack,
 
 #if defined(CAMERA_IMPLEMENTATION)
 
-#include <math.h>               // Required for: sinf(), cosf(), sqrtf()
-
 //----------------------------------------------------------------------------------
 // Defines and Macros
 //----------------------------------------------------------------------------------
-#ifndef PI
-    #define PI 3.14159265358979323846
-#endif
-#ifndef DEG2RAD
-    #define DEG2RAD (PI/180.0f)
-#endif
-#ifndef RAD2DEG
-    #define RAD2DEG (180.0f/PI)
-#endif
+
+#define CAMERA_MOVE_SPEED                               0.09f
+#define CAMERA_ROTATION_SPEED                           0.03f
 
 // Camera mouse movement sensitivity
-#define CAMERA_MOUSE_MOVE_SENSITIVITY                   0.5f    // TODO: it should be independent of framerate
+#define CAMERA_MOUSE_MOVE_SENSITIVITY                   0.003f    // TODO: it should be independant of framerate
 #define CAMERA_MOUSE_SCROLL_SENSITIVITY                 1.5f
 
-// FREE_CAMERA
-#define CAMERA_FREE_MOUSE_SENSITIVITY                   0.01f
-#define CAMERA_FREE_DISTANCE_MIN_CLAMP                  0.3f
-#define CAMERA_FREE_DISTANCE_MAX_CLAMP                  120.0f
-#define CAMERA_FREE_MIN_CLAMP                           85.0f
-#define CAMERA_FREE_MAX_CLAMP                          -85.0f
-#define CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY             0.05f
-#define CAMERA_FREE_PANNING_DIVIDER                     5.1f
-
-// ORBITAL_CAMERA
-#define CAMERA_ORBITAL_SPEED                            0.5f       // Radians per second
-
-// FIRST_PERSON
-//#define CAMERA_FIRST_PERSON_MOUSE_SENSITIVITY           0.003f
-#define CAMERA_FIRST_PERSON_FOCUS_DISTANCE              25.0f
-#define CAMERA_FIRST_PERSON_MIN_CLAMP                   89.0f
-#define CAMERA_FIRST_PERSON_MAX_CLAMP                  -89.0f
-
-// When walking, y-position of the player moves up-down at step frequency (swinging) but
-// also the body slightly tilts left-right on every step, when all the body weight is left over one foot (tilting)
-#define CAMERA_FIRST_PERSON_STEP_FREQUENCY               1.8f       // Step frequency when walking (steps per second)
-#define CAMERA_FIRST_PERSON_SWINGING_DELTA               0.03f      // Maximum up-down swinging distance when walking
-#define CAMERA_FIRST_PERSON_TILTING_DELTA                0.005f     // Maximum left-right tilting distance when walking
-
-// THIRD_PERSON
-//#define CAMERA_THIRD_PERSON_MOUSE_SENSITIVITY           0.003f
-#define CAMERA_THIRD_PERSON_DISTANCE_CLAMP              1.2f
-#define CAMERA_THIRD_PERSON_MIN_CLAMP                   5.0f
-#define CAMERA_THIRD_PERSON_MAX_CLAMP                  -85.0f
-#define CAMERA_THIRD_PERSON_OFFSET                      (Vector3){ 0.4f, 0.0f, 0.0f }
+#define CAMERA_ORBITAL_SPEED                            0.01f       // Radians per frame
+
+
+#define CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER  8.0f
+#define CAMERA_FIRST_PERSON_STEP_DIVIDER                30.0f
+#define CAMERA_FIRST_PERSON_WAVING_DIVIDER              200.0f
 
 // PLAYER (used by camera)
-#define PLAYER_MOVEMENT_SENSITIVITY                     2.0f
+#define PLAYER_MOVEMENT_SENSITIVITY                     20.0f
 
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
 //----------------------------------------------------------------------------------
-// Camera move modes (first person and third person cameras)
-typedef enum {
-    MOVE_FRONT = 0,
-    MOVE_BACK,
-    MOVE_RIGHT,
-    MOVE_LEFT,
-    MOVE_UP,
-    MOVE_DOWN
-} CameraMove;
-
-// Camera global state context data [56 bytes]
-typedef struct {
-    unsigned int mode;              // Current camera mode
-    float targetDistance;           // Camera distance from position to target
-    float playerEyesPosition;       // Player eyes position from ground (in meters)
-    Vector2 angle;                  // Camera angle in plane XZ
-
-    // Camera movement control keys
-    int moveControl[6];             // Move controls (CAMERA_FIRST_PERSON)
-    int smoothZoomControl;          // Smooth zoom control key
-    int altControl;                 // Alternative control key
-    int panControl;                 // Pan view control key
-} CameraData;
+
 
 //----------------------------------------------------------------------------------
 // Global Variables Definition
 //----------------------------------------------------------------------------------
-static CameraData CAMERA = {        // Global CAMERA state context
-    .mode = 0,
-    .targetDistance = 0,
-    .playerEyesPosition = 1.85f,
-    .angle = { 0 },
-    .moveControl = { 'W', 'S', 'D', 'A', 'E', 'Q' },
-    .smoothZoomControl = 341,       // raylib: KEY_LEFT_CONTROL
-    .altControl = 342,              // raylib: KEY_LEFT_ALT
-    .panControl = 2                 // raylib: MOUSE_BUTTON_MIDDLE
-};
+
 
 //----------------------------------------------------------------------------------
 // Module specific Functions Declaration
 //----------------------------------------------------------------------------------
-#if defined(CAMERA_STANDALONE)
-// NOTE: Camera controls depend on some raylib input functions
-static void EnableCursor() {}       // Unlock cursor
-static void DisableCursor() {}      // Lock cursor
 
-static int IsKeyDown(int key) { return 0; }
-
-static int IsMouseButtonDown(int button) { return 0;}
-static float GetMouseWheelMove() { return 0.0f; }
-static Vector2 GetMousePosition() { return (Vector2){ 0.0f, 0.0f }; }
-#endif
 
 //----------------------------------------------------------------------------------
 // Module Functions Definition
 //----------------------------------------------------------------------------------
 
-// Select camera mode (multiple camera modes available)
-void SetCameraMode(Camera camera, int mode)
+// Returns the cameras forward vector (normalized)
+Vector3 GetCameraForward(Camera3D *camera)
 {
-    Vector3 v1 = camera.position;
-    Vector3 v2 = camera.target;
+    return Vector3Normalize(Vector3Subtract(camera->target, camera->position));
+}
 
-    float dx = v2.x - v1.x;
-    float dy = v2.y - v1.y;
-    float dz = v2.z - v1.z;
+// Returns the cameras up vector (normalized)
+// Note: The up vector might not be perpendicular to the forward vector
+Vector3 GetCameraUp(Camera3D *camera)
+{
+    return Vector3Normalize(camera->up);
+}
 
-    CAMERA.targetDistance = sqrtf(dx*dx + dy*dy + dz*dz);   // Distance to target
+// Returns the cameras right vector (normalized)
+Vector3 GetCameraRight(Camera3D *camera)
+{
+    Vector3 forward = GetCameraForward(camera);
+    Vector3 up = GetCameraUp(camera);
+    return Vector3CrossProduct(forward, up);
+}
 
-    // Camera angle calculation
-    CAMERA.angle.x = atan2f(dx, dz);                        // Camera angle in plane XZ (0 aligned with Z, move positive CCW)
-    CAMERA.angle.y = atan2f(dy, sqrtf(dx*dx + dz*dz));      // Camera angle in plane XY (0 aligned with X, move positive CW)
+// Moves the camera in its forward direction
+void CameraMoveForward(Camera3D *camera, float distance, bool moveInWorldPlane)
+{
+    Vector3 forward = GetCameraForward(camera);
 
-    CAMERA.playerEyesPosition = camera.position.y;          // Init player eyes position to camera Y position
+    if (moveInWorldPlane)
+    {
+        // Project vector onto world plane
+        forward.y = 0;
+        forward = Vector3Normalize(forward);
+    }
 
-    // Lock cursor for first person and third person cameras
-    if ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)) DisableCursor();
-    else EnableCursor();
+    // Scale by distance
+    forward = Vector3Scale(forward, distance);
 
-    CAMERA.mode = mode;
+    // Move position and target
+    camera->position = Vector3Add(camera->position, forward);
+    camera->target = Vector3Add(camera->target, forward);
 }
 
-// Update camera depending on selected mode
-// NOTE: Camera controls depend on some raylib functions:
-//       System: EnableCursor(), DisableCursor()
-//       Mouse: IsMouseButtonDown(), GetMousePosition(), GetMouseWheelMove()
-//       Keys:  IsKeyDown()
-void UpdateCamera(Camera *camera)
+// Moves the camera in its up direction
+void CameraMoveUp(Camera3D *camera, float distance)
 {
-    static float swingCounter = 0.0f;    // Used for 1st person swinging movement
+    Vector3 up = GetCameraUp(camera);
+    
+    // Scale by distance
+    up = Vector3Scale(up, distance);
+
+    // Move position and target
+    camera->position = Vector3Add(camera->position, up);
+    camera->target = Vector3Add(camera->target, up);
+}
 
-    // TODO: Compute CAMERA.targetDistance and CAMERA.angle here (?)
+// Moves the camera target in its current right direction
+void CameraMoveRight(Camera3D *camera, float distance, bool moveInWorldPlane)
+{
+    Vector3 right = GetCameraRight(camera);
 
-    // Mouse movement detection
-    Vector2 mousePositionDelta = GetMouseDelta();
-    float mouseWheelMove = GetMouseWheelMove();
-
-    // Keys input detection
-    // TODO: Input detection is raylib-dependant, it could be moved outside the module
-    bool keyPan = IsMouseButtonDown(CAMERA.panControl);
-    bool keyAlt = IsKeyDown(CAMERA.altControl);
-    bool szoomKey = IsKeyDown(CAMERA.smoothZoomControl);
-    bool direction[6] = { IsKeyDown(CAMERA.moveControl[MOVE_FRONT]),
-                          IsKeyDown(CAMERA.moveControl[MOVE_BACK]),
-                          IsKeyDown(CAMERA.moveControl[MOVE_RIGHT]),
-                          IsKeyDown(CAMERA.moveControl[MOVE_LEFT]),
-                          IsKeyDown(CAMERA.moveControl[MOVE_UP]),
-                          IsKeyDown(CAMERA.moveControl[MOVE_DOWN]) };
-
-    // Support for multiple automatic camera modes
-    // NOTE: In case of CAMERA_CUSTOM nothing happens here, user must update it manually
-    switch (CAMERA.mode)
+    if (moveInWorldPlane)
     {
-        case CAMERA_FREE:           // Camera free controls, using standard 3d-content-creation scheme
-        {
-            // Camera zoom
-            if ((CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
-            {
-                CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
-                if (CAMERA.targetDistance > CAMERA_FREE_DISTANCE_MAX_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MAX_CLAMP;
-            }
-
-            // Camera looking down
-            else if ((camera->position.y > camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
-            {
-                camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
-                camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
-                camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
-            }
-            else if ((camera->position.y > camera->target.y) && (camera->target.y >= 0))
-            {
-                camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
-                camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
-                camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
-
-                // if (camera->target.y < 0) camera->target.y = -0.001;
-            }
-            else if ((camera->position.y > camera->target.y) && (camera->target.y < 0) && (mouseWheelMove > 0))
-            {
-                CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
-                if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP;
-            }
-            // Camera looking up
-            else if ((camera->position.y < camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
-            {
-                camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
-                camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
-                camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
-            }
-            else if ((camera->position.y < camera->target.y) && (camera->target.y <= 0))
-            {
-                camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
-                camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
-                camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
-
-                // if (camera->target.y > 0) camera->target.y = 0.001;
-            }
-            else if ((camera->position.y < camera->target.y) && (camera->target.y > 0) && (mouseWheelMove > 0))
-            {
-                CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
-                if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP;
-            }
-
-            // Input keys checks
-            if (keyPan)
-            {
-                if (keyAlt)     // Alternative key behaviour
-                {
-                    if (szoomKey)
-                    {
-                        // Camera smooth zoom
-                        CAMERA.targetDistance += (mousePositionDelta.y*CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY);
-                    }
-                    else
-                    {
-                        // Camera rotation
-                        CAMERA.angle.x += mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY;
-                        CAMERA.angle.y += mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY;
-
-                        // Angle clamp
-                        if (CAMERA.angle.y > CAMERA_FREE_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MIN_CLAMP*DEG2RAD;
-                        else if (CAMERA.angle.y < CAMERA_FREE_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MAX_CLAMP*DEG2RAD;
-                    }
-                }
-                else
-                {
-                    // Camera panning
-                    camera->target.x += ((mousePositionDelta.x*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x) + (mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
-                    camera->target.y += ((mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
-                    camera->target.z += ((mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x) + (mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
-                }
-            }
-
-            // Update camera position with changes
-            camera->position.x = -sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
-            camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance + camera->target.y;
-            camera->position.z = -cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z;
-
-        } break;
-        case CAMERA_ORBITAL:        // Camera just orbits around target, only zoom allowed
-        {
-            CAMERA.angle.x += CAMERA_ORBITAL_SPEED*GetFrameTime();      // Camera orbit angle
-            CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);   // Camera zoom
-
-            // Camera distance clamp
-            if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP;
-
-            // Update camera position with changes
-            camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
-            camera->position.y = ((CAMERA.angle.y <= 0.0f)? 1 : -1)*sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
-            camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z;
-
-        } break;
-        case CAMERA_FIRST_PERSON:   // Camera moves as in a first-person game, controls are configurable
-        {
-            // NOTE: On CAMERA_FIRST_PERSON player Y-movement is limited to player 'eyes position'
-            camera->position.y = CAMERA.playerEyesPosition;
-
-            camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] -
-                                   sinf(CAMERA.angle.x)*direction[MOVE_FRONT] -
-                                   cosf(CAMERA.angle.x)*direction[MOVE_LEFT] +
-                                   cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
-
-            camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] -
-                                   sinf(CAMERA.angle.y)*direction[MOVE_BACK] +
-                                   1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
-
-            camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] -
-                                   cosf(CAMERA.angle.x)*direction[MOVE_FRONT] +
-                                   sinf(CAMERA.angle.x)*direction[MOVE_LEFT] -
-                                   sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
-
-            // Camera orientation calculation
-            CAMERA.angle.x -= mousePositionDelta.x*CAMERA_MOUSE_MOVE_SENSITIVITY*GetFrameTime();
-            CAMERA.angle.y -= mousePositionDelta.y*CAMERA_MOUSE_MOVE_SENSITIVITY*GetFrameTime();
-
-            // Angle clamp
-            if (CAMERA.angle.y > CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD;
-            else if (CAMERA.angle.y < CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD;
-
-            // Calculate translation matrix
-            Matrix matTranslation = { 1.0f, 0.0f, 0.0f, 0.0f,
-                                      0.0f, 1.0f, 0.0f, 0.0f,
-                                      0.0f, 0.0f, 1.0f, (CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER),
-                                      0.0f, 0.0f, 0.0f, 1.0f };
-
-            // Calculate rotation matrix
-            Matrix matRotation = { 1.0f, 0.0f, 0.0f, 0.0f,
-                                   0.0f, 1.0f, 0.0f, 0.0f,
-                                   0.0f, 0.0f, 1.0f, 0.0f,
-                                   0.0f, 0.0f, 0.0f, 1.0f };
-
-            float cosz = cosf(0.0f);
-            float sinz = sinf(0.0f);
-            float cosy = cosf(-(PI*2 - CAMERA.angle.x));
-            float siny = sinf(-(PI*2 - CAMERA.angle.x));
-            float cosx = cosf(-(PI*2 - CAMERA.angle.y));
-            float sinx = sinf(-(PI*2 - CAMERA.angle.y));
-
-            matRotation.m0 = cosz*cosy;
-            matRotation.m4 = (cosz*siny*sinx) - (sinz*cosx);
-            matRotation.m8 = (cosz*siny*cosx) + (sinz*sinx);
-            matRotation.m1 = sinz*cosy;
-            matRotation.m5 = (sinz*siny*sinx) + (cosz*cosx);
-            matRotation.m9 = (sinz*siny*cosx) - (cosz*sinx);
-            matRotation.m2 = -siny;
-            matRotation.m6 = cosy*sinx;
-            matRotation.m10= cosy*cosx;
-
-            // Multiply translation and rotation matrices
-            Matrix matTransform = { 0 };
-            matTransform.m0 = matTranslation.m0*matRotation.m0 + matTranslation.m1*matRotation.m4 + matTranslation.m2*matRotation.m8 + matTranslation.m3*matRotation.m12;
-            matTransform.m1 = matTranslation.m0*matRotation.m1 + matTranslation.m1*matRotation.m5 + matTranslation.m2*matRotation.m9 + matTranslation.m3*matRotation.m13;
-            matTransform.m2 = matTranslation.m0*matRotation.m2 + matTranslation.m1*matRotation.m6 + matTranslation.m2*matRotation.m10 + matTranslation.m3*matRotation.m14;
-            matTransform.m3 = matTranslation.m0*matRotation.m3 + matTranslation.m1*matRotation.m7 + matTranslation.m2*matRotation.m11 + matTranslation.m3*matRotation.m15;
-            matTransform.m4 = matTranslation.m4*matRotation.m0 + matTranslation.m5*matRotation.m4 + matTranslation.m6*matRotation.m8 + matTranslation.m7*matRotation.m12;
-            matTransform.m5 = matTranslation.m4*matRotation.m1 + matTranslation.m5*matRotation.m5 + matTranslation.m6*matRotation.m9 + matTranslation.m7*matRotation.m13;
-            matTransform.m6 = matTranslation.m4*matRotation.m2 + matTranslation.m5*matRotation.m6 + matTranslation.m6*matRotation.m10 + matTranslation.m7*matRotation.m14;
-            matTransform.m7 = matTranslation.m4*matRotation.m3 + matTranslation.m5*matRotation.m7 + matTranslation.m6*matRotation.m11 + matTranslation.m7*matRotation.m15;
-            matTransform.m8 = matTranslation.m8*matRotation.m0 + matTranslation.m9*matRotation.m4 + matTranslation.m10*matRotation.m8 + matTranslation.m11*matRotation.m12;
-            matTransform.m9 = matTranslation.m8*matRotation.m1 + matTranslation.m9*matRotation.m5 + matTranslation.m10*matRotation.m9 + matTranslation.m11*matRotation.m13;
-            matTransform.m10 = matTranslation.m8*matRotation.m2 + matTranslation.m9*matRotation.m6 + matTranslation.m10*matRotation.m10 + matTranslation.m11*matRotation.m14;
-            matTransform.m11 = matTranslation.m8*matRotation.m3 + matTranslation.m9*matRotation.m7 + matTranslation.m10*matRotation.m11 + matTranslation.m11*matRotation.m15;
-            matTransform.m12 = matTranslation.m12*matRotation.m0 + matTranslation.m13*matRotation.m4 + matTranslation.m14*matRotation.m8 + matTranslation.m15*matRotation.m12;
-            matTransform.m13 = matTranslation.m12*matRotation.m1 + matTranslation.m13*matRotation.m5 + matTranslation.m14*matRotation.m9 + matTranslation.m15*matRotation.m13;
-            matTransform.m14 = matTranslation.m12*matRotation.m2 + matTranslation.m13*matRotation.m6 + matTranslation.m14*matRotation.m10 + matTranslation.m15*matRotation.m14;
-            matTransform.m15 = matTranslation.m12*matRotation.m3 + matTranslation.m13*matRotation.m7 + matTranslation.m14*matRotation.m11 + matTranslation.m15*matRotation.m15;
-
-            camera->target.x = camera->position.x - matTransform.m12;
-            camera->target.y = camera->position.y - matTransform.m13;
-            camera->target.z = camera->position.z - matTransform.m14;
-
-            // Camera swinging (y-movement), only when walking (some key pressed)
-            for (int i = 0; i < 6; i++) if (direction[i]) { swingCounter += GetFrameTime(); break; }
-            camera->position.y -= sinf(2*PI*CAMERA_FIRST_PERSON_STEP_FREQUENCY*swingCounter)*CAMERA_FIRST_PERSON_SWINGING_DELTA;
-
-            // Camera waiving (xz-movement), only when walking (some key pressed)
-            camera->up.x = sinf(2*PI*CAMERA_FIRST_PERSON_STEP_FREQUENCY*swingCounter)*CAMERA_FIRST_PERSON_TILTING_DELTA;
-            camera->up.z = -sinf(2*PI*CAMERA_FIRST_PERSON_STEP_FREQUENCY*swingCounter)*CAMERA_FIRST_PERSON_TILTING_DELTA;
-
-        } break;
-        case CAMERA_THIRD_PERSON:   // Camera moves as in a third-person game, following target at a distance, controls are configurable
-        {
-            camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] -
-                                   sinf(CAMERA.angle.x)*direction[MOVE_FRONT] -
-                                   cosf(CAMERA.angle.x)*direction[MOVE_LEFT] +
-                                   cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
-
-            camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] -
-                                   sinf(CAMERA.angle.y)*direction[MOVE_BACK] +
-                                   1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
-
-            camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] -
-                                   cosf(CAMERA.angle.x)*direction[MOVE_FRONT] +
-                                   sinf(CAMERA.angle.x)*direction[MOVE_LEFT] -
-                                   sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
-
-            // Camera orientation calculation
-            CAMERA.angle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY);
-            CAMERA.angle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY);
-
-            // Angle clamp
-            if (CAMERA.angle.y > CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD;
-            else if (CAMERA.angle.y < CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD;
-
-            // Camera zoom
-            CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
-
-            // Camera distance clamp
-            if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP;
-
-            camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
-
-            if (CAMERA.angle.y <= 0.0f) camera->position.y = sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
-            else camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
-
-            camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z;
-
-        } break;
-        case CAMERA_CUSTOM: break;
-        default: break;
+        // Project vector onto world plane
+        right.y = 0;
+        right = Vector3Normalize(right);
     }
+
+    // Scale by distance
+    right = Vector3Scale(right, distance);
+
+    // Move position and target
+    camera->position = Vector3Add(camera->position, right);
+    camera->target = Vector3Add(camera->target, right);
 }
 
-// Set camera pan key to combine with mouse movement (free camera)
-void SetCameraPanControl(int keyPan) { CAMERA.panControl = keyPan; }
+// Moves the camera position closer/farther to/from the camera target
+void CameraZoom(Camera3D *camera, float delta)
+{
+    float distance = Vector3Distance(camera->position, camera->target);
+
+    // Apply delta
+    distance += delta;
 
-// Set camera alt key to combine with mouse movement (free camera)
-void SetCameraAltControl(int keyAlt) { CAMERA.altControl = keyAlt; }
+    // Distance must be greater than 0
+    if (distance < 0) distance = 0.001f;
 
-// Set camera smooth zoom key to combine with mouse (free camera)
-void SetCameraSmoothZoomControl(int szoomKey) { CAMERA.smoothZoomControl = szoomKey; }
+    // Set new distance by moving the position along the forward vector
+    Vector3 forward = GetCameraForward(camera);
+    camera->position = Vector3Add(camera->target, Vector3Scale(forward, -distance));
+}
 
-// Set camera move controls (1st person and 3rd person cameras)
-void SetCameraMoveControls(int keyFront, int keyBack, int keyRight, int keyLeft, int keyUp, int keyDown)
+// Rotates the camera around its up vector
+// Yaw is "looking left and right"
+// If rotateAroundTarget is false, the camera rotates around its position
+// Note: angle must be provided in radians
+void CameraYaw(Camera3D *camera, float angle, bool rotateAroundTarget)
 {
-    CAMERA.moveControl[MOVE_FRONT] = keyFront;
-    CAMERA.moveControl[MOVE_BACK] = keyBack;
-    CAMERA.moveControl[MOVE_RIGHT] = keyRight;
-    CAMERA.moveControl[MOVE_LEFT] = keyLeft;
-    CAMERA.moveControl[MOVE_UP] = keyUp;
-    CAMERA.moveControl[MOVE_DOWN] = keyDown;
+    // Rotation axis
+    Vector3 up = GetCameraUp(camera);
+
+    // View vector
+    Vector3 target_position = Vector3Subtract(camera->target, camera->position);
+
+    // Rotate view vector around up axis
+    target_position = Vector3RotateByAxisAngle(target_position, up, angle);
+
+    if (rotateAroundTarget)
+    {
+        // Move position relative to target
+        camera->position = Vector3Subtract(camera->target, target_position);
+    }
+    else // rotate around camera.position
+    {
+        // Move target relative to position
+        camera->target = Vector3Add(camera->position, target_position);
+    }
+}
+
+// Rotates the camera around its right vector
+// Pitch is "looking up and down"
+// lockView prevents camera overrotation (aka "somersaults")
+// If rotateAroundTarget is false, the camera rotates around its position
+// rotateUp rotates the up direction as well (typically only usefull in CAMERA_FREE)
+// Note: angle must be provided in radians
+void CameraPitch(Camera3D *camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp)
+{
+    // Up direction
+    Vector3 up = GetCameraUp(camera);
+
+    // View vector
+    Vector3 target_position = Vector3Subtract(camera->target, camera->position);
+
+    if (lockView)
+    {
+        // In these camera modes we clamp the Pitch angle
+        // to allow only viewing straight up or down.
+
+        // Clamp view up
+        float max_angle_up = Vector3Angle(up, target_position);
+        max_angle_up -= 0.001f; // avoid numerical errors
+        if (angle > max_angle_up) angle = max_angle_up;
+
+        // Clamp view down
+        float max_angle_down = Vector3Angle(Vector3Negate(up), target_position);
+        max_angle_down *= -1.0f; // downwards angle is negative
+        max_angle_down += 0.001f; // avoid numerical errors
+        if (angle < max_angle_down) angle = max_angle_down;
+    }
+
+    // Rotation axis
+    Vector3 right = GetCameraRight(camera);
+
+    // Rotate view vector around right axis
+    target_position = Vector3RotateByAxisAngle(target_position, right, angle);
+
+    if (rotateAroundTarget)
+    {
+        // Move position relative to target
+        camera->position = Vector3Subtract(camera->target, target_position);
+    }
+    else // rotate around camera.position
+    {
+        // Move target relative to position
+        camera->target = Vector3Add(camera->position, target_position);
+    }
+
+    if (rotateUp)
+    {
+        // Rotate up direction around right axis
+        camera->up = Vector3RotateByAxisAngle(camera->up, right, angle);
+    }
+}
+
+// Rotates the camera around its forward vector
+// Roll is "turning your head sideways to the left or right"
+// Note: angle must be provided in radians
+void CameraRoll(Camera3D *camera, float angle)
+{
+    // Rotation axis
+    Vector3 forward = GetCameraForward(camera);
+
+    // Rotate up direction around forward axis
+    camera->up = Vector3RotateByAxisAngle(camera->up, forward, angle);
+}
+
+// Moves camera slightly to simulate a walking motion
+// Note: Only active if camera->swingCounter > 0
+void CameraViewBobbing(Camera3D *camera)
+{
+    if (camera->swingCounter > 0)
+    {
+        // NOTE: We delay the target movement relative to the position movement to create a little pitch with each step.
+        camera->position.y = camera->position.y - 0.25f * sinf((camera->swingCounter + 1) / CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER) / CAMERA_FIRST_PERSON_STEP_DIVIDER;
+        camera->target.y = camera->target.y - 0.25f * sinf((camera->swingCounter - 1) / CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER) / CAMERA_FIRST_PERSON_STEP_DIVIDER;
+
+        // Update counter for next frame
+        camera->swingCounter %= 2147483647 /* INT_MAX */; // Counter must be positive
+        camera->swingCounter++;
+    }
+}
+
+// Returns the camera view matrix
+Matrix GetCameraViewMatrix(Camera3D *camera)
+{
+    return MatrixLookAt(camera->position, camera->target, camera->up);
+}
+
+// Returns the camera projection matrix
+Matrix GetCameraProjectionMatrix(Camera3D *camera, float aspect)
+{
+    if (camera->projection == CAMERA_PERSPECTIVE)
+    {
+        return MatrixPerspective(camera->fovy * DEG2RAD, aspect, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR);
+    }
+    else if (camera->projection == CAMERA_ORTHOGRAPHIC)
+    {
+        double top = camera->fovy / 2.0;
+        double right = top * aspect;
+        return MatrixOrtho(-right, right, -top, top, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR);
+    }
+    
+    return MatrixIdentity();
+}
+
+
+#ifndef CAMERA_STANDALONE
+// Update camera position for selected mode
+// Camera mode: CAMERA_FREE, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON, CAMERA_ORBITAL or CUSTOM
+void UpdateCamera(Camera3D *camera, int mode)
+{
+    Vector2 mousePositionDelta = GetMouseDelta();
+
+    bool moveInWorldPlane = mode == CAMERA_FIRST_PERSON || mode == CAMERA_THIRD_PERSON;
+    bool rotateAroundTarget = mode == CAMERA_THIRD_PERSON || mode == CAMERA_ORBITAL;
+    bool lockView = mode == CAMERA_FIRST_PERSON || mode == CAMERA_THIRD_PERSON || mode == CAMERA_ORBITAL;
+    bool rotateUp = mode == CAMERA_FREE;
+    
+    // Camera movement
+    if (IsKeyDown(KEY_W)) CameraMoveForward(camera, CAMERA_MOVE_SPEED, moveInWorldPlane);
+    if (IsKeyDown(KEY_S)) CameraMoveForward(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane);
+    if (IsKeyDown(KEY_D)) CameraMoveRight(camera, CAMERA_MOVE_SPEED, moveInWorldPlane);
+    if (IsKeyDown(KEY_A)) CameraMoveRight(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane);
+    if (IsKeyDown(KEY_SPACE)) CameraMoveUp(camera, CAMERA_MOVE_SPEED);
+    if (IsKeyDown(KEY_LEFT_CONTROL)) CameraMoveUp(camera, -CAMERA_MOVE_SPEED);
+
+    // Camera rotation
+    if (IsKeyDown(KEY_DOWN)) CameraPitch(camera, -CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp);
+    if (IsKeyDown(KEY_UP)) CameraPitch(camera, CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp);
+    if (IsKeyDown(KEY_RIGHT)) CameraYaw(camera, -CAMERA_ROTATION_SPEED, rotateAroundTarget);
+    if (IsKeyDown(KEY_LEFT)) CameraYaw(camera, CAMERA_ROTATION_SPEED, rotateAroundTarget);
+    if (IsKeyDown(KEY_Q)) CameraRoll(camera, -CAMERA_ROTATION_SPEED);
+    if (IsKeyDown(KEY_E)) CameraRoll(camera, CAMERA_ROTATION_SPEED);
+
+    CameraYaw(camera, mousePositionDelta.x * -CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget);
+    CameraPitch(camera, mousePositionDelta.y * -CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp);
+
+    // Zoom target distance
+    CameraZoom(camera, -GetMouseWheelMove());
+    if (IsKeyPressed(KEY_KP_SUBTRACT)) CameraZoom(camera, 2.0f);
+    if (IsKeyPressed(KEY_KP_ADD)) CameraZoom(camera, -2.0f);
+
+
+    // Apply view bobbing when moving around (per default only active in CAMERA_FIRST_PERSON)
+    if (mode == CAMERA_FIRST_PERSON && (IsKeyDown(KEY_W) || IsKeyDown(KEY_A) || IsKeyDown(KEY_S) || IsKeyDown(KEY_D))) CameraViewBobbing(camera);
 }
+#endif // !CAMERA_STANDALONE
 
 #endif // CAMERA_IMPLEMENTATION

+ 567 - 0
src/rcamera_old.h

@@ -0,0 +1,567 @@
+/*******************************************************************************************
+*
+*   rcamera - Basic camera system for multiple camera modes
+*
+*   NOTE: Memory footprint of this library is aproximately 52 bytes (global variables)
+*
+*   CONFIGURATION:
+*
+*   #define CAMERA_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 CAMERA_STANDALONE
+*       If defined, the library can be used as standalone as a camera system but some
+*       functions must be redefined to manage inputs accordingly.
+*
+*   CONTRIBUTORS:
+*       Ramon Santamaria:   Supervision, review, update and maintenance
+*       Marc Palau:         Initial implementation (2014)
+*
+*
+*   LICENSE: zlib/libpng
+*
+*   Copyright (c) 2015-2022 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.
+*
+**********************************************************************************************/
+
+#ifndef RCAMERA_H
+#define RCAMERA_H
+
+//----------------------------------------------------------------------------------
+// Defines and Macros
+//----------------------------------------------------------------------------------
+//...
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+// NOTE: Below types are required for CAMERA_STANDALONE usage
+//----------------------------------------------------------------------------------
+#if defined(CAMERA_STANDALONE)
+    // Vector2 type
+    typedef struct Vector2 {
+        float x;
+        float y;
+    } Vector2;
+
+    // Vector3 type
+    typedef struct Vector3 {
+        float x;
+        float y;
+        float z;
+    } Vector3;
+
+    // Camera type, defines a camera position/orientation in 3d space
+    typedef struct Camera3D {
+        Vector3 position;       // Camera position
+        Vector3 target;         // Camera target it looks-at
+        Vector3 up;             // Camera up vector (rotation over its axis)
+        float fovy;             // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic
+        int type;               // Camera type, defines projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC
+    } Camera3D;
+
+    typedef Camera3D Camera;    // Camera type fallback, defaults to Camera3D
+
+    // Camera system modes
+    typedef enum {
+        CAMERA_CUSTOM = 0,
+        CAMERA_FREE,
+        CAMERA_ORBITAL,
+        CAMERA_FIRST_PERSON,
+        CAMERA_THIRD_PERSON
+    } CameraMode;
+
+    // Camera projection modes
+    typedef enum {
+        CAMERA_PERSPECTIVE = 0,
+        CAMERA_ORTHOGRAPHIC
+    } CameraProjection;
+#endif
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+//...
+
+//----------------------------------------------------------------------------------
+// Module Functions Declaration
+//----------------------------------------------------------------------------------
+
+#ifdef __cplusplus
+extern "C" {            // Prevents name mangling of functions
+#endif
+
+#if defined(CAMERA_STANDALONE)
+void SetCameraMode(Camera camera, int mode);                // Set camera mode (multiple camera modes available)
+void UpdateCamera(Camera *camera);                          // Update camera position for selected mode
+
+void SetCameraPanControl(int keyPan);                       // Set camera pan key to combine with mouse movement (free camera)
+void SetCameraAltControl(int keyAlt);                       // Set camera alt key to combine with mouse movement (free camera)
+void SetCameraSmoothZoomControl(int szoomKey);              // Set camera smooth zoom key to combine with mouse (free camera)
+void SetCameraMoveControls(int keyFront, int keyBack,
+                           int keyRight, int keyLeft,
+                           int keyUp, int keyDown);         // Set camera move controls (1st person and 3rd person cameras)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CAMERA_H
+
+
+/***********************************************************************************
+*
+*   CAMERA IMPLEMENTATION
+*
+************************************************************************************/
+
+#if defined(CAMERA_IMPLEMENTATION)
+
+#include <math.h>               // Required for: sinf(), cosf(), sqrtf()
+
+//----------------------------------------------------------------------------------
+// Defines and Macros
+//----------------------------------------------------------------------------------
+#ifndef PI
+    #define PI 3.14159265358979323846
+#endif
+#ifndef DEG2RAD
+    #define DEG2RAD (PI/180.0f)
+#endif
+#ifndef RAD2DEG
+    #define RAD2DEG (180.0f/PI)
+#endif
+
+// Camera mouse movement sensitivity
+#define CAMERA_MOUSE_MOVE_SENSITIVITY                   0.003f
+#define CAMERA_MOUSE_SCROLL_SENSITIVITY                 1.5f
+
+// FREE_CAMERA
+#define CAMERA_FREE_MOUSE_SENSITIVITY                   0.01f
+#define CAMERA_FREE_DISTANCE_MIN_CLAMP                  0.3f
+#define CAMERA_FREE_DISTANCE_MAX_CLAMP                  120.0f
+#define CAMERA_FREE_MIN_CLAMP                           85.0f
+#define CAMERA_FREE_MAX_CLAMP                          -85.0f
+#define CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY             0.05f
+#define CAMERA_FREE_PANNING_DIVIDER                     5.1f
+
+// ORBITAL_CAMERA
+#define CAMERA_ORBITAL_SPEED                            0.01f       // Radians per frame
+
+// FIRST_PERSON
+//#define CAMERA_FIRST_PERSON_MOUSE_SENSITIVITY           0.003f
+#define CAMERA_FIRST_PERSON_FOCUS_DISTANCE              25.0f
+#define CAMERA_FIRST_PERSON_MIN_CLAMP                   89.0f
+#define CAMERA_FIRST_PERSON_MAX_CLAMP                  -89.0f
+
+#define CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER  8.0f
+#define CAMERA_FIRST_PERSON_STEP_DIVIDER                30.0f
+#define CAMERA_FIRST_PERSON_WAVING_DIVIDER              200.0f
+
+// THIRD_PERSON
+//#define CAMERA_THIRD_PERSON_MOUSE_SENSITIVITY           0.003f
+#define CAMERA_THIRD_PERSON_DISTANCE_CLAMP              1.2f
+#define CAMERA_THIRD_PERSON_MIN_CLAMP                   5.0f
+#define CAMERA_THIRD_PERSON_MAX_CLAMP                  -85.0f
+#define CAMERA_THIRD_PERSON_OFFSET                      (Vector3){ 0.4f, 0.0f, 0.0f }
+
+// PLAYER (used by camera)
+#define PLAYER_MOVEMENT_SENSITIVITY                     20.0f
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+// Camera move modes (first person and third person cameras)
+typedef enum {
+    MOVE_FRONT = 0,
+    MOVE_BACK,
+    MOVE_RIGHT,
+    MOVE_LEFT,
+    MOVE_UP,
+    MOVE_DOWN
+} CameraMove;
+
+// Camera global state context data [56 bytes]
+typedef struct {
+    unsigned int mode;              // Current camera mode
+    float targetDistance;           // Camera distance from position to target
+    float playerEyesPosition;       // Player eyes position from ground (in meters)
+    Vector2 angle;                  // Camera angle in plane XZ
+    Vector2 previousMousePosition;  // Previous mouse position
+
+    // Camera movement control keys
+    int moveControl[6];             // Move controls (CAMERA_FIRST_PERSON)
+    int smoothZoomControl;          // Smooth zoom control key
+    int altControl;                 // Alternative control key
+    int panControl;                 // Pan view control key
+} CameraData;
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+static CameraData CAMERA = {        // Global CAMERA state context
+    .mode = 0,
+    .targetDistance = 0,
+    .playerEyesPosition = 1.85f,
+    .angle = { 0 },
+    .previousMousePosition = { 0 },
+    .moveControl = { 'W', 'S', 'D', 'A', 'E', 'Q' },
+    .smoothZoomControl = 341,       // raylib: KEY_LEFT_CONTROL
+    .altControl = 342,              // raylib: KEY_LEFT_ALT
+    .panControl = 2                 // raylib: MOUSE_BUTTON_MIDDLE
+};
+
+//----------------------------------------------------------------------------------
+// Module specific Functions Declaration
+//----------------------------------------------------------------------------------
+#if defined(CAMERA_STANDALONE)
+// NOTE: Camera controls depend on some raylib input functions
+static void EnableCursor() {}       // Unlock cursor
+static void DisableCursor() {}      // Lock cursor
+
+static int IsKeyDown(int key) { return 0; }
+
+static int IsMouseButtonDown(int button) { return 0;}
+static float GetMouseWheelMove() { return 0.0f; }
+static Vector2 GetMousePosition() { return (Vector2){ 0.0f, 0.0f }; }
+#endif
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+
+// Select camera mode (multiple camera modes available)
+void SetCameraMode(Camera camera, int mode)
+{
+    Vector3 v1 = camera.position;
+    Vector3 v2 = camera.target;
+
+    float dx = v2.x - v1.x;
+    float dy = v2.y - v1.y;
+    float dz = v2.z - v1.z;
+
+    CAMERA.targetDistance = sqrtf(dx*dx + dy*dy + dz*dz);   // Distance to target
+
+    // Camera angle calculation
+    CAMERA.angle.x = atan2f(dx, dz);                        // Camera angle in plane XZ (0 aligned with Z, move positive CCW)
+    CAMERA.angle.y = atan2f(dy, sqrtf(dx*dx + dz*dz));      // Camera angle in plane XY (0 aligned with X, move positive CW)
+
+    CAMERA.playerEyesPosition = camera.position.y;          // Init player eyes position to camera Y position
+
+    CAMERA.previousMousePosition = GetMousePosition();      // Init mouse position
+
+    // Lock cursor for first person and third person cameras
+    if ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)) DisableCursor();
+    else EnableCursor();
+
+    CAMERA.mode = mode;
+}
+
+// Update camera depending on selected mode
+// NOTE: Camera controls depend on some raylib functions:
+//       System: EnableCursor(), DisableCursor()
+//       Mouse: IsMouseButtonDown(), GetMousePosition(), GetMouseWheelMove()
+//       Keys:  IsKeyDown()
+void UpdateCamera(Camera *camera)
+{
+    static int swingCounter = 0;    // Used for 1st person swinging movement
+
+    // TODO: Compute CAMERA.targetDistance and CAMERA.angle here (?)
+
+    // Mouse movement detection
+    Vector2 mousePositionDelta = { 0.0f, 0.0f };
+    Vector2 mousePosition = GetMousePosition();
+    float mouseWheelMove = GetMouseWheelMove();
+
+    // Keys input detection
+    // TODO: Input detection is raylib-dependant, it could be moved outside the module
+    bool keyPan = IsMouseButtonDown(CAMERA.panControl);
+    bool keyAlt = IsKeyDown(CAMERA.altControl);
+    bool szoomKey = IsKeyDown(CAMERA.smoothZoomControl);
+    bool direction[6] = { IsKeyDown(CAMERA.moveControl[MOVE_FRONT]),
+                          IsKeyDown(CAMERA.moveControl[MOVE_BACK]),
+                          IsKeyDown(CAMERA.moveControl[MOVE_RIGHT]),
+                          IsKeyDown(CAMERA.moveControl[MOVE_LEFT]),
+                          IsKeyDown(CAMERA.moveControl[MOVE_UP]),
+                          IsKeyDown(CAMERA.moveControl[MOVE_DOWN]) };
+
+    if (CAMERA.mode != CAMERA_CUSTOM)
+    {
+        mousePositionDelta.x = mousePosition.x - CAMERA.previousMousePosition.x;
+        mousePositionDelta.y = mousePosition.y - CAMERA.previousMousePosition.y;
+
+        CAMERA.previousMousePosition = mousePosition;
+    }
+
+    // Support for multiple automatic camera modes
+    // NOTE: In case of CAMERA_CUSTOM nothing happens here, user must update it manually
+    switch (CAMERA.mode)
+    {
+        case CAMERA_FREE:           // Camera free controls, using standard 3d-content-creation scheme
+        {
+            // Camera zoom
+            if ((CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
+            {
+                CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
+                if (CAMERA.targetDistance > CAMERA_FREE_DISTANCE_MAX_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MAX_CLAMP;
+            }
+
+            // Camera looking down
+            else if ((camera->position.y > camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
+            {
+                camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
+                camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
+                camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
+            }
+            else if ((camera->position.y > camera->target.y) && (camera->target.y >= 0))
+            {
+                camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
+                camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
+                camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
+
+                // if (camera->target.y < 0) camera->target.y = -0.001;
+            }
+            else if ((camera->position.y > camera->target.y) && (camera->target.y < 0) && (mouseWheelMove > 0))
+            {
+                CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
+                if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP;
+            }
+            // Camera looking up
+            else if ((camera->position.y < camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
+            {
+                camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
+                camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
+                camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
+            }
+            else if ((camera->position.y < camera->target.y) && (camera->target.y <= 0))
+            {
+                camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
+                camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
+                camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
+
+                // if (camera->target.y > 0) camera->target.y = 0.001;
+            }
+            else if ((camera->position.y < camera->target.y) && (camera->target.y > 0) && (mouseWheelMove > 0))
+            {
+                CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
+                if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP;
+            }
+
+            // Input keys checks
+            if (keyPan)
+            {
+                if (keyAlt)     // Alternative key behaviour
+                {
+                    if (szoomKey)
+                    {
+                        // Camera smooth zoom
+                        CAMERA.targetDistance += (mousePositionDelta.y*CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY);
+                    }
+                    else
+                    {
+                        // Camera rotation
+                        CAMERA.angle.x += mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY;
+                        CAMERA.angle.y += mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY;
+
+                        // Angle clamp
+                        if (CAMERA.angle.y > CAMERA_FREE_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MIN_CLAMP*DEG2RAD;
+                        else if (CAMERA.angle.y < CAMERA_FREE_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MAX_CLAMP*DEG2RAD;
+                    }
+                }
+                else
+                {
+                    // Camera panning
+                    camera->target.x += ((mousePositionDelta.x*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x) + (mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
+                    camera->target.y += ((mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
+                    camera->target.z += ((mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x) + (mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
+                }
+            }
+
+            // Update camera position with changes
+            camera->position.x = -sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
+            camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance + camera->target.y;
+            camera->position.z = -cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z;
+
+        } break;
+        case CAMERA_ORBITAL:        // Camera just orbits around target, only zoom allowed
+        {
+            CAMERA.angle.x += CAMERA_ORBITAL_SPEED;      // Camera orbit angle
+            CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);   // Camera zoom
+
+            // Camera distance clamp
+            if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP;
+
+            // Update camera position with changes
+            camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
+            camera->position.y = ((CAMERA.angle.y <= 0.0f)? 1 : -1)*sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
+            camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z;
+
+        } break;
+        case CAMERA_FIRST_PERSON:   // Camera moves as in a first-person game, controls are configurable
+        {
+            camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] -
+                                   sinf(CAMERA.angle.x)*direction[MOVE_FRONT] -
+                                   cosf(CAMERA.angle.x)*direction[MOVE_LEFT] +
+                                   cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
+
+            camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] -
+                                   sinf(CAMERA.angle.y)*direction[MOVE_BACK] +
+                                   1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_SENSITIVITY;
+
+            camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] -
+                                   cosf(CAMERA.angle.x)*direction[MOVE_FRONT] +
+                                   sinf(CAMERA.angle.x)*direction[MOVE_LEFT] -
+                                   sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
+
+            // Camera orientation calculation
+            CAMERA.angle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY);
+            CAMERA.angle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY);
+
+            // Angle clamp
+            if (CAMERA.angle.y > CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD;
+            else if (CAMERA.angle.y < CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD;
+
+            // Calculate translation matrix
+            Matrix matTranslation = { 1.0f, 0.0f, 0.0f, 0.0f,
+                                      0.0f, 1.0f, 0.0f, 0.0f,
+                                      0.0f, 0.0f, 1.0f, (CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER),
+                                      0.0f, 0.0f, 0.0f, 1.0f };
+
+            // Calculate rotation matrix
+            Matrix matRotation = { 1.0f, 0.0f, 0.0f, 0.0f,
+                                   0.0f, 1.0f, 0.0f, 0.0f,
+                                   0.0f, 0.0f, 1.0f, 0.0f,
+                                   0.0f, 0.0f, 0.0f, 1.0f };
+
+            float cosz = cosf(0.0f);
+            float sinz = sinf(0.0f);
+            float cosy = cosf(-(PI*2 - CAMERA.angle.x));
+            float siny = sinf(-(PI*2 - CAMERA.angle.x));
+            float cosx = cosf(-(PI*2 - CAMERA.angle.y));
+            float sinx = sinf(-(PI*2 - CAMERA.angle.y));
+
+            matRotation.m0 = cosz*cosy;
+            matRotation.m4 = (cosz*siny*sinx) - (sinz*cosx);
+            matRotation.m8 = (cosz*siny*cosx) + (sinz*sinx);
+            matRotation.m1 = sinz*cosy;
+            matRotation.m5 = (sinz*siny*sinx) + (cosz*cosx);
+            matRotation.m9 = (sinz*siny*cosx) - (cosz*sinx);
+            matRotation.m2 = -siny;
+            matRotation.m6 = cosy*sinx;
+            matRotation.m10= cosy*cosx;
+
+            // Multiply translation and rotation matrices
+            Matrix matTransform = { 0 };
+            matTransform.m0 = matTranslation.m0*matRotation.m0 + matTranslation.m1*matRotation.m4 + matTranslation.m2*matRotation.m8 + matTranslation.m3*matRotation.m12;
+            matTransform.m1 = matTranslation.m0*matRotation.m1 + matTranslation.m1*matRotation.m5 + matTranslation.m2*matRotation.m9 + matTranslation.m3*matRotation.m13;
+            matTransform.m2 = matTranslation.m0*matRotation.m2 + matTranslation.m1*matRotation.m6 + matTranslation.m2*matRotation.m10 + matTranslation.m3*matRotation.m14;
+            matTransform.m3 = matTranslation.m0*matRotation.m3 + matTranslation.m1*matRotation.m7 + matTranslation.m2*matRotation.m11 + matTranslation.m3*matRotation.m15;
+            matTransform.m4 = matTranslation.m4*matRotation.m0 + matTranslation.m5*matRotation.m4 + matTranslation.m6*matRotation.m8 + matTranslation.m7*matRotation.m12;
+            matTransform.m5 = matTranslation.m4*matRotation.m1 + matTranslation.m5*matRotation.m5 + matTranslation.m6*matRotation.m9 + matTranslation.m7*matRotation.m13;
+            matTransform.m6 = matTranslation.m4*matRotation.m2 + matTranslation.m5*matRotation.m6 + matTranslation.m6*matRotation.m10 + matTranslation.m7*matRotation.m14;
+            matTransform.m7 = matTranslation.m4*matRotation.m3 + matTranslation.m5*matRotation.m7 + matTranslation.m6*matRotation.m11 + matTranslation.m7*matRotation.m15;
+            matTransform.m8 = matTranslation.m8*matRotation.m0 + matTranslation.m9*matRotation.m4 + matTranslation.m10*matRotation.m8 + matTranslation.m11*matRotation.m12;
+            matTransform.m9 = matTranslation.m8*matRotation.m1 + matTranslation.m9*matRotation.m5 + matTranslation.m10*matRotation.m9 + matTranslation.m11*matRotation.m13;
+            matTransform.m10 = matTranslation.m8*matRotation.m2 + matTranslation.m9*matRotation.m6 + matTranslation.m10*matRotation.m10 + matTranslation.m11*matRotation.m14;
+            matTransform.m11 = matTranslation.m8*matRotation.m3 + matTranslation.m9*matRotation.m7 + matTranslation.m10*matRotation.m11 + matTranslation.m11*matRotation.m15;
+            matTransform.m12 = matTranslation.m12*matRotation.m0 + matTranslation.m13*matRotation.m4 + matTranslation.m14*matRotation.m8 + matTranslation.m15*matRotation.m12;
+            matTransform.m13 = matTranslation.m12*matRotation.m1 + matTranslation.m13*matRotation.m5 + matTranslation.m14*matRotation.m9 + matTranslation.m15*matRotation.m13;
+            matTransform.m14 = matTranslation.m12*matRotation.m2 + matTranslation.m13*matRotation.m6 + matTranslation.m14*matRotation.m10 + matTranslation.m15*matRotation.m14;
+            matTransform.m15 = matTranslation.m12*matRotation.m3 + matTranslation.m13*matRotation.m7 + matTranslation.m14*matRotation.m11 + matTranslation.m15*matRotation.m15;
+
+            camera->target.x = camera->position.x - matTransform.m12;
+            camera->target.y = camera->position.y - matTransform.m13;
+            camera->target.z = camera->position.z - matTransform.m14;
+
+            // If movement detected (some key pressed), increase swinging
+            for (int i = 0; i < 6; i++) if (direction[i]) { swingCounter++; break; }
+
+            // Camera position update
+            // NOTE: On CAMERA_FIRST_PERSON player Y-movement is limited to player 'eyes position'
+            camera->position.y = CAMERA.playerEyesPosition - sinf(swingCounter/CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER)/CAMERA_FIRST_PERSON_STEP_DIVIDER;
+
+            camera->up.x = sinf(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER;
+            camera->up.z = -sinf(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER;
+
+        } break;
+        case CAMERA_THIRD_PERSON:   // Camera moves as in a third-person game, following target at a distance, controls are configurable
+        {
+            camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] -
+                                   sinf(CAMERA.angle.x)*direction[MOVE_FRONT] -
+                                   cosf(CAMERA.angle.x)*direction[MOVE_LEFT] +
+                                   cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
+
+            camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] -
+                                   sinf(CAMERA.angle.y)*direction[MOVE_BACK] +
+                                   1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_SENSITIVITY;
+
+            camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] -
+                                   cosf(CAMERA.angle.x)*direction[MOVE_FRONT] +
+                                   sinf(CAMERA.angle.x)*direction[MOVE_LEFT] -
+                                   sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
+
+            // Camera orientation calculation
+            CAMERA.angle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY);
+            CAMERA.angle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY);
+
+            // Angle clamp
+            if (CAMERA.angle.y > CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD;
+            else if (CAMERA.angle.y < CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD;
+
+            // Camera zoom
+            CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
+
+            // Camera distance clamp
+            if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP;
+
+            camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
+
+            if (CAMERA.angle.y <= 0.0f) camera->position.y = sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
+            else camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
+
+            camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z;
+
+        } break;
+        case CAMERA_CUSTOM: break;
+        default: break;
+    }
+}
+
+// Set camera pan key to combine with mouse movement (free camera)
+void SetCameraPanControl(int keyPan) { CAMERA.panControl = keyPan; }
+
+// Set camera alt key to combine with mouse movement (free camera)
+void SetCameraAltControl(int keyAlt) { CAMERA.altControl = keyAlt; }
+
+// Set camera smooth zoom key to combine with mouse (free camera)
+void SetCameraSmoothZoomControl(int szoomKey) { CAMERA.smoothZoomControl = szoomKey; }
+
+// Set camera move controls (1st person and 3rd person cameras)
+void SetCameraMoveControls(int keyFront, int keyBack, int keyRight, int keyLeft, int keyUp, int keyDown)
+{
+    CAMERA.moveControl[MOVE_FRONT] = keyFront;
+    CAMERA.moveControl[MOVE_BACK] = keyBack;
+    CAMERA.moveControl[MOVE_RIGHT] = keyRight;
+    CAMERA.moveControl[MOVE_LEFT] = keyLeft;
+    CAMERA.moveControl[MOVE_UP] = keyUp;
+    CAMERA.moveControl[MOVE_DOWN] = keyDown;
+}
+
+#endif // CAMERA_IMPLEMENTATION