Browse Source

Ported camera module to header-only

Ray 9 years ago
parent
commit
289e04a62a
4 changed files with 559 additions and 557 deletions
  1. 0 4
      src/Makefile
  2. 0 523
      src/camera.c
  3. 556 30
      src/camera.h
  4. 3 0
      src/core.c

+ 0 - 4
src/Makefile

@@ -203,10 +203,6 @@ external/stb_vorbis.o: external/stb_vorbis.c external/stb_vorbis.h
 utils.o : utils.c utils.h
 	$(CC) -c $< $(CFLAGS) $(INCLUDES) -D$(PLATFORM)
 
-# compile camera module
-camera.o : camera.c raylib.h
-	$(CC) -c $< $(CFLAGS) $(INCLUDES)
-
 # It installs generated and needed files to compile projects using raylib.
 # The installation works manually.
 # TODO: add other platforms.

+ 0 - 523
src/camera.c

@@ -1,523 +0,0 @@
-/**********************************************************************************************
-*
-*   raylib Camera System - Camera Modes Setup and Control Functions
-*
-*   Copyright (c) 2015 Marc Palau and Ramon Santamaria (@raysan5)
-*
-*   This software is provided "as-is", without any express or implied warranty. In no event
-*   will the authors be held liable for any damages arising from the use of this software.
-*
-*   Permission is granted to anyone to use this software for any purpose, including commercial
-*   applications, and to alter it and redistribute it freely, subject to the following restrictions:
-*
-*     1. The origin of this software must not be misrepresented; you must not claim that you
-*     wrote the original software. If you use this software in a product, an acknowledgment
-*     in the product documentation would be appreciated but is not required.
-*
-*     2. Altered source versions must be plainly marked as such, and must not be misrepresented
-*     as being the original software.
-*
-*     3. This notice may not be removed or altered from any source distribution.
-*
-**********************************************************************************************/
-
-//#define CAMERA_STANDALONE     // NOTE: To use the camera module as standalone lib, just uncomment this line
-                                // NOTE: ProcessCamera() should be reviewed to adapt inputs to other systems
-
-#if defined(CAMERA_STANDALONE)
-    #include "camera.h"
-#else
-    #include "raylib.h"
-#endif
-
-#include <math.h>               // Required for: sqrt(), sin(), cos()
-
-//----------------------------------------------------------------------------------
-// Defines and Macros
-//----------------------------------------------------------------------------------
-// CAMERA_GENERIC
-#define CAMERA_SCROLL_SENSITIVITY               1.5f
-
-// FREE_CAMERA
-#define FREE_CAMERA_MOUSE_SENSITIVITY           0.01f
-#define FREE_CAMERA_DISTANCE_MIN_CLAMP          0.3f
-#define FREE_CAMERA_DISTANCE_MAX_CLAMP          120.0f
-#define FREE_CAMERA_MIN_CLAMP                   85.0f
-#define FREE_CAMERA_MAX_CLAMP                  -85.0f
-#define FREE_CAMERA_SMOOTH_ZOOM_SENSITIVITY     0.05f
-#define FREE_CAMERA_PANNING_DIVIDER             5.1f
-
-// ORBITAL_CAMERA
-#define ORBITAL_CAMERA_SPEED                    0.01f
-
-// FIRST_PERSON
-//#define FIRST_PERSON_MOUSE_SENSITIVITY          0.003f
-#define FIRST_PERSON_FOCUS_DISTANCE             25.0f
-#define FIRST_PERSON_MIN_CLAMP                  85.0f
-#define FIRST_PERSON_MAX_CLAMP                 -85.0f
-
-#define FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 5.0f
-#define FIRST_PERSON_STEP_DIVIDER               30.0f
-#define FIRST_PERSON_WAVING_DIVIDER             200.0f
-
-#define FIRST_PERSON_HEIGHT_RELATIVE_EYES_POSITION  0.85f
-
-// THIRD_PERSON
-//#define THIRD_PERSON_MOUSE_SENSITIVITY          0.003f
-#define THIRD_PERSON_DISTANCE_CLAMP             1.2f
-#define THIRD_PERSON_MIN_CLAMP                  5.0f
-#define THIRD_PERSON_MAX_CLAMP                 -85.0f
-#define THIRD_PERSON_OFFSET                     (Vector3){ 0.4f, 0.0f, 0.0f }
-
-// PLAYER (used by camera)
-#define PLAYER_WIDTH                0.4f
-#define PLAYER_HEIGHT               0.9f
-#define PLAYER_DEPTH                0.4f
-#define PLAYER_MOVEMENT_DIVIDER     20.0f
-
-//----------------------------------------------------------------------------------
-// Types and Structures Definition
-//----------------------------------------------------------------------------------
-// Camera move modes (first person and third person cameras)
-typedef enum { MOVE_FRONT = 0, MOVE_LEFT, MOVE_BACK, MOVE_RIGHT, MOVE_UP, MOVE_DOWN } CameraMove;
-
-//----------------------------------------------------------------------------------
-// Global Variables Definition
-//----------------------------------------------------------------------------------
-static Camera internalCamera = {{ 2.0f, 0.0f, 2.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f };
-static Vector2 cameraAngle = { 0.0f, 0.0f };
-static float cameraTargetDistance = 5.0f;
-static Vector2 cameraMousePosition = { 0.0f, 0.0f };
-static Vector2 cameraMouseVariation = { 0.0f, 0.0f };
-static float mouseSensitivity = 0.003f;
-static int cameraMoveControl[6]  = { 'W', 'A', 'S', 'D', 'E', 'Q' };
-static int cameraMoveCounter = 0;
-static int cameraUseGravity = 1;
-static int panControlKey = 2;                   // raylib: MOUSE_MIDDLE_BUTTON
-static int altControlKey = 342;                 // raylib: KEY_LEFT_ALT
-static int smoothZoomControlKey = 341;          // raylib: KEY_LEFT_CONTROL
-
-static int cameraMode = CAMERA_CUSTOM;
-
-//----------------------------------------------------------------------------------
-// Module specific Functions Declaration
-//----------------------------------------------------------------------------------
-static void ProcessCamera(Camera *camera, Vector3 *playerPosition);
-
-#if defined(CAMERA_STANDALONE)
-// NOTE: Camera controls depend on some raylib input functions
-// TODO: Set your own input functions (used in ProcessCamera())
-static Vector2 GetMousePosition() { return (Vector2){ 0.0f, 0.0f }; }
-static void SetMousePosition(Vector2 pos) {} 
-static int IsMouseButtonDown(int button) { return 0;}
-static int GetMouseWheelMove() { return 0; }
-static int GetScreenWidth() { return 1280; }
-static int GetScreenHeight() { return 720; }
-static void ShowCursor() {}
-static void HideCursor() {}
-static int IsKeyDown(int key) { return 0; }
-#endif
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition
-//----------------------------------------------------------------------------------
-
-// Select camera mode (multiple camera modes available)
-// TODO: Review hardcoded values when changing modes...
-void SetCameraMode(int mode)
-{
-    if ((cameraMode == CAMERA_FIRST_PERSON) && (mode == CAMERA_FREE))
-    {
-        cameraMode = CAMERA_THIRD_PERSON;
-        cameraTargetDistance = 5.0f;
-        cameraAngle.y = -40*DEG2RAD;
-        ProcessCamera(&internalCamera, &internalCamera.position);
-    }
-    else if ((cameraMode == CAMERA_FIRST_PERSON) && (mode == CAMERA_ORBITAL))
-    {
-        cameraMode = CAMERA_THIRD_PERSON;
-        cameraTargetDistance = 5.0f;
-        cameraAngle.y = -40*DEG2RAD;
-        ProcessCamera(&internalCamera, &internalCamera.position);
-    }
-    else if ((cameraMode == CAMERA_CUSTOM) && (mode == CAMERA_FREE))
-    {
-        cameraTargetDistance = 10.0f;
-        cameraAngle.x = 45*DEG2RAD;
-        cameraAngle.y = -40*DEG2RAD;
-        internalCamera.target = (Vector3){ 0.0f, 0.0f, 0.0f };
-        ProcessCamera(&internalCamera, &internalCamera.position);
-        
-        ShowCursor();
-    }
-    else if ((cameraMode == CAMERA_CUSTOM) && (mode == CAMERA_ORBITAL))
-    {
-        cameraTargetDistance = 10.0f;
-        cameraAngle.x = 225*DEG2RAD;
-        cameraAngle.y = -40*DEG2RAD;
-        internalCamera.target = (Vector3){ 0.0f, 0.0f, 0.0f };
-        ProcessCamera(&internalCamera, &internalCamera.position);
-    }
-
-    cameraMode = mode;
-}
-
-// Update camera (player position is ignored)
-void UpdateCamera(Camera *camera)
-{
-    Vector3 position = { 0.0f, 0.0f, 0.0f };
-    
-    // Process internal camera and player position (if required)
-    if (cameraMode != CAMERA_CUSTOM) ProcessCamera(&internalCamera, &position);
-
-    *camera = internalCamera;
-}
-
-// Update camera and player position (1st person and 3rd person cameras)
-void UpdateCameraPlayer(Camera *camera, Vector3 *position)
-{
-    // Process internal camera and player position (if required)
-    if (cameraMode != CAMERA_CUSTOM) ProcessCamera(&internalCamera, position);
-
-    *camera = internalCamera;
-}
-
-// Set internal camera position
-void SetCameraPosition(Vector3 position)
-{
-    internalCamera.position = position;
-    
-    Vector3 v1 = internalCamera.position;
-    Vector3 v2 = internalCamera.target;
-    
-    float dx = v2.x - v1.x;
-    float dy = v2.y - v1.y;
-    float dz = v2.z - v1.z;
-    
-    cameraTargetDistance = sqrt(dx*dx + dy*dy + dz*dz);
-}
-
-// Set internal camera target
-void SetCameraTarget(Vector3 target)
-{
-    internalCamera.target = target;
-    
-    Vector3 v1 = internalCamera.position;
-    Vector3 v2 = internalCamera.target;
-    
-    float dx = v2.x - v1.x;
-    float dy = v2.y - v1.y;
-    float dz = v2.z - v1.z;
-    
-    cameraTargetDistance = sqrt(dx*dx + dy*dy + dz*dz);
-}
-
-// Set internal camera fovy
-void SetCameraFovy(float fovy)
-{
-    internalCamera.fovy = fovy;
-}
-
-// Set camera pan key to combine with mouse movement (free camera)
-void SetCameraPanControl(int panKey)
-{
-    panControlKey = panKey;
-}
-
-// Set camera alt key to combine with mouse movement (free camera)
-void SetCameraAltControl(int altKey)
-{
-    altControlKey = altKey;
-}
-
-// Set camera smooth zoom key to combine with mouse (free camera)
-void SetCameraSmoothZoomControl(int szKey)
-{
-    smoothZoomControlKey = szKey;
-}
-
-// Set camera move controls (1st person and 3rd person cameras)
-void SetCameraMoveControls(int frontKey, int backKey, int leftKey, int rightKey, int upKey, int downKey)
-{
-    cameraMoveControl[MOVE_FRONT] = frontKey;
-    cameraMoveControl[MOVE_LEFT] = leftKey;
-    cameraMoveControl[MOVE_BACK] = backKey;
-    cameraMoveControl[MOVE_RIGHT] = rightKey;
-    cameraMoveControl[MOVE_UP] = upKey;
-    cameraMoveControl[MOVE_DOWN] = downKey;
-}
-
-// Set camera mouse sensitivity (1st person and 3rd person cameras)
-void SetCameraMouseSensitivity(float sensitivity)
-{
-    mouseSensitivity = (sensitivity/10000.0f);
-}
-
-//----------------------------------------------------------------------------------
-// Module specific Functions Definition
-//----------------------------------------------------------------------------------
-
-// Process desired camera mode and controls
-// NOTE: Camera controls depend on some raylib functions:
-//       Mouse: GetMousePosition(), SetMousePosition(), IsMouseButtonDown(), GetMouseWheelMove()
-//       System: GetScreenWidth(), GetScreenHeight(), ShowCursor(), HideCursor()
-//       Keys:  IsKeyDown()
-static void ProcessCamera(Camera *camera, Vector3 *playerPosition)
-{
-    // Mouse movement detection
-    Vector2 mousePosition = GetMousePosition();
-    int mouseWheelMove = GetMouseWheelMove();
-    int panKey = IsMouseButtonDown(panControlKey);    // bool value
-    
-    int screenWidth = GetScreenWidth();
-    int screenHeight = GetScreenHeight();
-    
-    if ((cameraMode != CAMERA_FREE) && (cameraMode != CAMERA_ORBITAL))
-    {
-        HideCursor();
-
-        if (mousePosition.x < screenHeight/3) SetMousePosition((Vector2){ screenWidth - screenHeight/3, mousePosition.y});
-        else if (mousePosition.y < screenHeight/3) SetMousePosition((Vector2){ mousePosition.x, screenHeight - screenHeight/3});
-        else if (mousePosition.x > screenWidth - screenHeight/3) SetMousePosition((Vector2) { screenHeight/3, mousePosition.y});
-        else if (mousePosition.y > screenHeight - screenHeight/3) SetMousePosition((Vector2){ mousePosition.x, screenHeight/3});
-        else
-        {
-            cameraMouseVariation.x = mousePosition.x - cameraMousePosition.x;
-            cameraMouseVariation.y = mousePosition.y - cameraMousePosition.y;
-        }
-    }
-    else
-    {
-        ShowCursor();
-
-        cameraMouseVariation.x = mousePosition.x - cameraMousePosition.x;
-        cameraMouseVariation.y = mousePosition.y - cameraMousePosition.y;
-    }
-
-	// NOTE: We GetMousePosition() again because it can be modified by a previous SetMousePosition() call
-	// If using directly mousePosition variable we have problems on CAMERA_FIRST_PERSON and CAMERA_THIRD_PERSON
-    cameraMousePosition = GetMousePosition();
-
-    // Support for multiple automatic camera modes
-    switch (cameraMode)
-    {
-        case CAMERA_FREE:
-        {
-            // Camera zoom
-            if ((cameraTargetDistance < FREE_CAMERA_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
-            {
-                cameraTargetDistance -= (mouseWheelMove*CAMERA_SCROLL_SENSITIVITY);
-
-                if (cameraTargetDistance > FREE_CAMERA_DISTANCE_MAX_CLAMP) cameraTargetDistance = FREE_CAMERA_DISTANCE_MAX_CLAMP;
-            }
-            // Camera looking down
-            else if ((camera->position.y > camera->target.y) && (cameraTargetDistance == FREE_CAMERA_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
-            {
-                camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance;
-                camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance;
-                camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance;
-            }
-            else if ((camera->position.y > camera->target.y) && (camera->target.y >= 0))
-            {
-                camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance;
-                camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance;
-                camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance;
-
-                // if (camera->target.y < 0) camera->target.y = -0.001;
-            }
-            else if ((camera->position.y > camera->target.y) && (camera->target.y < 0) && (mouseWheelMove > 0))
-            {
-                cameraTargetDistance -= (mouseWheelMove*CAMERA_SCROLL_SENSITIVITY);
-                if (cameraTargetDistance < FREE_CAMERA_DISTANCE_MIN_CLAMP) cameraTargetDistance = FREE_CAMERA_DISTANCE_MIN_CLAMP;
-            }
-            // Camera looking up
-            else if ((camera->position.y < camera->target.y) && (cameraTargetDistance == FREE_CAMERA_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
-            {
-                camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance;
-                camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance;
-                camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance;
-            }
-            else if ((camera->position.y < camera->target.y) && (camera->target.y <= 0))
-            {
-                camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance;
-                camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance;
-                camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance;
-
-                // if (camera->target.y > 0) camera->target.y = 0.001;
-            }
-            else if ((camera->position.y < camera->target.y) && (camera->target.y > 0) && (mouseWheelMove > 0))
-            {
-                cameraTargetDistance -= (mouseWheelMove*CAMERA_SCROLL_SENSITIVITY);
-                if (cameraTargetDistance < FREE_CAMERA_DISTANCE_MIN_CLAMP) cameraTargetDistance = FREE_CAMERA_DISTANCE_MIN_CLAMP;
-            }
-
-            // Inputs
-            if (IsKeyDown(altControlKey))
-            {
-                if (IsKeyDown(smoothZoomControlKey))
-                {
-                    // Camera smooth zoom
-                    if (panKey) cameraTargetDistance += (cameraMouseVariation.y*FREE_CAMERA_SMOOTH_ZOOM_SENSITIVITY);
-                }
-                // Camera orientation calculation
-                else if (panKey)
-                {
-                    // Camera orientation calculation
-                    // Get the mouse sensitivity
-                    cameraAngle.x += cameraMouseVariation.x*-FREE_CAMERA_MOUSE_SENSITIVITY;
-                    cameraAngle.y += cameraMouseVariation.y*-FREE_CAMERA_MOUSE_SENSITIVITY;
-
-                    // Angle clamp
-                    if (cameraAngle.y > FREE_CAMERA_MIN_CLAMP*DEG2RAD) cameraAngle.y = FREE_CAMERA_MIN_CLAMP*DEG2RAD;
-                    else if (cameraAngle.y < FREE_CAMERA_MAX_CLAMP*DEG2RAD) cameraAngle.y = FREE_CAMERA_MAX_CLAMP*DEG2RAD;
-                }
-            }
-            // Paning
-            else if (panKey)
-            {
-                camera->target.x += ((cameraMouseVariation.x*-FREE_CAMERA_MOUSE_SENSITIVITY)*cos(cameraAngle.x) + (cameraMouseVariation.y*FREE_CAMERA_MOUSE_SENSITIVITY)*sin(cameraAngle.x)*sin(cameraAngle.y))*(cameraTargetDistance/FREE_CAMERA_PANNING_DIVIDER);
-                camera->target.y += ((cameraMouseVariation.y*FREE_CAMERA_MOUSE_SENSITIVITY)*cos(cameraAngle.y))*(cameraTargetDistance/FREE_CAMERA_PANNING_DIVIDER);
-                camera->target.z += ((cameraMouseVariation.x*FREE_CAMERA_MOUSE_SENSITIVITY)*sin(cameraAngle.x) + (cameraMouseVariation.y*FREE_CAMERA_MOUSE_SENSITIVITY)*cos(cameraAngle.x)*sin(cameraAngle.y))*(cameraTargetDistance/FREE_CAMERA_PANNING_DIVIDER);
-            }
-
-            // Focus to center
-            // TODO: Move this function out of this module?
-            if (IsKeyDown('Z')) camera->target = (Vector3){ 0.0f, 0.0f, 0.0f };
-
-            // Camera position update
-            camera->position.x = sin(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.x;
-
-            if (cameraAngle.y <= 0.0f) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y;
-            else camera->position.y = -sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y;
-
-            camera->position.z = cos(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.z;
-
-        } break;
-        case CAMERA_ORBITAL:
-        {
-            cameraAngle.x += ORBITAL_CAMERA_SPEED;
-
-            // Camera zoom
-            cameraTargetDistance -= (mouseWheelMove*CAMERA_SCROLL_SENSITIVITY);
-            
-            // Camera distance clamp
-            if (cameraTargetDistance < THIRD_PERSON_DISTANCE_CLAMP) cameraTargetDistance = THIRD_PERSON_DISTANCE_CLAMP;
-
-            // Focus to center
-            if (IsKeyDown('Z')) camera->target = (Vector3){ 0.0f, 0.0f, 0.0f };
-
-            // Camera position update
-            camera->position.x = sin(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.x;
-
-            if (cameraAngle.y <= 0.0f) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y;
-            else camera->position.y = -sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y;
-
-            camera->position.z = cos(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.z;
-
-        } break;
-        case CAMERA_FIRST_PERSON:
-        case CAMERA_THIRD_PERSON:
-        {
-            bool isMoving = false;
-
-            // Keyboard inputs
-            if (IsKeyDown(cameraMoveControl[MOVE_FRONT]))
-            {
-                playerPosition->x -= sin(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER;
-                playerPosition->z -= cos(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER;
-                
-                if (!cameraUseGravity) camera->position.y += sin(cameraAngle.y)/PLAYER_MOVEMENT_DIVIDER;
-
-                isMoving = true;
-            }
-            else if (IsKeyDown(cameraMoveControl[MOVE_BACK]))
-            {
-                playerPosition->x += sin(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER;
-                playerPosition->z += cos(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER;
-                
-                if (!cameraUseGravity) camera->position.y -= sin(cameraAngle.y)/PLAYER_MOVEMENT_DIVIDER;
-
-                isMoving = true;
-            }
-
-            if (IsKeyDown(cameraMoveControl[MOVE_LEFT]))
-            {
-                playerPosition->x -= cos(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER;
-                playerPosition->z += sin(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER;
-
-                isMoving = true;
-            }
-            else if (IsKeyDown(cameraMoveControl[MOVE_RIGHT]))
-            {
-                playerPosition->x += cos(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER;
-                playerPosition->z -= sin(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER;
-
-                isMoving = true;
-            }
-
-            if (IsKeyDown(cameraMoveControl[MOVE_UP]))
-            {
-                if (!cameraUseGravity) playerPosition->y += 1.0f/PLAYER_MOVEMENT_DIVIDER;
-            }
-            else if (IsKeyDown(cameraMoveControl[MOVE_DOWN]))
-            {
-                if (!cameraUseGravity) playerPosition->y -= 1.0f/PLAYER_MOVEMENT_DIVIDER;
-            }
-
-            if (cameraMode == CAMERA_THIRD_PERSON)
-            {
-                // Camera orientation calculation
-                cameraAngle.x += cameraMouseVariation.x*-mouseSensitivity;
-                cameraAngle.y += cameraMouseVariation.y*-mouseSensitivity;
-
-                // Angle clamp
-                if (cameraAngle.y > THIRD_PERSON_MIN_CLAMP*DEG2RAD) cameraAngle.y = THIRD_PERSON_MIN_CLAMP*DEG2RAD;
-                else if (cameraAngle.y < THIRD_PERSON_MAX_CLAMP*DEG2RAD) cameraAngle.y = THIRD_PERSON_MAX_CLAMP*DEG2RAD;
-
-                // Camera zoom
-                cameraTargetDistance -= (mouseWheelMove*CAMERA_SCROLL_SENSITIVITY);
-
-                // Camera distance clamp
-                if (cameraTargetDistance < THIRD_PERSON_DISTANCE_CLAMP) cameraTargetDistance = THIRD_PERSON_DISTANCE_CLAMP;
-
-                // Camera is always looking at player
-                camera->target.x = playerPosition->x + THIRD_PERSON_OFFSET.x*cos(cameraAngle.x) + THIRD_PERSON_OFFSET.z*sin(cameraAngle.x);
-                camera->target.y = playerPosition->y + PLAYER_HEIGHT*FIRST_PERSON_HEIGHT_RELATIVE_EYES_POSITION + THIRD_PERSON_OFFSET.y;
-                camera->target.z = playerPosition->z + THIRD_PERSON_OFFSET.z*sin(cameraAngle.x) - THIRD_PERSON_OFFSET.x*sin(cameraAngle.x);
-
-                // Camera position update
-                camera->position.x = sin(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.x;
-
-                if (cameraAngle.y <= 0.0f) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y;
-                else camera->position.y = -sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y;
-
-                camera->position.z = cos(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.z;
-            }
-            else    // CAMERA_FIRST_PERSON
-            {
-                if (isMoving) cameraMoveCounter++;
-
-                // Camera orientation calculation
-                cameraAngle.x += (cameraMouseVariation.x * -mouseSensitivity);
-                cameraAngle.y += (cameraMouseVariation.y * -mouseSensitivity);
-
-                // Angle clamp
-                if (cameraAngle.y > FIRST_PERSON_MIN_CLAMP*DEG2RAD) cameraAngle.y = FIRST_PERSON_MIN_CLAMP*DEG2RAD;
-                else if (cameraAngle.y < FIRST_PERSON_MAX_CLAMP*DEG2RAD) cameraAngle.y = FIRST_PERSON_MAX_CLAMP*DEG2RAD;
-
-                // Camera is always looking at player
-                camera->target.x = camera->position.x - sin(cameraAngle.x)*FIRST_PERSON_FOCUS_DISTANCE;
-                camera->target.y = camera->position.y + sin(cameraAngle.y)*FIRST_PERSON_FOCUS_DISTANCE;
-                camera->target.z = camera->position.z - cos(cameraAngle.x)*FIRST_PERSON_FOCUS_DISTANCE;
-
-                camera->position.x = playerPosition->x;
-                camera->position.y = (playerPosition->y + PLAYER_HEIGHT*FIRST_PERSON_HEIGHT_RELATIVE_EYES_POSITION) - sin(cameraMoveCounter/FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER)/FIRST_PERSON_STEP_DIVIDER;
-                camera->position.z = playerPosition->z;
-
-                camera->up.x = sin(cameraMoveCounter/(FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/FIRST_PERSON_WAVING_DIVIDER;
-                camera->up.z = -sin(cameraMoveCounter/(FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/FIRST_PERSON_WAVING_DIVIDER;
-            }
-        } break;
-        default: break;
-    }
-}

+ 556 - 30
src/camera.h

@@ -2,7 +2,19 @@
 *
 *   raylib Camera System - Camera Modes Setup and Control Functions
 *
-*   Copyright (c) 2015 Marc Palau and Ramon Santamaria
+*   #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.
+*
+*   NOTE: Memory footprint of this library is aproximately 112 bytes
+*
+*   Initial design by Marc Palau (2014)
+*   Reviewed by Ramon Santamaria (2015-2016)
 *
 *   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.
@@ -24,13 +36,6 @@
 #ifndef CAMERA_H
 #define CAMERA_H
 
-#ifndef PI
-    #define PI 3.14159265358979323846
-#endif
-
-#define DEG2RAD (PI/180.0f)
-#define RAD2DEG (180.0f/PI)
-
 //----------------------------------------------------------------------------------
 // Defines and Macros
 //----------------------------------------------------------------------------------
@@ -40,28 +45,30 @@
 // Types and Structures Definition
 // NOTE: Below types are required for CAMERA_STANDALONE usage
 //----------------------------------------------------------------------------------
-// Camera modes
-typedef enum { CAMERA_CUSTOM = 0, CAMERA_FREE, CAMERA_ORBITAL, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON } CameraMode;
-
-// 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 Camera {
-    Vector3 position;
-    Vector3 target;
-    Vector3 up;
-} Camera;
+#if defined(CAMERA_STANDALONE)
+    // Camera modes
+    typedef enum { CAMERA_CUSTOM = 0, CAMERA_FREE, CAMERA_ORBITAL, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON } CameraMode;
+
+    // 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 Camera {
+        Vector3 position;
+        Vector3 target;
+        Vector3 up;
+    } Camera;
+#endif
 
 #ifdef __cplusplus
 extern "C" {            // Prevents name mangling of functions
@@ -75,6 +82,7 @@ extern "C" {            // Prevents name mangling of functions
 //----------------------------------------------------------------------------------
 // Module Functions Declaration
 //----------------------------------------------------------------------------------
+#if defined(CAMERA_STANDALONE)
 void SetCameraMode(int mode);                               // Set camera mode (multiple camera modes available)
 void UpdateCamera(Camera *camera);                          // Update camera (player position is ignored)
 void UpdateCameraPlayer(Camera *camera, Vector3 *position); // Update camera and player position (1st person and 3rd person cameras)
@@ -91,9 +99,527 @@ void SetCameraMoveControls(int frontKey, int backKey,
                            int leftKey, int rightKey, 
                            int upKey, int downKey);         // Set camera move controls (1st person and 3rd person cameras)
 void SetCameraMouseSensitivity(float sensitivity);          // Set camera mouse sensitivity (1st person and 3rd person cameras)
+#endif
 
 #ifdef __cplusplus
 }
 #endif
 
 #endif // CAMERA_H
+
+
+/***********************************************************************************
+*
+*   CAMERA IMPLEMENTATION
+*
+************************************************************************************/
+
+#if defined(CAMERA_IMPLEMENTATION)
+
+#include <math.h>               // Required for: sqrt(), sin(), cos()
+
+#ifndef PI
+    #define PI 3.14159265358979323846
+#endif
+
+#ifndef DEG2RAD
+    #define DEG2RAD (PI/180.0f)
+#endif
+
+#ifndef RAD2DEG
+    #define RAD2DEG (180.0f/PI)
+#endif
+
+//----------------------------------------------------------------------------------
+// Defines and Macros
+//----------------------------------------------------------------------------------
+// CAMERA_GENERIC
+#define CAMERA_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
+
+// FIRST_PERSON
+//#define CAMERA_FIRST_PERSON_MOUSE_SENSITIVITY           0.003f
+#define CAMERA_FIRST_PERSON_FOCUS_DISTANCE              25.0f
+#define CAMERA_FIRST_PERSON_MIN_CLAMP                   85.0f
+#define CAMERA_FIRST_PERSON_MAX_CLAMP                  -85.0f
+
+#define CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER  5.0f
+#define CAMERA_FIRST_PERSON_STEP_DIVIDER                30.0f
+#define CAMERA_FIRST_PERSON_WAVING_DIVIDER              200.0f
+
+#define CAMERA_FIRST_PERSON_HEIGHT_RELATIVE_EYES_POSITION  0.85f
+
+// 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_WIDTH                        0.4f
+#define PLAYER_HEIGHT                       0.9f
+#define PLAYER_DEPTH                        0.4f
+#define PLAYER_MOVEMENT_DIVIDER             20.0f
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+// Camera move modes (first person and third person cameras)
+typedef enum { MOVE_FRONT = 0, MOVE_LEFT, MOVE_BACK, MOVE_RIGHT, MOVE_UP, MOVE_DOWN } CameraMove;
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+static Camera internalCamera = {{ 2.0f, 0.0f, 2.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f };
+
+static Vector2 cameraAngle = { 0.0f, 0.0f };
+static float cameraTargetDistance = 5.0f;
+static Vector2 cameraMousePosition = { 0.0f, 0.0f };
+static Vector2 cameraMouseVariation = { 0.0f, 0.0f };
+
+static int cameraMoveControl[6]  = { 'W', 'A', 'S', 'D', 'E', 'Q' };
+static int cameraPanControlKey = 2;                   // raylib: MOUSE_MIDDLE_BUTTON
+static int cameraAltControlKey = 342;                 // raylib: KEY_LEFT_ALT
+static int cameraSmoothZoomControlKey = 341;          // raylib: KEY_LEFT_CONTROL
+
+static int cameraMoveCounter = 0;                     // Used for 1st person swinging movement
+static float cameraMouseSensitivity = 0.003f;         // How sensible is camera movement to mouse movement
+
+static int cameraMode = CAMERA_CUSTOM;                // Current internal camera mode
+
+//----------------------------------------------------------------------------------
+// Module specific Functions Declaration
+//----------------------------------------------------------------------------------
+static void ProcessCamera(Camera *camera, Vector3 *playerPosition);
+
+#if defined(CAMERA_STANDALONE)
+// NOTE: Camera controls depend on some raylib input functions
+// TODO: Set your own input functions (used in ProcessCamera())
+static Vector2 GetMousePosition() { return (Vector2){ 0.0f, 0.0f }; }
+static void SetMousePosition(Vector2 pos) {} 
+static int IsMouseButtonDown(int button) { return 0;}
+static int GetMouseWheelMove() { return 0; }
+static int GetScreenWidth() { return 1280; }
+static int GetScreenHeight() { return 720; }
+static void ShowCursor() {}
+static void HideCursor() {}
+static int IsKeyDown(int key) { return 0; }
+#endif
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+
+// Select camera mode (multiple camera modes available)
+// TODO: Review hardcoded values when changing modes...
+void SetCameraMode(int mode)
+{
+    if ((cameraMode == CAMERA_FIRST_PERSON) && (mode == CAMERA_FREE))
+    {
+        cameraMode = CAMERA_THIRD_PERSON;
+        cameraTargetDistance = 5.0f;
+        cameraAngle.y = -40*DEG2RAD;
+        ProcessCamera(&internalCamera, &internalCamera.position);
+    }
+    else if ((cameraMode == CAMERA_FIRST_PERSON) && (mode == CAMERA_ORBITAL))
+    {
+        cameraMode = CAMERA_THIRD_PERSON;
+        cameraTargetDistance = 5.0f;
+        cameraAngle.y = -40*DEG2RAD;
+        ProcessCamera(&internalCamera, &internalCamera.position);
+    }
+    else if ((cameraMode == CAMERA_CUSTOM) && (mode == CAMERA_FREE))
+    {
+        cameraTargetDistance = 10.0f;
+        cameraAngle.x = 45*DEG2RAD;
+        cameraAngle.y = -40*DEG2RAD;
+        internalCamera.target = (Vector3){ 0.0f, 0.0f, 0.0f };
+        ProcessCamera(&internalCamera, &internalCamera.position);
+        
+        ShowCursor();
+    }
+    else if ((cameraMode == CAMERA_CUSTOM) && (mode == CAMERA_ORBITAL))
+    {
+        cameraTargetDistance = 10.0f;
+        cameraAngle.x = 225*DEG2RAD;
+        cameraAngle.y = -40*DEG2RAD;
+        internalCamera.target = (Vector3){ 0.0f, 0.0f, 0.0f };
+        ProcessCamera(&internalCamera, &internalCamera.position);
+    }
+
+    cameraMode = mode;
+}
+
+// Update camera (player position is ignored)
+void UpdateCamera(Camera *camera)
+{
+    Vector3 position = { 0.0f, 0.0f, 0.0f };
+    
+    // Process internal camera and player position (if required)
+    if (cameraMode != CAMERA_CUSTOM) ProcessCamera(&internalCamera, &position);
+
+    *camera = internalCamera;
+}
+
+// Update camera and player position (1st person and 3rd person cameras)
+void UpdateCameraPlayer(Camera *camera, Vector3 *position)
+{
+    // Process internal camera and player position (if required)
+    if (cameraMode != CAMERA_CUSTOM) ProcessCamera(&internalCamera, position);
+
+    *camera = internalCamera;
+}
+
+// Set internal camera position
+void SetCameraPosition(Vector3 position)
+{
+    internalCamera.position = position;
+    
+    Vector3 v1 = internalCamera.position;
+    Vector3 v2 = internalCamera.target;
+    
+    float dx = v2.x - v1.x;
+    float dy = v2.y - v1.y;
+    float dz = v2.z - v1.z;
+    
+    cameraTargetDistance = sqrt(dx*dx + dy*dy + dz*dz);
+}
+
+// Set internal camera target
+void SetCameraTarget(Vector3 target)
+{
+    internalCamera.target = target;
+    
+    Vector3 v1 = internalCamera.position;
+    Vector3 v2 = internalCamera.target;
+    
+    float dx = v2.x - v1.x;
+    float dy = v2.y - v1.y;
+    float dz = v2.z - v1.z;
+    
+    cameraTargetDistance = sqrt(dx*dx + dy*dy + dz*dz);
+}
+
+// Set internal camera fovy
+void SetCameraFovy(float fovy)
+{
+    internalCamera.fovy = fovy;
+}
+
+// Set camera pan key to combine with mouse movement (free camera)
+void SetCameraPanControl(int panKey)
+{
+    cameraPanControlKey = panKey;
+}
+
+// Set camera alt key to combine with mouse movement (free camera)
+void SetCameraAltControl(int altKey)
+{
+    cameraAltControlKey = altKey;
+}
+
+// Set camera smooth zoom key to combine with mouse (free camera)
+void SetCameraSmoothZoomControl(int szKey)
+{
+    cameraSmoothZoomControlKey = szKey;
+}
+
+// Set camera move controls (1st person and 3rd person cameras)
+void SetCameraMoveControls(int frontKey, int backKey, int leftKey, int rightKey, int upKey, int downKey)
+{
+    cameraMoveControl[MOVE_FRONT] = frontKey;
+    cameraMoveControl[MOVE_LEFT] = leftKey;
+    cameraMoveControl[MOVE_BACK] = backKey;
+    cameraMoveControl[MOVE_RIGHT] = rightKey;
+    cameraMoveControl[MOVE_UP] = upKey;
+    cameraMoveControl[MOVE_DOWN] = downKey;
+}
+
+// Set camera mouse sensitivity (1st person and 3rd person cameras)
+void SetCameracameraMouseSensitivity(float sensitivity)
+{
+    cameraMouseSensitivity = (sensitivity/10000.0f);
+}
+
+//----------------------------------------------------------------------------------
+// Module specific Functions Definition
+//----------------------------------------------------------------------------------
+
+// Process desired camera mode and controls
+// NOTE: Camera controls depend on some raylib functions:
+//       Mouse: GetMousePosition(), SetMousePosition(), IsMouseButtonDown(), GetMouseWheelMove()
+//       System: GetScreenWidth(), GetScreenHeight(), ShowCursor(), HideCursor()
+//       Keys:  IsKeyDown()
+static void ProcessCamera(Camera *camera, Vector3 *playerPosition)
+{
+    // Mouse movement detection
+    Vector2 mousePosition = GetMousePosition();
+    int mouseWheelMove = GetMouseWheelMove();
+    int panKey = IsMouseButtonDown(cameraPanControlKey);    // bool value
+    
+    int screenWidth = GetScreenWidth();
+    int screenHeight = GetScreenHeight();
+    
+    if ((cameraMode != CAMERA_FREE) && (cameraMode != CAMERA_ORBITAL))
+    {
+        HideCursor();
+
+        if (mousePosition.x < screenHeight/3) SetMousePosition((Vector2){ screenWidth - screenHeight/3, mousePosition.y});
+        else if (mousePosition.y < screenHeight/3) SetMousePosition((Vector2){ mousePosition.x, screenHeight - screenHeight/3});
+        else if (mousePosition.x > screenWidth - screenHeight/3) SetMousePosition((Vector2) { screenHeight/3, mousePosition.y});
+        else if (mousePosition.y > screenHeight - screenHeight/3) SetMousePosition((Vector2){ mousePosition.x, screenHeight/3});
+        else
+        {
+            cameraMouseVariation.x = mousePosition.x - cameraMousePosition.x;
+            cameraMouseVariation.y = mousePosition.y - cameraMousePosition.y;
+        }
+    }
+    else
+    {
+        ShowCursor();
+
+        cameraMouseVariation.x = mousePosition.x - cameraMousePosition.x;
+        cameraMouseVariation.y = mousePosition.y - cameraMousePosition.y;
+    }
+
+	// NOTE: We GetMousePosition() again because it can be modified by a previous SetMousePosition() call
+	// If using directly mousePosition variable we have problems on CAMERA_FIRST_PERSON and CAMERA_THIRD_PERSON
+    cameraMousePosition = GetMousePosition();
+
+    // Support for multiple automatic camera modes
+    switch (cameraMode)
+    {
+        case CAMERA_FREE:
+        {
+            // Camera zoom
+            if ((cameraTargetDistance < CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
+            {
+                cameraTargetDistance -= (mouseWheelMove*CAMERA_SCROLL_SENSITIVITY);
+
+                if (cameraTargetDistance > CAMERA_FREE_DISTANCE_MAX_CLAMP) cameraTargetDistance = CAMERA_FREE_DISTANCE_MAX_CLAMP;
+            }
+            // Camera looking down
+            else if ((camera->position.y > camera->target.y) && (cameraTargetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
+            {
+                camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance;
+                camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance;
+                camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance;
+            }
+            else if ((camera->position.y > camera->target.y) && (camera->target.y >= 0))
+            {
+                camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance;
+                camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance;
+                camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance;
+
+                // if (camera->target.y < 0) camera->target.y = -0.001;
+            }
+            else if ((camera->position.y > camera->target.y) && (camera->target.y < 0) && (mouseWheelMove > 0))
+            {
+                cameraTargetDistance -= (mouseWheelMove*CAMERA_SCROLL_SENSITIVITY);
+                if (cameraTargetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) cameraTargetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP;
+            }
+            // Camera looking up
+            else if ((camera->position.y < camera->target.y) && (cameraTargetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
+            {
+                camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance;
+                camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance;
+                camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance;
+            }
+            else if ((camera->position.y < camera->target.y) && (camera->target.y <= 0))
+            {
+                camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance;
+                camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance;
+                camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance;
+
+                // if (camera->target.y > 0) camera->target.y = 0.001;
+            }
+            else if ((camera->position.y < camera->target.y) && (camera->target.y > 0) && (mouseWheelMove > 0))
+            {
+                cameraTargetDistance -= (mouseWheelMove*CAMERA_SCROLL_SENSITIVITY);
+                if (cameraTargetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) cameraTargetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP;
+            }
+
+            // Inputs
+            if (IsKeyDown(cameraAltControlKey))
+            {
+                if (IsKeyDown(cameraSmoothZoomControlKey))
+                {
+                    // Camera smooth zoom
+                    if (panKey) cameraTargetDistance += (cameraMouseVariation.y*CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY);
+                }
+                // Camera orientation calculation
+                else if (panKey)
+                {
+                    // Camera orientation calculation
+                    // Get the mouse sensitivity
+                    cameraAngle.x += cameraMouseVariation.x*-CAMERA_FREE_MOUSE_SENSITIVITY;
+                    cameraAngle.y += cameraMouseVariation.y*-CAMERA_FREE_MOUSE_SENSITIVITY;
+
+                    // Angle clamp
+                    if (cameraAngle.y > CAMERA_FREE_MIN_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FREE_MIN_CLAMP*DEG2RAD;
+                    else if (cameraAngle.y < CAMERA_FREE_MAX_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FREE_MAX_CLAMP*DEG2RAD;
+                }
+            }
+            // Paning
+            else if (panKey)
+            {
+                camera->target.x += ((cameraMouseVariation.x*-CAMERA_FREE_MOUSE_SENSITIVITY)*cos(cameraAngle.x) + (cameraMouseVariation.y*CAMERA_FREE_MOUSE_SENSITIVITY)*sin(cameraAngle.x)*sin(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER);
+                camera->target.y += ((cameraMouseVariation.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cos(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER);
+                camera->target.z += ((cameraMouseVariation.x*CAMERA_FREE_MOUSE_SENSITIVITY)*sin(cameraAngle.x) + (cameraMouseVariation.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cos(cameraAngle.x)*sin(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER);
+            }
+
+            // Focus to center
+            // TODO: Move this function out of this module?
+            if (IsKeyDown('Z')) camera->target = (Vector3){ 0.0f, 0.0f, 0.0f };
+
+            // Camera position update
+            camera->position.x = sin(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.x;
+
+            if (cameraAngle.y <= 0.0f) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y;
+            else camera->position.y = -sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y;
+
+            camera->position.z = cos(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.z;
+
+        } break;
+        case CAMERA_ORBITAL:
+        {
+            cameraAngle.x += CAMERA_ORBITAL_SPEED;
+
+            // Camera zoom
+            cameraTargetDistance -= (mouseWheelMove*CAMERA_SCROLL_SENSITIVITY);
+            
+            // Camera distance clamp
+            if (cameraTargetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) cameraTargetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP;
+
+            // Focus to center
+            if (IsKeyDown('Z')) camera->target = (Vector3){ 0.0f, 0.0f, 0.0f };
+
+            // Camera position update
+            camera->position.x = sin(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.x;
+
+            if (cameraAngle.y <= 0.0f) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y;
+            else camera->position.y = -sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y;
+
+            camera->position.z = cos(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.z;
+
+        } break;
+        case CAMERA_FIRST_PERSON:
+        case CAMERA_THIRD_PERSON:
+        {
+            bool isMoving = false;
+
+            // Keyboard inputs
+            if (IsKeyDown(cameraMoveControl[MOVE_FRONT]))
+            {
+                playerPosition->x -= sin(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER;
+                playerPosition->z -= cos(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER;
+                
+                camera->position.y += sin(cameraAngle.y)/PLAYER_MOVEMENT_DIVIDER;
+
+                isMoving = true;
+            }
+            else if (IsKeyDown(cameraMoveControl[MOVE_BACK]))
+            {
+                playerPosition->x += sin(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER;
+                playerPosition->z += cos(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER;
+                
+                camera->position.y -= sin(cameraAngle.y)/PLAYER_MOVEMENT_DIVIDER;
+
+                isMoving = true;
+            }
+
+            if (IsKeyDown(cameraMoveControl[MOVE_LEFT]))
+            {
+                playerPosition->x -= cos(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER;
+                playerPosition->z += sin(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER;
+
+                isMoving = true;
+            }
+            else if (IsKeyDown(cameraMoveControl[MOVE_RIGHT]))
+            {
+                playerPosition->x += cos(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER;
+                playerPosition->z -= sin(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER;
+
+                isMoving = true;
+            }
+
+            if (IsKeyDown(cameraMoveControl[MOVE_UP]))
+            {
+                playerPosition->y += 1.0f/PLAYER_MOVEMENT_DIVIDER;
+            }
+            else if (IsKeyDown(cameraMoveControl[MOVE_DOWN]))
+            {
+                playerPosition->y -= 1.0f/PLAYER_MOVEMENT_DIVIDER;
+            }
+
+            if (cameraMode == CAMERA_THIRD_PERSON)
+            {
+                // Camera orientation calculation
+                cameraAngle.x += cameraMouseVariation.x*-cameraMouseSensitivity;
+                cameraAngle.y += cameraMouseVariation.y*-cameraMouseSensitivity;
+
+                // Angle clamp
+                if (cameraAngle.y > CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD;
+                else if (cameraAngle.y < CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD;
+
+                // Camera zoom
+                cameraTargetDistance -= (mouseWheelMove*CAMERA_SCROLL_SENSITIVITY);
+
+                // Camera distance clamp
+                if (cameraTargetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) cameraTargetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP;
+
+                // Camera is always looking at player
+                camera->target.x = playerPosition->x + CAMERA_THIRD_PERSON_OFFSET.x*cos(cameraAngle.x) + CAMERA_THIRD_PERSON_OFFSET.z*sin(cameraAngle.x);
+                camera->target.y = playerPosition->y + PLAYER_HEIGHT*CAMERA_FIRST_PERSON_HEIGHT_RELATIVE_EYES_POSITION + CAMERA_THIRD_PERSON_OFFSET.y;
+                camera->target.z = playerPosition->z + CAMERA_THIRD_PERSON_OFFSET.z*sin(cameraAngle.x) - CAMERA_THIRD_PERSON_OFFSET.x*sin(cameraAngle.x);
+
+                // Camera position update
+                camera->position.x = sin(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.x;
+
+                if (cameraAngle.y <= 0.0f) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y;
+                else camera->position.y = -sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y;
+
+                camera->position.z = cos(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.z;
+            }
+            else    // CAMERA_FIRST_PERSON
+            {
+                if (isMoving) cameraMoveCounter++;
+
+                // Camera orientation calculation
+                cameraAngle.x += (cameraMouseVariation.x*-cameraMouseSensitivity);
+                cameraAngle.y += (cameraMouseVariation.y*-cameraMouseSensitivity);
+
+                // Angle clamp
+                if (cameraAngle.y > CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD;
+                else if (cameraAngle.y < CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD;
+
+                // Camera is always looking at player
+                camera->target.x = camera->position.x - sin(cameraAngle.x)*CAMERA_FIRST_PERSON_FOCUS_DISTANCE;
+                camera->target.y = camera->position.y + sin(cameraAngle.y)*CAMERA_FIRST_PERSON_FOCUS_DISTANCE;
+                camera->target.z = camera->position.z - cos(cameraAngle.x)*CAMERA_FIRST_PERSON_FOCUS_DISTANCE;
+
+                camera->position.x = playerPosition->x;
+                camera->position.y = (playerPosition->y + PLAYER_HEIGHT*CAMERA_FIRST_PERSON_HEIGHT_RELATIVE_EYES_POSITION) - sin(cameraMoveCounter/CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER)/CAMERA_FIRST_PERSON_STEP_DIVIDER;
+                camera->position.z = playerPosition->z;
+
+                camera->up.x = sin(cameraMoveCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER;
+                camera->up.z = -sin(cameraMoveCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER;
+            }
+        } break;
+        default: break;
+    }
+}
+
+#endif // CAMERA_IMPLEMENTATION

+ 3 - 0
src/core.c

@@ -48,6 +48,9 @@
 #define GESTURES_IMPLEMENTATION
 #include "gestures.h"       // Gestures detection functionality
 
+#define CAMERA_IMPLEMENTATION
+#include "camera.h"         // Camera system functionality
+
 #include <stdio.h>          // Standard input / output lib
 #include <stdlib.h>         // Declares malloc() and free() for memory management, rand(), atexit()
 #include <stdint.h>         // Required for typedef unsigned long long int uint64_t, used by hi-res timer