LibGame  v0.4.0
The LG Game Engine - Copyright (C) 2024-2025 ETMSoftware
lg_camera.c File Reference

Functions

LG_Camera lg_camera ()
 
int lg_camera_init (LG_Camera *cam)
 
int lg_camera_set_all (LG_Camera *cam, vec3_t position, vec3_t target, vec3_t up, float v_fov, float z_near, float z_far)
 
int lg_camera_reset (LG_Camera *cam)
 
mat4_t lg_camera_compute_view_matrix_RH (LG_Camera *cam)
 
mat4_t lg_camera_compute_proj_matrix_RH (LG_Camera *cam)
 
mat4_t lg_camera_compute_view_proj_matrix_RH (LG_Camera *cam)
 
void lg_update_all_cam_m (LG_Camera *cam)
 
int lg_camera_move_to (LG_Camera *cam, vec3_t transl)
 
int lg_camera_rotate_by_eu (LG_Camera *cam, LG_EulerAng ang, const char *rot_order)
 
int lg_camera_rotate_by_quat (LG_Camera *cam, LG_Quat q)
 
int lg_camera_set_rot_by_eu (LG_Camera *cam, LG_EulerAng ang, const char *rot_order)
 
int lg_camera_set_rot_by_quat (LG_Camera *cam, LG_Quat q)
 
void lg_camera_get_frustum (LG_Camera *cam, LG_Frustum *frustum)
 
zboolean is_in_frustum (vec3_t *v, LG_Frustum *frustum)
 
zboolean lg_cuboid_is_in_frustum (LG_Cuboid *cuboid, LG_Frustum *frustum, zboolean fully)
 
zboolean lg_mesh_is_in_frustum (LG_Mesh *mesh, LG_Frustum *frustum, zboolean fully)
 
void lg_camera_override_znear (LG_Camera *cam, float z_near)
 
void lg_camera_override_zfar (LG_Camera *cam, float z_far)
 
void lg_camera_orbit_around (LG_Camera *cam, vec3_t center, float yaw, float pitch)
 
int lg_plane_normalize (LG_Plane *p)
 
float lg_point_to_plane_distance (vec3_t *v, LG_Plane *p)
 
float lg_point_to_norm_plane_distance (vec3_t *v, LG_Plane *p)
 
void lg_camera_info (LG_Camera *cam)
 
void lg_frustum_info (LG_Frustum *frustum)
 

Detailed Description


TODO: KEEP IMPROVING THE API DOC

=== SO FAR, USES RH COORDS SYS FOR MATRIX OPS ===

=== Need to write LH versions for these funcs:

  • lg_camera_compute_view_matrix()
  • lg_camera_compute_proj_matrix()
  • lg_camera_compute_view_proj_matrix()

Because OpenGL coords sys is RH but the Z dir is visually counter-intuitive IMO

See:

Renamed funcs in math_3d.h:

  • m4_ortho() -> m4_ortho_RH()
  • m4_perspective() -> m4_perspective_RH()
  • m4_look_at() -> m4_look_at_RH()

Renamed funcs in lg_camera.c/h:

Camera initial position in world coords is always at center ie (0.0, 0.0, 0.0)

NOTE about cam->orientation and cam->target:

  • You should always update cam->target after setting/changing cam->orientation
  • Target should always only be updated from orientation quat
  • Orientation is always stored as a quaternion

Aircraft/flight simulator camera and user input:

  • All rotations are intrinsic
  • Standard order = YAW/PITCH/ROLL

With OpenGL right hand coords sys:

  • Yaw = rot/Y
  • Pitch = rot/X
  • Roll = rot/Z

So:

 LibGame uses column-major order matrices

 LibGame try to/will use LH 3D coords sys as often as possible (!= OpenGL)

 (To avoid endless confusion, always mention coords sys or anything relevant)

You can use a global, always available, always default-values-initialized, camera:

 LG_Camera *lg_get_camera_one()

if needed, or you can use as many cameras as you want

When multiplying matrices before rendering, the right order is:

 cam->proj_m * cam->view_m * node->world_matrix

or

 cam->view_proj_m * node->world_matrix

MVP stands for Model-View-Proj but it should be WVP for World-View-Proj and you multiply matrices in the reversed order, ie P * V * M or P * V * W.

Function Documentation

◆ lg_camera()

LG_Camera lg_camera ( )

Return a new camera, initialized with default values:

 LG_CAMERA_ORIGIN
 LG_CAMERA_TARGET
 LG_CAMERA_UP
 LG_V_FOV
 LG_Z_NEAR
 LG_Z_FAR
