rcamera.h (21819B)
1 /******************************************************************************************* 2 * 3 * rcamera - Basic camera system with support for multiple camera modes 4 * 5 * CONFIGURATION: 6 * #define RCAMERA_IMPLEMENTATION 7 * Generates the implementation of the library into the included file. 8 * If not defined, the library is in header only mode and can be included in other headers 9 * or source files without problems. But only ONE file should hold the implementation. 10 * 11 * #define RCAMERA_STANDALONE 12 * If defined, the library can be used as standalone as a camera system but some 13 * functions must be redefined to manage inputs accordingly. 14 * 15 * CONTRIBUTORS: 16 * Ramon Santamaria: Supervision, review, update and maintenance 17 * Christoph Wagner: Complete redesign, using raymath (2022) 18 * Marc Palau: Initial implementation (2014) 19 * 20 * 21 * LICENSE: zlib/libpng 22 * 23 * Copyright (c) 2022-2024 Christoph Wagner (@Crydsch) & Ramon Santamaria (@raysan5) 24 * 25 * This software is provided "as-is", without any express or implied warranty. In no event 26 * will the authors be held liable for any damages arising from the use of this software. 27 * 28 * Permission is granted to anyone to use this software for any purpose, including commercial 29 * applications, and to alter it and redistribute it freely, subject to the following restrictions: 30 * 31 * 1. The origin of this software must not be misrepresented; you must not claim that you 32 * wrote the original software. If you use this software in a product, an acknowledgment 33 * in the product documentation would be appreciated but is not required. 34 * 35 * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 36 * as being the original software. 37 * 38 * 3. This notice may not be removed or altered from any source distribution. 39 * 40 **********************************************************************************************/ 41 42 #ifndef RCAMERA_H 43 #define RCAMERA_H 44 45 //---------------------------------------------------------------------------------- 46 // Defines and Macros 47 //---------------------------------------------------------------------------------- 48 // Function specifiers definition 49 50 // Function specifiers in case library is build/used as a shared library (Windows) 51 // NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll 52 #if defined(_WIN32) 53 #if defined(BUILD_LIBTYPE_SHARED) 54 #if defined(__TINYC__) 55 #define __declspec(x) __attribute__((x)) 56 #endif 57 #define RLAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll) 58 #elif defined(USE_LIBTYPE_SHARED) 59 #define RLAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll) 60 #endif 61 #endif 62 63 #ifndef RLAPI 64 #define RLAPI // Functions defined as 'extern' by default (implicit specifiers) 65 #endif 66 67 #if defined(RCAMERA_STANDALONE) 68 #define CAMERA_CULL_DISTANCE_NEAR 0.01 69 #define CAMERA_CULL_DISTANCE_FAR 1000.0 70 #else 71 #define CAMERA_CULL_DISTANCE_NEAR RL_CULL_DISTANCE_NEAR 72 #define CAMERA_CULL_DISTANCE_FAR RL_CULL_DISTANCE_FAR 73 #endif 74 75 //---------------------------------------------------------------------------------- 76 // Types and Structures Definition 77 // NOTE: Below types are required for standalone usage 78 //---------------------------------------------------------------------------------- 79 #if defined(RCAMERA_STANDALONE) 80 // Vector2, 2 components 81 typedef struct Vector2 { 82 float x; // Vector x component 83 float y; // Vector y component 84 } Vector2; 85 86 // Vector3, 3 components 87 typedef struct Vector3 { 88 float x; // Vector x component 89 float y; // Vector y component 90 float z; // Vector z component 91 } Vector3; 92 93 // Matrix, 4x4 components, column major, OpenGL style, right-handed 94 typedef struct Matrix { 95 float m0, m4, m8, m12; // Matrix first row (4 components) 96 float m1, m5, m9, m13; // Matrix second row (4 components) 97 float m2, m6, m10, m14; // Matrix third row (4 components) 98 float m3, m7, m11, m15; // Matrix fourth row (4 components) 99 } Matrix; 100 101 // Camera type, defines a camera position/orientation in 3d space 102 typedef struct Camera3D { 103 Vector3 position; // Camera position 104 Vector3 target; // Camera target it looks-at 105 Vector3 up; // Camera up vector (rotation over its axis) 106 float fovy; // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic 107 int projection; // Camera projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC 108 } Camera3D; 109 110 typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D 111 112 // Camera projection 113 typedef enum { 114 CAMERA_PERSPECTIVE = 0, // Perspective projection 115 CAMERA_ORTHOGRAPHIC // Orthographic projection 116 } CameraProjection; 117 118 // Camera system modes 119 typedef enum { 120 CAMERA_CUSTOM = 0, // Camera custom, controlled by user (UpdateCamera() does nothing) 121 CAMERA_FREE, // Camera free mode 122 CAMERA_ORBITAL, // Camera orbital, around target, zoom supported 123 CAMERA_FIRST_PERSON, // Camera first person 124 CAMERA_THIRD_PERSON // Camera third person 125 } CameraMode; 126 #endif 127 128 //---------------------------------------------------------------------------------- 129 // Global Variables Definition 130 //---------------------------------------------------------------------------------- 131 //... 132 133 //---------------------------------------------------------------------------------- 134 // Module Functions Declaration 135 //---------------------------------------------------------------------------------- 136 137 #if defined(__cplusplus) 138 extern "C" { // Prevents name mangling of functions 139 #endif 140 141 RLAPI Vector3 GetCameraForward(Camera *camera); 142 RLAPI Vector3 GetCameraUp(Camera *camera); 143 RLAPI Vector3 GetCameraRight(Camera *camera); 144 145 // Camera movement 146 RLAPI void CameraMoveForward(Camera *camera, float distance, bool moveInWorldPlane); 147 RLAPI void CameraMoveUp(Camera *camera, float distance); 148 RLAPI void CameraMoveRight(Camera *camera, float distance, bool moveInWorldPlane); 149 RLAPI void CameraMoveToTarget(Camera *camera, float delta); 150 151 // Camera rotation 152 RLAPI void CameraYaw(Camera *camera, float angle, bool rotateAroundTarget); 153 RLAPI void CameraPitch(Camera *camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp); 154 RLAPI void CameraRoll(Camera *camera, float angle); 155 156 RLAPI Matrix GetCameraViewMatrix(Camera *camera); 157 RLAPI Matrix GetCameraProjectionMatrix(Camera* camera, float aspect); 158 159 #if defined(__cplusplus) 160 } 161 #endif 162 163 #endif // RCAMERA_H 164 165 /*********************************************************************************** 166 * 167 * CAMERA IMPLEMENTATION 168 * 169 ************************************************************************************/ 170 171 #if defined(RCAMERA_IMPLEMENTATION) 172 173 #include "raymath.h" // Required for vector maths: 174 // Vector3Add() 175 // Vector3Subtract() 176 // Vector3Scale() 177 // Vector3Normalize() 178 // Vector3Distance() 179 // Vector3CrossProduct() 180 // Vector3RotateByAxisAngle() 181 // Vector3Angle() 182 // Vector3Negate() 183 // MatrixLookAt() 184 // MatrixPerspective() 185 // MatrixOrtho() 186 // MatrixIdentity() 187 188 // raylib required functionality: 189 // GetMouseDelta() 190 // GetMouseWheelMove() 191 // IsKeyDown() 192 // IsKeyPressed() 193 // GetFrameTime() 194 195 //---------------------------------------------------------------------------------- 196 // Defines and Macros 197 //---------------------------------------------------------------------------------- 198 #define CAMERA_MOVE_SPEED 5.4f // Units per second 199 #define CAMERA_ROTATION_SPEED 0.03f 200 #define CAMERA_PAN_SPEED 0.2f 201 202 // Camera mouse movement sensitivity 203 #define CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f 204 205 // Camera orbital speed in CAMERA_ORBITAL mode 206 #define CAMERA_ORBITAL_SPEED 0.5f // Radians per second 207 208 //---------------------------------------------------------------------------------- 209 // Types and Structures Definition 210 //---------------------------------------------------------------------------------- 211 //... 212 213 //---------------------------------------------------------------------------------- 214 // Global Variables Definition 215 //---------------------------------------------------------------------------------- 216 //... 217 218 //---------------------------------------------------------------------------------- 219 // Module specific Functions Declaration 220 //---------------------------------------------------------------------------------- 221 //... 222 223 //---------------------------------------------------------------------------------- 224 // Module Functions Definition 225 //---------------------------------------------------------------------------------- 226 // Returns the cameras forward vector (normalized) 227 Vector3 GetCameraForward(Camera *camera) 228 { 229 return Vector3Normalize(Vector3Subtract(camera->target, camera->position)); 230 } 231 232 // Returns the cameras up vector (normalized) 233 // Note: The up vector might not be perpendicular to the forward vector 234 Vector3 GetCameraUp(Camera *camera) 235 { 236 return Vector3Normalize(camera->up); 237 } 238 239 // Returns the cameras right vector (normalized) 240 Vector3 GetCameraRight(Camera *camera) 241 { 242 Vector3 forward = GetCameraForward(camera); 243 Vector3 up = GetCameraUp(camera); 244 245 return Vector3Normalize(Vector3CrossProduct(forward, up)); 246 } 247 248 // Moves the camera in its forward direction 249 void CameraMoveForward(Camera *camera, float distance, bool moveInWorldPlane) 250 { 251 Vector3 forward = GetCameraForward(camera); 252 253 if (moveInWorldPlane) 254 { 255 // Project vector onto world plane 256 forward.y = 0; 257 forward = Vector3Normalize(forward); 258 } 259 260 // Scale by distance 261 forward = Vector3Scale(forward, distance); 262 263 // Move position and target 264 camera->position = Vector3Add(camera->position, forward); 265 camera->target = Vector3Add(camera->target, forward); 266 } 267 268 // Moves the camera in its up direction 269 void CameraMoveUp(Camera *camera, float distance) 270 { 271 Vector3 up = GetCameraUp(camera); 272 273 // Scale by distance 274 up = Vector3Scale(up, distance); 275 276 // Move position and target 277 camera->position = Vector3Add(camera->position, up); 278 camera->target = Vector3Add(camera->target, up); 279 } 280 281 // Moves the camera target in its current right direction 282 void CameraMoveRight(Camera *camera, float distance, bool moveInWorldPlane) 283 { 284 Vector3 right = GetCameraRight(camera); 285 286 if (moveInWorldPlane) 287 { 288 // Project vector onto world plane 289 right.y = 0; 290 right = Vector3Normalize(right); 291 } 292 293 // Scale by distance 294 right = Vector3Scale(right, distance); 295 296 // Move position and target 297 camera->position = Vector3Add(camera->position, right); 298 camera->target = Vector3Add(camera->target, right); 299 } 300 301 // Moves the camera position closer/farther to/from the camera target 302 void CameraMoveToTarget(Camera *camera, float delta) 303 { 304 float distance = Vector3Distance(camera->position, camera->target); 305 306 // Apply delta 307 distance += delta; 308 309 // Distance must be greater than 0 310 if (distance <= 0) distance = 0.001f; 311 312 // Set new distance by moving the position along the forward vector 313 Vector3 forward = GetCameraForward(camera); 314 camera->position = Vector3Add(camera->target, Vector3Scale(forward, -distance)); 315 } 316 317 // Rotates the camera around its up vector 318 // Yaw is "looking left and right" 319 // If rotateAroundTarget is false, the camera rotates around its position 320 // Note: angle must be provided in radians 321 void CameraYaw(Camera *camera, float angle, bool rotateAroundTarget) 322 { 323 // Rotation axis 324 Vector3 up = GetCameraUp(camera); 325 326 // View vector 327 Vector3 targetPosition = Vector3Subtract(camera->target, camera->position); 328 329 // Rotate view vector around up axis 330 targetPosition = Vector3RotateByAxisAngle(targetPosition, up, angle); 331 332 if (rotateAroundTarget) 333 { 334 // Move position relative to target 335 camera->position = Vector3Subtract(camera->target, targetPosition); 336 } 337 else // rotate around camera.position 338 { 339 // Move target relative to position 340 camera->target = Vector3Add(camera->position, targetPosition); 341 } 342 } 343 344 // Rotates the camera around its right vector, pitch is "looking up and down" 345 // - lockView prevents camera overrotation (aka "somersaults") 346 // - rotateAroundTarget defines if rotation is around target or around its position 347 // - rotateUp rotates the up direction as well (typically only usefull in CAMERA_FREE) 348 // NOTE: angle must be provided in radians 349 void CameraPitch(Camera *camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp) 350 { 351 // Up direction 352 Vector3 up = GetCameraUp(camera); 353 354 // View vector 355 Vector3 targetPosition = Vector3Subtract(camera->target, camera->position); 356 357 if (lockView) 358 { 359 // In these camera modes we clamp the Pitch angle 360 // to allow only viewing straight up or down. 361 362 // Clamp view up 363 float maxAngleUp = Vector3Angle(up, targetPosition); 364 maxAngleUp -= 0.001f; // avoid numerical errors 365 if (angle > maxAngleUp) angle = maxAngleUp; 366 367 // Clamp view down 368 float maxAngleDown = Vector3Angle(Vector3Negate(up), targetPosition); 369 maxAngleDown *= -1.0f; // downwards angle is negative 370 maxAngleDown += 0.001f; // avoid numerical errors 371 if (angle < maxAngleDown) angle = maxAngleDown; 372 } 373 374 // Rotation axis 375 Vector3 right = GetCameraRight(camera); 376 377 // Rotate view vector around right axis 378 targetPosition = Vector3RotateByAxisAngle(targetPosition, right, angle); 379 380 if (rotateAroundTarget) 381 { 382 // Move position relative to target 383 camera->position = Vector3Subtract(camera->target, targetPosition); 384 } 385 else // rotate around camera.position 386 { 387 // Move target relative to position 388 camera->target = Vector3Add(camera->position, targetPosition); 389 } 390 391 if (rotateUp) 392 { 393 // Rotate up direction around right axis 394 camera->up = Vector3RotateByAxisAngle(camera->up, right, angle); 395 } 396 } 397 398 // Rotates the camera around its forward vector 399 // Roll is "turning your head sideways to the left or right" 400 // Note: angle must be provided in radians 401 void CameraRoll(Camera *camera, float angle) 402 { 403 // Rotation axis 404 Vector3 forward = GetCameraForward(camera); 405 406 // Rotate up direction around forward axis 407 camera->up = Vector3RotateByAxisAngle(camera->up, forward, angle); 408 } 409 410 // Returns the camera view matrix 411 Matrix GetCameraViewMatrix(Camera *camera) 412 { 413 return MatrixLookAt(camera->position, camera->target, camera->up); 414 } 415 416 // Returns the camera projection matrix 417 Matrix GetCameraProjectionMatrix(Camera *camera, float aspect) 418 { 419 if (camera->projection == CAMERA_PERSPECTIVE) 420 { 421 return MatrixPerspective(camera->fovy*DEG2RAD, aspect, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR); 422 } 423 else if (camera->projection == CAMERA_ORTHOGRAPHIC) 424 { 425 double top = camera->fovy/2.0; 426 double right = top*aspect; 427 428 return MatrixOrtho(-right, right, -top, top, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR); 429 } 430 431 return MatrixIdentity(); 432 } 433 434 #if !defined(RCAMERA_STANDALONE) 435 // Update camera position for selected mode 436 // Camera mode: CAMERA_FREE, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON, CAMERA_ORBITAL or CUSTOM 437 void UpdateCamera(Camera *camera, int mode) 438 { 439 Vector2 mousePositionDelta = GetMouseDelta(); 440 441 bool moveInWorldPlane = ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)); 442 bool rotateAroundTarget = ((mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL)); 443 bool lockView = ((mode == CAMERA_FREE) || (mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL)); 444 bool rotateUp = false; 445 446 // Camera speeds based on frame time 447 float cameraMoveSpeed = CAMERA_MOVE_SPEED*GetFrameTime(); 448 float cameraRotationSpeed = CAMERA_ROTATION_SPEED*GetFrameTime(); 449 float cameraPanSpeed = CAMERA_PAN_SPEED*GetFrameTime(); 450 float cameraOrbitalSpeed = CAMERA_ORBITAL_SPEED*GetFrameTime(); 451 452 if (mode == CAMERA_CUSTOM) {} 453 else if (mode == CAMERA_ORBITAL) 454 { 455 // Orbital can just orbit 456 Matrix rotation = MatrixRotate(GetCameraUp(camera), cameraOrbitalSpeed); 457 Vector3 view = Vector3Subtract(camera->position, camera->target); 458 view = Vector3Transform(view, rotation); 459 camera->position = Vector3Add(camera->target, view); 460 } 461 else 462 { 463 // Camera rotation 464 if (IsKeyDown(KEY_DOWN)) CameraPitch(camera, -cameraRotationSpeed, lockView, rotateAroundTarget, rotateUp); 465 if (IsKeyDown(KEY_UP)) CameraPitch(camera, cameraRotationSpeed, lockView, rotateAroundTarget, rotateUp); 466 if (IsKeyDown(KEY_RIGHT)) CameraYaw(camera, -cameraRotationSpeed, rotateAroundTarget); 467 if (IsKeyDown(KEY_LEFT)) CameraYaw(camera, cameraRotationSpeed, rotateAroundTarget); 468 if (IsKeyDown(KEY_Q)) CameraRoll(camera, -cameraRotationSpeed); 469 if (IsKeyDown(KEY_E)) CameraRoll(camera, cameraRotationSpeed); 470 471 // Camera movement 472 // Camera pan (for CAMERA_FREE) 473 if ((mode == CAMERA_FREE) && (IsMouseButtonDown(MOUSE_BUTTON_MIDDLE))) 474 { 475 const Vector2 mouseDelta = GetMouseDelta(); 476 if (mouseDelta.x > 0.0f) CameraMoveRight(camera, cameraPanSpeed, moveInWorldPlane); 477 if (mouseDelta.x < 0.0f) CameraMoveRight(camera, -cameraPanSpeed, moveInWorldPlane); 478 if (mouseDelta.y > 0.0f) CameraMoveUp(camera, -cameraPanSpeed); 479 if (mouseDelta.y < 0.0f) CameraMoveUp(camera, cameraPanSpeed); 480 } 481 else 482 { 483 // Mouse support 484 CameraYaw(camera, -mousePositionDelta.x*CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget); 485 CameraPitch(camera, -mousePositionDelta.y*CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp); 486 } 487 488 // Keyboard support 489 if (IsKeyDown(KEY_W)) CameraMoveForward(camera, cameraMoveSpeed, moveInWorldPlane); 490 if (IsKeyDown(KEY_A)) CameraMoveRight(camera, -cameraMoveSpeed, moveInWorldPlane); 491 if (IsKeyDown(KEY_S)) CameraMoveForward(camera, -cameraMoveSpeed, moveInWorldPlane); 492 if (IsKeyDown(KEY_D)) CameraMoveRight(camera, cameraMoveSpeed, moveInWorldPlane); 493 494 // Gamepad movement 495 if (IsGamepadAvailable(0)) 496 { 497 // Gamepad controller support 498 CameraYaw(camera, -(GetGamepadAxisMovement(0, GAMEPAD_AXIS_RIGHT_X)*2)*CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget); 499 CameraPitch(camera, -(GetGamepadAxisMovement(0, GAMEPAD_AXIS_RIGHT_Y)*2)*CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp); 500 501 if (GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_Y) <= -0.25f) CameraMoveForward(camera, cameraMoveSpeed, moveInWorldPlane); 502 if (GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_X) <= -0.25f) CameraMoveRight(camera, -cameraMoveSpeed, moveInWorldPlane); 503 if (GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_Y) >= 0.25f) CameraMoveForward(camera, -cameraMoveSpeed, moveInWorldPlane); 504 if (GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_X) >= 0.25f) CameraMoveRight(camera, cameraMoveSpeed, moveInWorldPlane); 505 } 506 507 if (mode == CAMERA_FREE) 508 { 509 if (IsKeyDown(KEY_SPACE)) CameraMoveUp(camera, cameraMoveSpeed); 510 if (IsKeyDown(KEY_LEFT_CONTROL)) CameraMoveUp(camera, -cameraMoveSpeed); 511 } 512 } 513 514 if ((mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL) || (mode == CAMERA_FREE)) 515 { 516 // Zoom target distance 517 CameraMoveToTarget(camera, -GetMouseWheelMove()); 518 if (IsKeyPressed(KEY_KP_SUBTRACT)) CameraMoveToTarget(camera, 2.0f); 519 if (IsKeyPressed(KEY_KP_ADD)) CameraMoveToTarget(camera, -2.0f); 520 } 521 } 522 #endif // !RCAMERA_STANDALONE 523 524 // Update camera movement, movement/rotation values should be provided by user 525 void UpdateCameraPro(Camera *camera, Vector3 movement, Vector3 rotation, float zoom) 526 { 527 // Required values 528 // movement.x - Move forward/backward 529 // movement.y - Move right/left 530 // movement.z - Move up/down 531 // rotation.x - yaw 532 // rotation.y - pitch 533 // rotation.z - roll 534 // zoom - Move towards target 535 536 bool lockView = true; 537 bool rotateAroundTarget = false; 538 bool rotateUp = false; 539 bool moveInWorldPlane = true; 540 541 // Camera rotation 542 CameraPitch(camera, -rotation.y*DEG2RAD, lockView, rotateAroundTarget, rotateUp); 543 CameraYaw(camera, -rotation.x*DEG2RAD, rotateAroundTarget); 544 CameraRoll(camera, rotation.z*DEG2RAD); 545 546 // Camera movement 547 CameraMoveForward(camera, movement.x, moveInWorldPlane); 548 CameraMoveRight(camera, movement.y, moveInWorldPlane); 549 CameraMoveUp(camera, movement.z); 550 551 // Zoom target distance 552 CameraMoveToTarget(camera, zoom); 553 } 554 555 #endif // RCAMERA_IMPLEMENTATION