comparison third_party/raylib/include/rcamera.h @ 276:b55c22cff335

Add interactive infinite canvas prototype
author MrJuneJune <me@mrjunejune.com>
date Mon, 17 Aug 2026 16:57:56 -0700
parents
children
comparison
equal deleted inserted replaced
274:c9be578316a6 276:b55c22cff335
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-2026 Christoph Wagner (@Crydsch) and 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) // Building the library as a Win32 shared library (.dll)
58 #elif defined(USE_LIBTYPE_SHARED)
59 #define RLAPI __declspec(dllimport) // 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.05
69 #define CAMERA_CULL_DISTANCE_FAR 4000.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 aperture 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 #include <math.h> // Required for: fabsf()
196
197 //----------------------------------------------------------------------------------
198 // Defines and Macros
199 //----------------------------------------------------------------------------------
200 #define CAMERA_MOVE_SPEED 5.4f // Units per second
201 #define CAMERA_ROTATION_SPEED 0.03f
202 #define CAMERA_PAN_SPEED 2.0f
203
204 // Camera mouse movement sensitivity
205 #define CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f
206
207 // Camera orbital speed in CAMERA_ORBITAL mode
208 #define CAMERA_ORBITAL_SPEED 0.5f // Radians per second
209
210 //----------------------------------------------------------------------------------
211 // Types and Structures Definition
212 //----------------------------------------------------------------------------------
213 //...
214
215 //----------------------------------------------------------------------------------
216 // Global Variables Definition
217 //----------------------------------------------------------------------------------
218 //...
219
220 //----------------------------------------------------------------------------------
221 // Module Internal Functions Declaration
222 //----------------------------------------------------------------------------------
223 //...
224
225 //----------------------------------------------------------------------------------
226 // Module Functions Definition
227 //----------------------------------------------------------------------------------
228 // Returns the cameras forward vector (normalized)
229 Vector3 GetCameraForward(Camera *camera)
230 {
231 return Vector3Normalize(Vector3Subtract(camera->target, camera->position));
232 }
233
234 // Returns the cameras up vector (normalized)
235 // Note: The up vector might not be perpendicular to the forward vector
236 Vector3 GetCameraUp(Camera *camera)
237 {
238 return Vector3Normalize(camera->up);
239 }
240
241 // Returns the cameras right vector (normalized)
242 Vector3 GetCameraRight(Camera *camera)
243 {
244 Vector3 forward = GetCameraForward(camera);
245 Vector3 up = GetCameraUp(camera);
246
247 return Vector3Normalize(Vector3CrossProduct(forward, up));
248 }
249
250 // Moves the camera in its forward direction
251 void CameraMoveForward(Camera *camera, float distance, bool moveInWorldPlane)
252 {
253 Vector3 forward = GetCameraForward(camera);
254
255 if (moveInWorldPlane)
256 {
257 // Project vector onto world plane (the plane defined by the up vector)
258 if (fabsf(camera->up.z) > 0.7071f) forward.z = 0;
259 else if (fabsf(camera->up.x) > 0.7071f) forward.x = 0;
260 else forward.y = 0;
261
262 forward = Vector3Normalize(forward);
263 }
264
265 // Scale by distance
266 forward = Vector3Scale(forward, distance);
267
268 // Move position and target
269 camera->position = Vector3Add(camera->position, forward);
270 camera->target = Vector3Add(camera->target, forward);
271 }
272
273 // Moves the camera in its up direction
274 void CameraMoveUp(Camera *camera, float distance)
275 {
276 Vector3 up = GetCameraUp(camera);
277
278 // Scale by distance
279 up = Vector3Scale(up, distance);
280
281 // Move position and target
282 camera->position = Vector3Add(camera->position, up);
283 camera->target = Vector3Add(camera->target, up);
284 }
285
286 // Moves the camera target in its current right direction
287 void CameraMoveRight(Camera *camera, float distance, bool moveInWorldPlane)
288 {
289 Vector3 right = GetCameraRight(camera);
290
291 if (moveInWorldPlane)
292 {
293 // Project vector onto world plane (the plane defined by the up vector)
294 if (fabsf(camera->up.z) > 0.7071f) right.z = 0;
295 else if (fabsf(camera->up.x) > 0.7071f) right.x = 0;
296 else right.y = 0;
297
298 right = Vector3Normalize(right);
299 }
300
301 // Scale by distance
302 right = Vector3Scale(right, distance);
303
304 // Move position and target
305 camera->position = Vector3Add(camera->position, right);
306 camera->target = Vector3Add(camera->target, right);
307 }
308
309 // Moves the camera position closer/farther to/from the camera target
310 void CameraMoveToTarget(Camera *camera, float delta)
311 {
312 float distance = Vector3Distance(camera->position, camera->target);
313
314 // Apply delta
315 distance += delta;
316
317 // Distance must be greater than 0
318 if (distance <= 0) distance = 0.001f;
319
320 // Set new distance by moving the position along the forward vector
321 Vector3 forward = GetCameraForward(camera);
322 camera->position = Vector3Add(camera->target, Vector3Scale(forward, -distance));
323 }
324
325 // Rotates the camera around its up vector
326 // Yaw is "looking left and right"
327 // If rotateAroundTarget is false, the camera rotates around its position
328 // Note: angle must be provided in radians
329 void CameraYaw(Camera *camera, float angle, bool rotateAroundTarget)
330 {
331 // Rotation axis
332 Vector3 up = GetCameraUp(camera);
333
334 // View vector
335 Vector3 targetPosition = Vector3Subtract(camera->target, camera->position);
336
337 // Rotate view vector around up axis
338 targetPosition = Vector3RotateByAxisAngle(targetPosition, up, angle);
339
340 if (rotateAroundTarget)
341 {
342 // Move position relative to target
343 camera->position = Vector3Subtract(camera->target, targetPosition);
344 }
345 else // rotate around camera.position
346 {
347 // Move target relative to position
348 camera->target = Vector3Add(camera->position, targetPosition);
349 }
350 }
351
352 // Rotates the camera around its right vector, pitch is "looking up and down"
353 // - lockView prevents camera overrotation (aka "somersaults")
354 // - rotateAroundTarget defines if rotation is around target or around its position
355 // - rotateUp rotates the up direction as well (typically only useful in CAMERA_FREE)
356 // NOTE: [angle] must be provided in radians
357 void CameraPitch(Camera *camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp)
358 {
359 // Up direction
360 Vector3 up = GetCameraUp(camera);
361
362 // View vector
363 Vector3 targetPosition = Vector3Subtract(camera->target, camera->position);
364
365 if (lockView)
366 {
367 // In these camera modes, clamp the Pitch angle
368 // to allow only viewing straight up or down
369
370 // Clamp view up
371 float maxAngleUp = Vector3Angle(up, targetPosition);
372 maxAngleUp -= 0.001f; // avoid numerical errors
373 if (angle > maxAngleUp) angle = maxAngleUp;
374
375 // Clamp view down
376 float maxAngleDown = Vector3Angle(Vector3Negate(up), targetPosition);
377 maxAngleDown *= -1.0f; // downwards angle is negative
378 maxAngleDown += 0.001f; // avoid numerical errors
379 if (angle < maxAngleDown) angle = maxAngleDown;
380 }
381
382 // Rotation axis
383 Vector3 right = GetCameraRight(camera);
384
385 // Rotate view vector around right axis
386 targetPosition = Vector3RotateByAxisAngle(targetPosition, right, angle);
387
388 if (rotateAroundTarget)
389 {
390 // Move position relative to target
391 camera->position = Vector3Subtract(camera->target, targetPosition);
392 }
393 else // Rotate around camera.position
394 {
395 // Move target relative to position
396 camera->target = Vector3Add(camera->position, targetPosition);
397 }
398
399 if (rotateUp)
400 {
401 // Rotate up direction around right axis
402 camera->up = Vector3RotateByAxisAngle(camera->up, right, angle);
403 }
404 }
405
406 // Rotates the camera around its forward vector
407 // Roll is "turning your head sideways to the left or right"
408 // Note: angle must be provided in radians
409 void CameraRoll(Camera *camera, float angle)
410 {
411 // Rotation axis
412 Vector3 forward = GetCameraForward(camera);
413
414 // Rotate up direction around forward axis
415 camera->up = Vector3RotateByAxisAngle(camera->up, forward, angle);
416 }
417
418 // Returns the camera view matrix
419 Matrix GetCameraViewMatrix(Camera *camera)
420 {
421 return MatrixLookAt(camera->position, camera->target, camera->up);
422 }
423
424 // Returns the camera projection matrix
425 Matrix GetCameraProjectionMatrix(Camera *camera, float aspect)
426 {
427 if (camera->projection == CAMERA_PERSPECTIVE)
428 {
429 return MatrixPerspective(camera->fovy*DEG2RAD, aspect, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR);
430 }
431 else if (camera->projection == CAMERA_ORTHOGRAPHIC)
432 {
433 double top = camera->fovy/2.0;
434 double right = top*aspect;
435
436 return MatrixOrtho(-right, right, -top, top, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR);
437 }
438
439 return MatrixIdentity();
440 }
441
442 #if !defined(RCAMERA_STANDALONE)
443 // Update camera position for selected mode
444 // Camera mode: CAMERA_FREE, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON, CAMERA_ORBITAL or CUSTOM
445 void UpdateCamera(Camera *camera, int mode)
446 {
447 Vector2 mousePositionDelta = GetMouseDelta();
448
449 bool moveInWorldPlane = ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON));
450 bool rotateAroundTarget = ((mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL));
451 bool lockView = ((mode == CAMERA_FREE) || (mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL));
452 bool rotateUp = false;
453
454 // Camera speeds based on frame time
455 float cameraMoveSpeed = CAMERA_MOVE_SPEED*GetFrameTime();
456 float cameraRotationSpeed = CAMERA_ROTATION_SPEED*GetFrameTime();
457 float cameraPanSpeed = CAMERA_PAN_SPEED*GetFrameTime();
458 float cameraOrbitalSpeed = CAMERA_ORBITAL_SPEED*GetFrameTime();
459
460 if (mode == CAMERA_CUSTOM) {}
461 else if (mode == CAMERA_ORBITAL)
462 {
463 Matrix rotation = MatrixRotate(GetCameraUp(camera), cameraOrbitalSpeed);
464 Vector3 view = Vector3Subtract(camera->position, camera->target);
465 view = Vector3Transform(view, rotation);
466 camera->position = Vector3Add(camera->target, view);
467 }
468 else
469 {
470 // Camera rotation
471 if (IsKeyDown(KEY_DOWN)) CameraPitch(camera, -cameraRotationSpeed, lockView, rotateAroundTarget, rotateUp);
472 if (IsKeyDown(KEY_UP)) CameraPitch(camera, cameraRotationSpeed, lockView, rotateAroundTarget, rotateUp);
473 if (IsKeyDown(KEY_RIGHT)) CameraYaw(camera, -cameraRotationSpeed, rotateAroundTarget);
474 if (IsKeyDown(KEY_LEFT)) CameraYaw(camera, cameraRotationSpeed, rotateAroundTarget);
475 if (IsKeyDown(KEY_Q)) CameraRoll(camera, -cameraRotationSpeed);
476 if (IsKeyDown(KEY_E)) CameraRoll(camera, cameraRotationSpeed);
477
478 // Camera movement
479 // Camera pan (for CAMERA_FREE)
480 if ((mode == CAMERA_FREE) && (IsMouseButtonDown(MOUSE_BUTTON_MIDDLE)))
481 {
482 const Vector2 mouseDelta = GetMouseDelta();
483 if (mouseDelta.x > 0.0f) CameraMoveRight(camera, cameraPanSpeed, moveInWorldPlane);
484 if (mouseDelta.x < 0.0f) CameraMoveRight(camera, -cameraPanSpeed, moveInWorldPlane);
485 if (mouseDelta.y > 0.0f) CameraMoveUp(camera, -cameraPanSpeed);
486 if (mouseDelta.y < 0.0f) CameraMoveUp(camera, cameraPanSpeed);
487 }
488 else
489 {
490 // Mouse support
491 CameraYaw(camera, -mousePositionDelta.x*CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget);
492 CameraPitch(camera, -mousePositionDelta.y*CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp);
493 }
494
495 // Keyboard support
496 if (IsKeyDown(KEY_W)) CameraMoveForward(camera, cameraMoveSpeed, moveInWorldPlane);
497 if (IsKeyDown(KEY_A)) CameraMoveRight(camera, -cameraMoveSpeed, moveInWorldPlane);
498 if (IsKeyDown(KEY_S)) CameraMoveForward(camera, -cameraMoveSpeed, moveInWorldPlane);
499 if (IsKeyDown(KEY_D)) CameraMoveRight(camera, cameraMoveSpeed, moveInWorldPlane);
500
501 // Gamepad movement
502 if (IsGamepadAvailable(0))
503 {
504 // Gamepad controller support
505 CameraYaw(camera, -(GetGamepadAxisMovement(0, GAMEPAD_AXIS_RIGHT_X)*2)*CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget);
506 CameraPitch(camera, -(GetGamepadAxisMovement(0, GAMEPAD_AXIS_RIGHT_Y)*2)*CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp);
507
508 if (GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_Y) <= -0.25f) CameraMoveForward(camera, cameraMoveSpeed, moveInWorldPlane);
509 if (GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_X) <= -0.25f) CameraMoveRight(camera, -cameraMoveSpeed, moveInWorldPlane);
510 if (GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_Y) >= 0.25f) CameraMoveForward(camera, -cameraMoveSpeed, moveInWorldPlane);
511 if (GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_X) >= 0.25f) CameraMoveRight(camera, cameraMoveSpeed, moveInWorldPlane);
512 }
513
514 if (mode == CAMERA_FREE)
515 {
516 if (IsKeyDown(KEY_SPACE)) CameraMoveUp(camera, cameraMoveSpeed);
517 if (IsKeyDown(KEY_LEFT_CONTROL)) CameraMoveUp(camera, -cameraMoveSpeed);
518 }
519 }
520
521 if ((mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL) || (mode == CAMERA_FREE))
522 {
523 // Zoom target distance
524 CameraMoveToTarget(camera, -GetMouseWheelMove());
525 if (IsKeyPressed(KEY_KP_SUBTRACT)) CameraMoveToTarget(camera, 2.0f);
526 if (IsKeyPressed(KEY_KP_ADD)) CameraMoveToTarget(camera, -2.0f);
527 }
528 }
529 #endif // !RCAMERA_STANDALONE
530
531 // Update camera movement, movement/rotation values should be provided by user
532 void UpdateCameraPro(Camera *camera, Vector3 movement, Vector3 rotation, float zoom)
533 {
534 // Required values
535 // movement.x - Move forward/backward
536 // movement.y - Move right/left
537 // movement.z - Move up/down
538 // rotation.x - yaw
539 // rotation.y - pitch
540 // rotation.z - roll
541 // zoom - Move towards target
542
543 bool lockView = true;
544 bool rotateAroundTarget = false;
545 bool rotateUp = false;
546 bool moveInWorldPlane = true;
547
548 // Camera rotation
549 CameraPitch(camera, -rotation.y*DEG2RAD, lockView, rotateAroundTarget, rotateUp);
550 CameraYaw(camera, -rotation.x*DEG2RAD, rotateAroundTarget);
551 CameraRoll(camera, rotation.z*DEG2RAD);
552
553 // Camera movement
554 CameraMoveForward(camera, movement.x, moveInWorldPlane);
555 CameraMoveRight(camera, movement.y, moveInWorldPlane);
556 CameraMoveUp(camera, movement.z);
557
558 // Zoom target distance
559 CameraMoveToTarget(camera, zoom);
560 }
561
562 #endif // RCAMERA_IMPLEMENTATION