Returns
A new LG_Camera

◆ lg_camera_init()

int lg_camera_init ( LG_Camera cam)

Init the camera, with default values:

 LG_CAMERA_ORIGIN
 LG_CAMERA_TARGET
 LG_CAMERA_UP
 LG_V_FOV
 LG_Z_NEAR
 LG_Z_FAR

To change z_near value, use lg_camera_override_znear()

To change z_far value, use lg_camera_override_zfar()

What matters is the ratio (not the difference) between these values

Parameters
camPointer to a LG_Camera
Returns
LG_OK if OK

◆ lg_camera_set_all()

int lg_camera_set_all ( LG_Camera cam,
vec3_t  position,
vec3_t  target,
vec3_t  up,
float  v_fov,
float  z_near,
float  z_far 
)

Set all camera params

Parameters
camPointer to a LG_Camera
positionPosition in world space
targetLook at target
upThe 'up' vector - will get normalized
v_fovVertical field of view, in degrees
z_nearDistance to the near clipping plane along -z
z_farDistance to the far clipping plane along -z
Returns
LG_OK if OK

◆ lg_camera_reset()

int lg_camera_reset ( LG_Camera cam)

'Reset' the camera, ie init the cam again

Parameters
camPointer to a LG_Camera
Returns
LG_OK if OK

◆ lg_camera_compute_view_matrix_RH()

mat4_t lg_camera_compute_view_matrix_RH ( LG_Camera cam)

Compute and return the view matrix from the camera data

WARNING: Doesn't update cam->view_m

Parameters
camPointer to a LG_Camera
Returns
The camera view matrix

◆ lg_camera_compute_proj_matrix_RH()

mat4_t lg_camera_compute_proj_matrix_RH ( LG_Camera cam)

Compute and return the projection matrix from the camera data

WARNING: Doesn't update cam->proj_m

Parameters
camPointer to a LG_Camera
Returns
The camera projection matrix

◆ lg_camera_compute_view_proj_matrix_RH()

mat4_t lg_camera_compute_view_proj_matrix_RH ( LG_Camera cam)

Compute and return the view projection matrix from the camera data

WARNING: Doesn't update cam->view_proj_m

Parameters
camPointer to a LG_Camera
Returns
The camera view projection matrix

◆ lg_update_all_cam_m()

void lg_update_all_cam_m ( LG_Camera cam)

(Re)compute and update all cam->view_m/proj_m/view_proj_m

This is usually done automatically (if necessary) when moving/rotating the camera or changing other camera settings

Parameters
camPointer to a LG_Camera

◆ lg_camera_move_to()

int lg_camera_move_to ( LG_Camera cam,
vec3_t  transl 
)

Move the camera (FORWARD if transl.x = 0, transl.y = 0, transl.z != 0)

Compute new 'from' and 'to" vectors for the look_at matrix, the 'up' vector remains unchanged by the translation

Doesn't change cam orientation

Update cam->view_m and cam->view_proj_m

Parameters
camPointer to a LG_Camera
translTranslation vector
Returns
LG_OK if OK

◆ lg_camera_rotate_by_eu()

int lg_camera_rotate_by_eu ( LG_Camera cam,
LG_EulerAng  ang,
const char *  rot_order 
)

Rotate the camera by Euler angles

Getting camera orientation from LG_EulerAng in UI is the easiest/prefered way

Update cam->target, cam->up, cam->view_m, and cam->view_proj_m

Parameters
camPointer to a LG_Camera
angThe Euler angles
rot_orderThe rotations order - one of "XYZ", "YXZ", "ZXY", "ZYX", "YZX", "XZY"
Returns
LG_OK if OK

◆ lg_camera_rotate_by_quat()

int lg_camera_rotate_by_quat ( LG_Camera cam,
LG_Quat  q 
)

Rotate the camera with a quaternion

Update cam->target, cam->up, cam->view_m, and cam->view_proj_m

Parameters
camPointer to a LG_Camera
qThe quaternion
Returns
LG_OK if OK

◆ lg_camera_set_rot_by_eu()

int lg_camera_set_rot_by_eu ( LG_Camera cam,
LG_EulerAng  ang,
const char *  rot_order 
)

Set camera rotation by Euler angles

Update cam->target, cam->up, cam->view_m, and cam->view_proj_m

Parameters
camPointer to a LG_Camera
angThe Euler angles
rot_orderThe rotations order - one of "XYZ", "YXZ", "ZXY", "ZYX", "YZX", "XZY"
Returns
LG_OK if OK

◆ lg_camera_set_rot_by_quat()

