// Camera2D: 24 bytes (offset, target as Vector2; rotation, zoom as float)
///|
/// Camera2D, defines position/orientation in 2D space.
pub struct Camera2D {
offset : Vector2
target : Vector2
rotation : Float
zoom : Float
} derive(Eq, Debug)
///|
/// Create a new Camera2D.
pub fn Camera2D::new(
offset : Vector2,
target : Vector2,
rotation : Float,
zoom : Float,
) -> Camera2D {
{ offset, target, rotation, zoom }
}
///|
/// Serialize Camera2D to bytes.
pub fn Camera2D::to_bytes(c : Camera2D) -> Bytes {
let buf = @buffer.new(size_hint=24)
buf.write_float_le(c.offset.x)
buf.write_float_le(c.offset.y)
buf.write_float_le(c.target.x)
buf.write_float_le(c.target.y)
buf.write_float_le(c.rotation)
buf.write_float_le(c.zoom)
buf.to_bytes()
}
///|
/// Deserialize Camera2D from bytes.
pub fn Camera2D::from_bytes(b : Bytes) -> Camera2D {
{
offset: { x: read_float(b, 0), y: read_float(b, 4) },
target: { x: read_float(b, 8), y: read_float(b, 12) },
rotation: read_float(b, 16),
zoom: read_float(b, 20),
}
}
// Camera3D: 44 bytes (position, target, up as Vector3; fovy as float; projection as int)
///|
/// Camera3D, defines position/orientation in 3D space.
pub struct Camera3D {
position : Vector3
target : Vector3
up : Vector3
fovy : Float
projection : Int
} derive(Eq, Debug)
///|
/// Create a new Camera3D.
pub fn Camera3D::new(
position : Vector3,
target : Vector3,
up : Vector3,
fovy : Float,
projection : Int,
) -> Camera3D {
{ position, target, up, fovy, projection }
}
///|
/// Serialize Camera3D to bytes.
pub fn Camera3D::to_bytes(c : Camera3D) -> Bytes {
let buf = @buffer.new(size_hint=44)
buf.write_float_le(c.position.x)
buf.write_float_le(c.position.y)
buf.write_float_le(c.position.z)
buf.write_float_le(c.target.x)
buf.write_float_le(c.target.y)
buf.write_float_le(c.target.z)
buf.write_float_le(c.up.x)
buf.write_float_le(c.up.y)
buf.write_float_le(c.up.z)
buf.write_float_le(c.fovy)
buf.write_int_le(c.projection)
buf.to_bytes()
}
///|
/// Deserialize Camera3D from bytes.
pub fn Camera3D::from_bytes(b : Bytes) -> Camera3D {
{
position: { x: read_float(b, 0), y: read_float(b, 4), z: read_float(b, 8) },
target: { x: read_float(b, 12), y: read_float(b, 16), z: read_float(b, 20) },
up: { x: read_float(b, 24), y: read_float(b, 28), z: read_float(b, 32) },
fovy: read_float(b, 36),
projection: read_int(b, 40),
}
}
// Camera mode constants
///|
/// Custom camera mode, controlled by user (UpdateCamera() does nothing).
pub const CameraCustom : Int = 0
///|
/// Camera free mode.
pub const CameraFree : Int = 1
///|
/// Camera orbital mode, around target, zoom supported.
pub const CameraOrbital : Int = 2
///|
/// Camera first person mode.
pub const CameraFirstPerson : Int = 3
///|
/// Camera third person mode.
pub const CameraThirdPerson : Int = 4
// Camera projection constants
///|
/// Perspective projection.
pub const CameraPerspective : Int = 0
///|
/// Orthographic projection.
pub const CameraOrthographic : Int = 1
// Re-export passthrough camera functions
///|
pub using @ffi {end_mode_2d, end_mode_3d}
// Camera wrappers
///|
/// Begin 2D mode with custom camera (2D).
pub fn begin_mode_2d(camera : Camera2D) -> Unit {
@ffi.begin_mode_2d(camera.to_bytes())
}
///|
/// Begin 3D mode with custom camera (3D).
pub fn begin_mode_3d(camera : Camera3D) -> Unit {
@ffi.begin_mode_3d(camera.to_bytes())
}
///|
/// Update camera position for selected mode.
pub fn update_camera(camera : Camera3D, mode : Int) -> Camera3D {
Camera3D::from_bytes(@ffi.update_camera(camera.to_bytes(), mode))
}
///|
/// Update camera movement/rotation.
pub fn update_camera_pro(
camera : Camera3D,
movement : Vector3,
rotation : Vector3,
zoom : Float,
) -> Camera3D {
Camera3D::from_bytes(
@ffi.update_camera_pro(
camera.to_bytes(),
movement.to_bytes(),
rotation.to_bytes(),
zoom,
),
)
}
///|
/// Get the screen space position for a 3D world space position.
pub fn get_world_to_screen(position : Vector3, camera : Camera3D) -> Vector2 {
Vector2::from_bytes(
@ffi.get_world_to_screen(position.to_bytes(), camera.to_bytes()),
)
}
///|
/// Get the world space position for a 2D camera screen space position.
pub fn get_screen_to_world_2d(position : Vector2, camera : Camera2D) -> Vector2 {
let inv = Matrix::invert(get_camera_matrix_2d(camera))
let v = Vector3::transform({ x: position.x, y: position.y, z: 0.0 }, inv)
{ x: v.x, y: v.y }
}
///|
/// Get the screen space position for a 2D camera world space position.
pub fn get_world_to_screen_2d(position : Vector2, camera : Camera2D) -> Vector2 {
let mat = get_camera_matrix_2d(camera)
let v = Vector3::transform({ x: position.x, y: position.y, z: 0.0 }, mat)
{ x: v.x, y: v.y }
}
// ============================================================================
// Camera matrix
// ============================================================================
///|
/// Get camera transform matrix (view matrix).
pub fn get_camera_matrix(camera : Camera3D) -> Matrix {
Matrix::look_at(camera.position, camera.target, camera.up)
}
///|
/// Get camera 2D transform matrix.
pub fn get_camera_matrix_2d(camera : Camera2D) -> Matrix {
let mat_origin = Matrix::translate(-camera.target.x, -camera.target.y, 0.0)
let mat_rotation = Matrix::rotate(
{ x: 0.0, y: 0.0, z: 1.0 },
camera.rotation * 0.017453292519943295,
)
let mat_scale = Matrix::scale(camera.zoom, camera.zoom, 1.0)
let mat_translation = Matrix::translate(camera.offset.x, camera.offset.y, 0.0)
Matrix::multiply(
Matrix::multiply(mat_origin, Matrix::multiply(mat_scale, mat_rotation)),
mat_translation,
)
}
///|
/// Get a ray trace from screen position (i.e mouse).
pub fn get_screen_to_world_ray(position : Vector2, camera : Camera3D) -> Ray {
Ray::from_bytes(
@ffi.get_screen_to_world_ray(position.to_bytes(), camera.to_bytes()),
)
}
///|
/// Get a ray trace from screen position (i.e mouse) in a viewport.
pub fn get_screen_to_world_ray_ex(
position : Vector2,
camera : Camera3D,
width : Int,
height : Int,
) -> Ray {
Ray::from_bytes(
@ffi.get_screen_to_world_ray_ex(
position.to_bytes(),
camera.to_bytes(),
width,
height,
),
)
}
///|
/// Get size position for a 3D world space position.
pub fn get_world_to_screen_ex(
position : Vector3,
camera : Camera3D,
width : Int,
height : Int,
) -> Vector2 {
Vector2::from_bytes(
@ffi.get_world_to_screen_ex(
position.to_bytes(),
camera.to_bytes(),
width,
height,
),
)
}