github.com/Konstantin8105/c4go@v0.0.0-20240505174241-768bb1c65a51/tests/raylib/rcamera.h (about)

     1  /*******************************************************************************************
     2  *
     3  *   rcamera - Basic camera system for multiple camera modes
     4  *
     5  *   NOTE: Memory footprint of this library is aproximately 52 bytes (global variables)
     6  *
     7  *   CONFIGURATION:
     8  *
     9  *   #define CAMERA_IMPLEMENTATION
    10  *       Generates the implementation of the library into the included file.
    11  *       If not defined, the library is in header only mode and can be included in other headers
    12  *       or source files without problems. But only ONE file should hold the implementation.
    13  *
    14  *   #define CAMERA_STANDALONE
    15  *       If defined, the library can be used as standalone as a camera system but some
    16  *       functions must be redefined to manage inputs accordingly.
    17  *
    18  *   CONTRIBUTORS:
    19  *       Ramon Santamaria:   Supervision, review, update and maintenance
    20  *       Marc Palau:         Initial implementation (2014)
    21  *
    22  *
    23  *   LICENSE: zlib/libpng
    24  *
    25  *   Copyright (c) 2015-2022 Ramon Santamaria (@raysan5)
    26  *
    27  *   This software is provided "as-is", without any express or implied warranty. In no event
    28  *   will the authors be held liable for any damages arising from the use of this software.
    29  *
    30  *   Permission is granted to anyone to use this software for any purpose, including commercial
    31  *   applications, and to alter it and redistribute it freely, subject to the following restrictions:
    32  *
    33  *     1. The origin of this software must not be misrepresented; you must not claim that you
    34  *     wrote the original software. If you use this software in a product, an acknowledgment
    35  *     in the product documentation would be appreciated but is not required.
    36  *
    37  *     2. Altered source versions must be plainly marked as such, and must not be misrepresented
    38  *     as being the original software.
    39  *
    40  *     3. This notice may not be removed or altered from any source distribution.
    41  *
    42  **********************************************************************************************/
    43  
    44  #ifndef RCAMERA_H
    45  #define RCAMERA_H
    46  
    47  //----------------------------------------------------------------------------------
    48  // Defines and Macros
    49  //----------------------------------------------------------------------------------
    50  //...
    51  
    52  //----------------------------------------------------------------------------------
    53  // Types and Structures Definition
    54  // NOTE: Below types are required for CAMERA_STANDALONE usage
    55  //----------------------------------------------------------------------------------
    56  #if defined(CAMERA_STANDALONE)
    57      // Vector2 type
    58      typedef struct Vector2 {
    59          float x;
    60          float y;
    61      } Vector2;
    62  
    63      // Vector3 type
    64      typedef struct Vector3 {
    65          float x;
    66          float y;
    67          float z;
    68      } Vector3;
    69  
    70      // Camera type, defines a camera position/orientation in 3d space
    71      typedef struct Camera3D {
    72          Vector3 position;       // Camera position
    73          Vector3 target;         // Camera target it looks-at
    74          Vector3 up;             // Camera up vector (rotation over its axis)
    75          float fovy;             // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic
    76          int type;               // Camera type, defines projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC
    77      } Camera3D;
    78  
    79      typedef Camera3D Camera;    // Camera type fallback, defaults to Camera3D
    80  
    81      // Camera system modes
    82      typedef enum {
    83          CAMERA_CUSTOM = 0,
    84          CAMERA_FREE,
    85          CAMERA_ORBITAL,
    86          CAMERA_FIRST_PERSON,
    87          CAMERA_THIRD_PERSON
    88      } CameraMode;
    89  
    90      // Camera projection modes
    91      typedef enum {
    92          CAMERA_PERSPECTIVE = 0,
    93          CAMERA_ORTHOGRAPHIC
    94      } CameraProjection;
    95  #endif
    96  
    97  //----------------------------------------------------------------------------------
    98  // Global Variables Definition
    99  //----------------------------------------------------------------------------------
   100  //...
   101  
   102  //----------------------------------------------------------------------------------
   103  // Module Functions Declaration
   104  //----------------------------------------------------------------------------------
   105  
   106  #if defined(__cplusplus)
   107  extern "C" {            // Prevents name mangling of functions
   108  #endif
   109  
   110  #if defined(CAMERA_STANDALONE)
   111  void SetCameraMode(Camera camera, int mode);                // Set camera mode (multiple camera modes available)
   112  void UpdateCamera(Camera *camera);                          // Update camera position for selected mode
   113  
   114  void SetCameraPanControl(int keyPan);                       // Set camera pan key to combine with mouse movement (free camera)
   115  void SetCameraAltControl(int keyAlt);                       // Set camera alt key to combine with mouse movement (free camera)
   116  void SetCameraSmoothZoomControl(int szoomKey);              // Set camera smooth zoom key to combine with mouse (free camera)
   117  void SetCameraMoveControls(int keyFront, int keyBack,
   118                             int keyRight, int keyLeft,
   119                             int keyUp, int keyDown);         // Set camera move controls (1st person and 3rd person cameras)
   120  #endif
   121  
   122  #if defined(__cplusplus)
   123  }
   124  #endif
   125  
   126  #endif // CAMERA_H
   127  
   128  
   129  /***********************************************************************************
   130  *
   131  *   CAMERA IMPLEMENTATION
   132  *
   133  ************************************************************************************/
   134  
   135  #if defined(CAMERA_IMPLEMENTATION)
   136  
   137  #include <math.h>               // Required for: sinf(), cosf(), sqrtf()
   138  
   139  //----------------------------------------------------------------------------------
   140  // Defines and Macros
   141  //----------------------------------------------------------------------------------
   142  #ifndef PI
   143      #define PI 3.14159265358979323846
   144  #endif
   145  #ifndef DEG2RAD
   146      #define DEG2RAD (PI/180.0f)
   147  #endif
   148  #ifndef RAD2DEG
   149      #define RAD2DEG (180.0f/PI)
   150  #endif
   151  
   152  // Camera mouse movement sensitivity
   153  #define CAMERA_MOUSE_MOVE_SENSITIVITY                   0.5f    // TODO: it should be independant of framerate
   154  #define CAMERA_MOUSE_SCROLL_SENSITIVITY                 1.5f
   155  
   156  // FREE_CAMERA
   157  #define CAMERA_FREE_MOUSE_SENSITIVITY                   0.01f
   158  #define CAMERA_FREE_DISTANCE_MIN_CLAMP                  0.3f
   159  #define CAMERA_FREE_DISTANCE_MAX_CLAMP                  120.0f
   160  #define CAMERA_FREE_MIN_CLAMP                           85.0f
   161  #define CAMERA_FREE_MAX_CLAMP                          -85.0f
   162  #define CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY             0.05f
   163  #define CAMERA_FREE_PANNING_DIVIDER                     5.1f
   164  
   165  // ORBITAL_CAMERA
   166  #define CAMERA_ORBITAL_SPEED                            0.5f       // Radians per second
   167  
   168  // FIRST_PERSON
   169  //#define CAMERA_FIRST_PERSON_MOUSE_SENSITIVITY           0.003f
   170  #define CAMERA_FIRST_PERSON_FOCUS_DISTANCE              25.0f
   171  #define CAMERA_FIRST_PERSON_MIN_CLAMP                   89.0f
   172  #define CAMERA_FIRST_PERSON_MAX_CLAMP                  -89.0f
   173  
   174  // When walking, y-position of the player moves up-down at step frequency (swinging) but
   175  // also the body slightly tilts left-right on every step, when all the body weight is left over one foot (tilting)
   176  #define CAMERA_FIRST_PERSON_STEP_FREQUENCY               1.8f       // Step frequency when walking (steps per second)
   177  #define CAMERA_FIRST_PERSON_SWINGING_DELTA               0.03f      // Maximum up-down swinging distance when walking
   178  #define CAMERA_FIRST_PERSON_TILTING_DELTA                0.005f     // Maximum left-right tilting distance when walking
   179  
   180  // THIRD_PERSON
   181  //#define CAMERA_THIRD_PERSON_MOUSE_SENSITIVITY           0.003f
   182  #define CAMERA_THIRD_PERSON_DISTANCE_CLAMP              1.2f
   183  #define CAMERA_THIRD_PERSON_MIN_CLAMP                   5.0f
   184  #define CAMERA_THIRD_PERSON_MAX_CLAMP                  -85.0f
   185  #define CAMERA_THIRD_PERSON_OFFSET                      (Vector3){ 0.4f, 0.0f, 0.0f }
   186  
   187  // PLAYER (used by camera)
   188  #define PLAYER_MOVEMENT_SENSITIVITY                     2.0f
   189  
   190  //----------------------------------------------------------------------------------
   191  // Types and Structures Definition
   192  //----------------------------------------------------------------------------------
   193  // Camera move modes (first person and third person cameras)
   194  typedef enum {
   195      MOVE_FRONT = 0,
   196      MOVE_BACK,
   197      MOVE_RIGHT,
   198      MOVE_LEFT,
   199      MOVE_UP,
   200      MOVE_DOWN
   201  } CameraMove;
   202  
   203  // Camera global state context data [56 bytes]
   204  typedef struct {
   205      unsigned int mode;              // Current camera mode
   206      float targetDistance;           // Camera distance from position to target
   207      float playerEyesPosition;       // Player eyes position from ground (in meters)
   208      Vector2 angle;                  // Camera angle in plane XZ
   209  
   210      // Camera movement control keys
   211      int moveControl[6];             // Move controls (CAMERA_FIRST_PERSON)
   212      int smoothZoomControl;          // Smooth zoom control key
   213      int altControl;                 // Alternative control key
   214      int panControl;                 // Pan view control key
   215  } CameraData;
   216  
   217  //----------------------------------------------------------------------------------
   218  // Global Variables Definition
   219  //----------------------------------------------------------------------------------
   220  static CameraData CAMERA = {        // Global CAMERA state context
   221      .mode = 0,
   222      .targetDistance = 0,
   223      .playerEyesPosition = 1.85f,
   224      .angle = { 0 },
   225      .moveControl = { 'W', 'S', 'D', 'A', 'E', 'Q' },
   226      .smoothZoomControl = 341,       // raylib: KEY_LEFT_CONTROL
   227      .altControl = 342,              // raylib: KEY_LEFT_ALT
   228      .panControl = 2                 // raylib: MOUSE_BUTTON_MIDDLE
   229  };
   230  
   231  //----------------------------------------------------------------------------------
   232  // Module specific Functions Declaration
   233  //----------------------------------------------------------------------------------
   234  #if defined(CAMERA_STANDALONE)
   235  // NOTE: Camera controls depend on some raylib input functions
   236  static void EnableCursor() {}       // Unlock cursor
   237  static void DisableCursor() {}      // Lock cursor
   238  
   239  static int IsKeyDown(int key) { return 0; }
   240  
   241  static int IsMouseButtonDown(int button) { return 0;}
   242  static float GetMouseWheelMove() { return 0.0f; }
   243  static Vector2 GetMousePosition() { return (Vector2){ 0.0f, 0.0f }; }
   244  #endif
   245  
   246  //----------------------------------------------------------------------------------
   247  // Module Functions Definition
   248  //----------------------------------------------------------------------------------
   249  
   250  // Select camera mode (multiple camera modes available)
   251  void SetCameraMode(Camera camera, int mode)
   252  {
   253      Vector3 v1 = camera.position;
   254      Vector3 v2 = camera.target;
   255  
   256      float dx = v2.x - v1.x;
   257      float dy = v2.y - v1.y;
   258      float dz = v2.z - v1.z;
   259  
   260      CAMERA.targetDistance = sqrtf(dx*dx + dy*dy + dz*dz);   // Distance to target
   261  
   262      // Camera angle calculation
   263      CAMERA.angle.x = atan2f(dx, dz);                        // Camera angle in plane XZ (0 aligned with Z, move positive CCW)
   264      CAMERA.angle.y = atan2f(dy, sqrtf(dx*dx + dz*dz));      // Camera angle in plane XY (0 aligned with X, move positive CW)
   265  
   266      CAMERA.playerEyesPosition = camera.position.y;          // Init player eyes position to camera Y position
   267  
   268      // Lock cursor for first person and third person cameras
   269      if ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)) DisableCursor();
   270      else EnableCursor();
   271  
   272      CAMERA.mode = mode;
   273  }
   274  
   275  // Update camera depending on selected mode
   276  // NOTE: Camera controls depend on some raylib functions:
   277  //       System: EnableCursor(), DisableCursor()
   278  //       Mouse: IsMouseButtonDown(), GetMousePosition(), GetMouseWheelMove()
   279  //       Keys:  IsKeyDown()
   280  void UpdateCamera(Camera *camera)
   281  {
   282      static float swingCounter = 0.0f;    // Used for 1st person swinging movement
   283  
   284      // TODO: Compute CAMERA.targetDistance and CAMERA.angle here (?)
   285  
   286      // Mouse movement detection
   287      Vector2 mousePositionDelta = GetMouseDelta();
   288      float mouseWheelMove = GetMouseWheelMove();
   289  
   290      // Keys input detection
   291      // TODO: Input detection is raylib-dependant, it could be moved outside the module
   292      bool keyPan = IsMouseButtonDown(CAMERA.panControl);
   293      bool keyAlt = IsKeyDown(CAMERA.altControl);
   294      bool szoomKey = IsKeyDown(CAMERA.smoothZoomControl);
   295      bool direction[6] = { IsKeyDown(CAMERA.moveControl[MOVE_FRONT]),
   296                            IsKeyDown(CAMERA.moveControl[MOVE_BACK]),
   297                            IsKeyDown(CAMERA.moveControl[MOVE_RIGHT]),
   298                            IsKeyDown(CAMERA.moveControl[MOVE_LEFT]),
   299                            IsKeyDown(CAMERA.moveControl[MOVE_UP]),
   300                            IsKeyDown(CAMERA.moveControl[MOVE_DOWN]) };
   301  
   302      // Support for multiple automatic camera modes
   303      // NOTE: In case of CAMERA_CUSTOM nothing happens here, user must update it manually
   304      switch (CAMERA.mode)
   305      {
   306          case CAMERA_FREE:           // Camera free controls, using standard 3d-content-creation scheme
   307          {
   308              // Camera zoom
   309              if ((CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
   310              {
   311                  CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
   312                  if (CAMERA.targetDistance > CAMERA_FREE_DISTANCE_MAX_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MAX_CLAMP;
   313              }
   314  
   315              // Camera looking down
   316              else if ((camera->position.y > camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
   317              {
   318                  camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
   319                  camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
   320                  camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
   321              }
   322              else if ((camera->position.y > camera->target.y) && (camera->target.y >= 0))
   323              {
   324                  camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
   325                  camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
   326                  camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
   327  
   328                  // if (camera->target.y < 0) camera->target.y = -0.001;
   329              }
   330              else if ((camera->position.y > camera->target.y) && (camera->target.y < 0) && (mouseWheelMove > 0))
   331              {
   332                  CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
   333                  if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP;
   334              }
   335              // Camera looking up
   336              else if ((camera->position.y < camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
   337              {
   338                  camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
   339                  camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
   340                  camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
   341              }
   342              else if ((camera->position.y < camera->target.y) && (camera->target.y <= 0))
   343              {
   344                  camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
   345                  camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
   346                  camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
   347  
   348                  // if (camera->target.y > 0) camera->target.y = 0.001;
   349              }
   350              else if ((camera->position.y < camera->target.y) && (camera->target.y > 0) && (mouseWheelMove > 0))
   351              {
   352                  CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
   353                  if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP;
   354              }
   355  
   356              // Input keys checks
   357              if (keyPan)
   358              {
   359                  if (keyAlt)     // Alternative key behaviour
   360                  {
   361                      if (szoomKey)
   362                      {
   363                          // Camera smooth zoom
   364                          CAMERA.targetDistance += (mousePositionDelta.y*CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY);
   365                      }
   366                      else
   367                      {
   368                          // Camera rotation
   369                          CAMERA.angle.x += mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY;
   370                          CAMERA.angle.y += mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY;
   371  
   372                          // Angle clamp
   373                          if (CAMERA.angle.y > CAMERA_FREE_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MIN_CLAMP*DEG2RAD;
   374                          else if (CAMERA.angle.y < CAMERA_FREE_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MAX_CLAMP*DEG2RAD;
   375                      }
   376                  }
   377                  else
   378                  {
   379                      // Camera panning
   380                      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);
   381                      camera->target.y += ((mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
   382                      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);
   383                  }
   384              }
   385  
   386              // Update camera position with changes
   387              camera->position.x = -sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
   388              camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance + camera->target.y;
   389              camera->position.z = -cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z;
   390  
   391          } break;
   392          case CAMERA_ORBITAL:        // Camera just orbits around target, only zoom allowed
   393          {
   394              CAMERA.angle.x += CAMERA_ORBITAL_SPEED*GetFrameTime();      // Camera orbit angle
   395              CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);   // Camera zoom
   396  
   397              // Camera distance clamp
   398              if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP;
   399  
   400              // Update camera position with changes
   401              camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
   402              camera->position.y = ((CAMERA.angle.y <= 0.0f)? 1 : -1)*sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
   403              camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z;
   404  
   405          } break;
   406          case CAMERA_FIRST_PERSON:   // Camera moves as in a first-person game, controls are configurable
   407          {
   408              camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] -
   409                                     sinf(CAMERA.angle.x)*direction[MOVE_FRONT] -
   410                                     cosf(CAMERA.angle.x)*direction[MOVE_LEFT] +
   411                                     cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
   412  
   413              camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] -
   414                                     sinf(CAMERA.angle.y)*direction[MOVE_BACK] +
   415                                     1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
   416  
   417              camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] -
   418                                     cosf(CAMERA.angle.x)*direction[MOVE_FRONT] +
   419                                     sinf(CAMERA.angle.x)*direction[MOVE_LEFT] -
   420                                     sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
   421  
   422              // Camera orientation calculation
   423              CAMERA.angle.x -= mousePositionDelta.x*CAMERA_MOUSE_MOVE_SENSITIVITY*GetFrameTime();
   424              CAMERA.angle.y -= mousePositionDelta.y*CAMERA_MOUSE_MOVE_SENSITIVITY*GetFrameTime();
   425  
   426              // Angle clamp
   427              if (CAMERA.angle.y > CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD;
   428              else if (CAMERA.angle.y < CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD;
   429  
   430              // Calculate translation matrix
   431              Matrix matTranslation = { 1.0f, 0.0f, 0.0f, 0.0f,
   432                                        0.0f, 1.0f, 0.0f, 0.0f,
   433                                        0.0f, 0.0f, 1.0f, (CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER),
   434                                        0.0f, 0.0f, 0.0f, 1.0f };
   435  
   436              // Calculate rotation matrix
   437              Matrix matRotation = { 1.0f, 0.0f, 0.0f, 0.0f,
   438                                     0.0f, 1.0f, 0.0f, 0.0f,
   439                                     0.0f, 0.0f, 1.0f, 0.0f,
   440                                     0.0f, 0.0f, 0.0f, 1.0f };
   441  
   442              float cosz = cosf(0.0f);
   443              float sinz = sinf(0.0f);
   444              float cosy = cosf(-(PI*2 - CAMERA.angle.x));
   445              float siny = sinf(-(PI*2 - CAMERA.angle.x));
   446              float cosx = cosf(-(PI*2 - CAMERA.angle.y));
   447              float sinx = sinf(-(PI*2 - CAMERA.angle.y));
   448  
   449              matRotation.m0 = cosz*cosy;
   450              matRotation.m4 = (cosz*siny*sinx) - (sinz*cosx);
   451              matRotation.m8 = (cosz*siny*cosx) + (sinz*sinx);
   452              matRotation.m1 = sinz*cosy;
   453              matRotation.m5 = (sinz*siny*sinx) + (cosz*cosx);
   454              matRotation.m9 = (sinz*siny*cosx) - (cosz*sinx);
   455              matRotation.m2 = -siny;
   456              matRotation.m6 = cosy*sinx;
   457              matRotation.m10= cosy*cosx;
   458  
   459              // Multiply translation and rotation matrices
   460              Matrix matTransform = { 0 };
   461              matTransform.m0 = matTranslation.m0*matRotation.m0 + matTranslation.m1*matRotation.m4 + matTranslation.m2*matRotation.m8 + matTranslation.m3*matRotation.m12;
   462              matTransform.m1 = matTranslation.m0*matRotation.m1 + matTranslation.m1*matRotation.m5 + matTranslation.m2*matRotation.m9 + matTranslation.m3*matRotation.m13;
   463              matTransform.m2 = matTranslation.m0*matRotation.m2 + matTranslation.m1*matRotation.m6 + matTranslation.m2*matRotation.m10 + matTranslation.m3*matRotation.m14;
   464              matTransform.m3 = matTranslation.m0*matRotation.m3 + matTranslation.m1*matRotation.m7 + matTranslation.m2*matRotation.m11 + matTranslation.m3*matRotation.m15;
   465              matTransform.m4 = matTranslation.m4*matRotation.m0 + matTranslation.m5*matRotation.m4 + matTranslation.m6*matRotation.m8 + matTranslation.m7*matRotation.m12;
   466              matTransform.m5 = matTranslation.m4*matRotation.m1 + matTranslation.m5*matRotation.m5 + matTranslation.m6*matRotation.m9 + matTranslation.m7*matRotation.m13;
   467              matTransform.m6 = matTranslation.m4*matRotation.m2 + matTranslation.m5*matRotation.m6 + matTranslation.m6*matRotation.m10 + matTranslation.m7*matRotation.m14;
   468              matTransform.m7 = matTranslation.m4*matRotation.m3 + matTranslation.m5*matRotation.m7 + matTranslation.m6*matRotation.m11 + matTranslation.m7*matRotation.m15;
   469              matTransform.m8 = matTranslation.m8*matRotation.m0 + matTranslation.m9*matRotation.m4 + matTranslation.m10*matRotation.m8 + matTranslation.m11*matRotation.m12;
   470              matTransform.m9 = matTranslation.m8*matRotation.m1 + matTranslation.m9*matRotation.m5 + matTranslation.m10*matRotation.m9 + matTranslation.m11*matRotation.m13;
   471              matTransform.m10 = matTranslation.m8*matRotation.m2 + matTranslation.m9*matRotation.m6 + matTranslation.m10*matRotation.m10 + matTranslation.m11*matRotation.m14;
   472              matTransform.m11 = matTranslation.m8*matRotation.m3 + matTranslation.m9*matRotation.m7 + matTranslation.m10*matRotation.m11 + matTranslation.m11*matRotation.m15;
   473              matTransform.m12 = matTranslation.m12*matRotation.m0 + matTranslation.m13*matRotation.m4 + matTranslation.m14*matRotation.m8 + matTranslation.m15*matRotation.m12;
   474              matTransform.m13 = matTranslation.m12*matRotation.m1 + matTranslation.m13*matRotation.m5 + matTranslation.m14*matRotation.m9 + matTranslation.m15*matRotation.m13;
   475              matTransform.m14 = matTranslation.m12*matRotation.m2 + matTranslation.m13*matRotation.m6 + matTranslation.m14*matRotation.m10 + matTranslation.m15*matRotation.m14;
   476              matTransform.m15 = matTranslation.m12*matRotation.m3 + matTranslation.m13*matRotation.m7 + matTranslation.m14*matRotation.m11 + matTranslation.m15*matRotation.m15;
   477  
   478              camera->target.x = camera->position.x - matTransform.m12;
   479              camera->target.y = camera->position.y - matTransform.m13;
   480              camera->target.z = camera->position.z - matTransform.m14;
   481  
   482              // Camera position update
   483              // NOTE: On CAMERA_FIRST_PERSON player Y-movement is limited to player 'eyes position'
   484              camera->position.y = CAMERA.playerEyesPosition;
   485  
   486              // Camera swinging (y-movement), only when walking (some key pressed)
   487              for (int i = 0; i < 6; i++) if (direction[i]) { swingCounter += GetFrameTime(); break; }
   488              camera->position.y -= sinf(2*PI*CAMERA_FIRST_PERSON_STEP_FREQUENCY*swingCounter)*CAMERA_FIRST_PERSON_SWINGING_DELTA;
   489  
   490              // Camera waiving (xz-movement), only when walking (some key pressed)
   491              camera->up.x = sinf(2*PI*CAMERA_FIRST_PERSON_STEP_FREQUENCY*swingCounter)*CAMERA_FIRST_PERSON_TILTING_DELTA;
   492              camera->up.z = -sinf(2*PI*CAMERA_FIRST_PERSON_STEP_FREQUENCY*swingCounter)*CAMERA_FIRST_PERSON_TILTING_DELTA;
   493  
   494          } break;
   495          case CAMERA_THIRD_PERSON:   // Camera moves as in a third-person game, following target at a distance, controls are configurable
   496          {
   497              camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] -
   498                                     sinf(CAMERA.angle.x)*direction[MOVE_FRONT] -
   499                                     cosf(CAMERA.angle.x)*direction[MOVE_LEFT] +
   500                                     cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
   501  
   502              camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] -
   503                                     sinf(CAMERA.angle.y)*direction[MOVE_BACK] +
   504                                     1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
   505  
   506              camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] -
   507                                     cosf(CAMERA.angle.x)*direction[MOVE_FRONT] +
   508                                     sinf(CAMERA.angle.x)*direction[MOVE_LEFT] -
   509                                     sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
   510  
   511              // Camera orientation calculation
   512              CAMERA.angle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY);
   513              CAMERA.angle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY);
   514  
   515              // Angle clamp
   516              if (CAMERA.angle.y > CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD;
   517              else if (CAMERA.angle.y < CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD;
   518  
   519              // Camera zoom
   520              CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
   521  
   522              // Camera distance clamp
   523              if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP;
   524  
   525              camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
   526  
   527              if (CAMERA.angle.y <= 0.0f) camera->position.y = sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
   528              else camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
   529  
   530              camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z;
   531  
   532          } break;
   533          case CAMERA_CUSTOM: break;
   534          default: break;
   535      }
   536  }
   537  
   538  // Set camera pan key to combine with mouse movement (free camera)
   539  void SetCameraPanControl(int keyPan) { CAMERA.panControl = keyPan; }
   540  
   541  // Set camera alt key to combine with mouse movement (free camera)
   542  void SetCameraAltControl(int keyAlt) { CAMERA.altControl = keyAlt; }
   543  
   544  // Set camera smooth zoom key to combine with mouse (free camera)
   545  void SetCameraSmoothZoomControl(int szoomKey) { CAMERA.smoothZoomControl = szoomKey; }
   546  
   547  // Set camera move controls (1st person and 3rd person cameras)
   548  void SetCameraMoveControls(int keyFront, int keyBack, int keyRight, int keyLeft, int keyUp, int keyDown)
   549  {
   550      CAMERA.moveControl[MOVE_FRONT] = keyFront;
   551      CAMERA.moveControl[MOVE_BACK] = keyBack;
   552      CAMERA.moveControl[MOVE_RIGHT] = keyRight;
   553      CAMERA.moveControl[MOVE_LEFT] = keyLeft;
   554      CAMERA.moveControl[MOVE_UP] = keyUp;
   555      CAMERA.moveControl[MOVE_DOWN] = keyDown;
   556  }
   557  
   558  #endif // CAMERA_IMPLEMENTATION