int lg_camera_set_rot_by_quat ( LG_Camera cam,
LG_Quat  q 
)

Set camera rotation by a quaternion

Update cam->target, cam->up, cam->view_m, and cam->view_proj_m

Parameters
camPointer to a LG_Camera
qThe quaternion
Returns
LG_OK if OK

◆ lg_camera_get_frustum()

void lg_camera_get_frustum ( LG_Camera cam,
LG_Frustum frustum 
)

Get camera frustum, using the Gribb & Hartmann algorithm:

'Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix'
Gil Gribb ggrib.nosp@m.b@ra.nosp@m.venso.nosp@m.ft.c.nosp@m.om
Klaus Hartmann k_har.nosp@m.tman.nosp@m.n@osn.nosp@m.abru.nosp@m.eck.n.nosp@m.etsu.nosp@m.rf.de

Parameters
camPointer to a LG_Camera
frustumPointer to a LG_Frustum

◆ is_in_frustum()

zboolean is_in_frustum ( vec3_t v,
LG_Frustum frustum 
)

Test if pos vector is inside frustum

A pos vector is inside a frustrum if the dot product with all side planes is always > 0

Parameters
vPointer to a vec3_t pos vector
frustumPointer to a LG_Frustum
Returns
TRUE if inside, FALSE otherwise

◆ lg_cuboid_is_in_frustum()

zboolean lg_cuboid_is_in_frustum ( LG_Cuboid cuboid,
LG_Frustum frustum,
zboolean  fully 
)

Test if cuboid is inside frustum (fully or partially)

Parameters
cuboidPointer to a LG_Cuboid
frustumPointer to a LG_Frustum
fullyTRUE to test if all vertices are inside, FALSE to test if at least one is inside
Returns
TRUE if inside, FALSE otherwise

◆ lg_mesh_is_in_frustum()

zboolean lg_mesh_is_in_frustum ( LG_Mesh mesh,
LG_Frustum frustum,
zboolean  fully 
)

Test if mesh is inside frustum (fully or partially)

Parameters
meshPointer to a LG_Mesh
frustumPointer to a LG_Frustum
fullyTRUE to test if all vertices are inside, FALSE to test if at least one is inside
Returns
TRUE if inside, FALSE otherwise

◆ lg_camera_override_znear()

void lg_camera_override_znear ( LG_Camera cam,
float  z_near 
)

Set cam->z_near value to z_near (default is LG_Z_NEAR, defined in lg_camera.h)

Update cam->proj_m and cam->view_proj_m

Parameters
camPointer to a LG_Camera
z_nearNew cam->z_near value

◆ lg_camera_override_zfar()

void lg_camera_override_zfar ( LG_Camera cam,
float  z_far 
)

Set cam->z_far value to z_far (default is LG_Z_FAR, defined in lg_camera.h)

Update cam->proj_m and cam->view_proj_m

Parameters
camPointer to a LG_Camera
z_farNew cam->z_far value

◆ lg_camera_orbit_around()

void lg_camera_orbit_around ( LG_Camera cam,
vec3_t  center,
float  yaw,
float  pitch 
)

Compute an orbit and move/rotate the camera along this orbit, always looking at the center

This is working fine until cam goes "through" center, ie get out of frustum

Parameters
camPointer to a LG_Camera
centerCenter of the orbit
yawRotation angle around the Y axis, in radians
pitchRotation angle around the X axis, in radians

◆ lg_plane_normalize()

int lg_plane_normalize ( LG_Plane p)

Normalize plane

Parameters
pA pointer to a LG_Plane
Returns
LG_OK if OK, LG_ERROR if magnitude <= LG_FLOAT_EPSILON

◆ lg_point_to_plane_distance()

float lg_point_to_plane_distance ( vec3_t v,
LG_Plane p 
)

Compute point to (non-normalized) plane distance

Parameters
vA pointer to a position vec3_t
pA pointer to a non-normalized LG_Plane
Returns
Distance

◆ lg_point_to_norm_plane_distance()

float lg_point_to_norm_plane_distance ( vec3_t v,
LG_Plane p 
)

Compute point to (normalized) plane distance

Parameters
vA pointer to a position vec3_t
pA pointer to a normalized LG_Plane
Returns
Distance

◆ lg_camera_info()

void lg_camera_info ( LG_Camera cam)

Print out LG_Camera info

Parameters
camPointer to a LG_Camera

◆ lg_frustum_info()

void lg_frustum_info ( LG_Frustum frustum)

Print out LG_Frustum info

Parameters
frustumPointer to a LG_Frustum