#[cfg(not(feature = "std"))]
use crate::extensions::*;
use crate::math::radians;
pub fn rotate_x_vertex_3d(
angle_degrees: f64,
rotation_center: Point3D,
vertex: &mut Vertex3D,
) {
let angle_radians = radians(angle_degrees);
let cos_a = angle_radians.cos();
let sin_a = angle_radians.sin();
let (cx, cy, cz) =
(rotation_center.x, rotation_center.y, rotation_center.z);
let x = vertex.x - cx;
let y = vertex.y - cy;
let z = vertex.z - cz;
let new_y = cos_a.mul_add(y, -(sin_a * (z)));
let new_z = sin_a.mul_add(y, cos_a * (z));
vertex.x = x + cx;
vertex.y = new_y + cy;
vertex.z = new_z + cz;
}
pub fn rotate_x_polygon_3d(
angle_degrees: f64,
rotation_center: Point3D,
polygon: &mut Polygon,
) {
rotate_x_vertex_3d(angle_degrees, rotation_center, &mut polygon.point1);
rotate_x_vertex_3d(angle_degrees, rotation_center, &mut polygon.point2);
rotate_x_vertex_3d(angle_degrees, rotation_center, &mut polygon.point3);
}
pub fn rotate_y_polygon_3d(
angle_degrees: f64,
rotation_center: Point3D,
polygon: &mut Polygon,
) {
rotate_y_vertex_3d(angle_degrees, rotation_center, &mut polygon.point1);
rotate_y_vertex_3d(angle_degrees, rotation_center, &mut polygon.point2);
rotate_y_vertex_3d(angle_degrees, rotation_center, &mut polygon.point3);
}
pub fn rotate_z_polygon_3d(
angle_degrees: f64,
rotation_center: Point3D,
polygon: &mut Polygon,
) {
rotate_z_vertex_3d(angle_degrees, rotation_center, &mut polygon.point1);
rotate_z_vertex_3d(angle_degrees, rotation_center, &mut polygon.point2);
rotate_z_vertex_3d(angle_degrees, rotation_center, &mut polygon.point3);
}
pub fn rotate_y_vertex_3d(
angle_degrees: f64,
rotation_center: Point3D,
vertex: &mut Vertex3D,
) {
let angle_radians = radians(angle_degrees);
let cos_a = angle_radians.cos();
let sin_a = angle_radians.sin();
let (cx, cy, cz) =
(rotation_center.x, rotation_center.y, rotation_center.z);
let x = vertex.x - cx;
let y = vertex.y - cy;
let z = vertex.z - cz;
let new_x = cos_a.mul_add(x, sin_a * (z));
let new_z = (-sin_a).mul_add(x, cos_a * (z));
vertex.x = new_x + cx;
vertex.y = y + cy;
vertex.z = new_z + cz;
}
pub fn rotate_z_vertex_3d(
angle_degrees: f64,
rotation_center: Point3D,
vertex: &mut Vertex3D,
) {
let angle_radians = radians(angle_degrees);
let cos_a = angle_radians.cos();
let sin_a = angle_radians.sin();
let (cx, cy, cz) =
(rotation_center.x, rotation_center.y, rotation_center.z);
let x = vertex.x - cx;
let y = vertex.y - cy;
let z = vertex.z - cz;
let new_x = cos_a.mul_add(x, -(sin_a * (y)));
let new_y = sin_a.mul_add(x, cos_a * (y));
vertex.x = new_x + cx;
vertex.y = new_y + cy;
vertex.z = z + cz;
}
#[inline(always)]
#[allow(clippy::inline_always)]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub fn set_pixel_safe(
buffer: *mut u32,
width: usize,
height: usize,
x: usize,
y: usize,
color: u32,
) {
if x >= width || y >= height {
return;
}
unsafe {
*buffer.add(y * width + x) = color;
}
}
#[inline(always)]
#[allow(clippy::inline_always)]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub fn set_pixel_unsafe(
buffer: *mut u32,
width: usize,
x: usize,
y: usize,
color: u32,
) {
unsafe {
*buffer.add(y * width + x) = color;
}
}
#[inline]
#[must_use]
#[allow(clippy::float_cmp)]
pub fn uv_interpolate(
target_y: f32,
start_y: f32,
start_val: f32,
end_y: f32,
end_val: f32,
) -> f32 {
if start_y == end_y {
return start_val;
}
start_val + (end_val - start_val) * (target_y - start_y) / (end_y - start_y)
}
#[cfg_attr(feature = "bitcode", derive(bitcode::Encode, bitcode::Decode))]
#[cfg_attr(
feature = "wincode",
derive(wincode::SchemaWrite, wincode::SchemaRead)
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "c_compatible", repr(C))]
pub struct Polygon {
pub point1: Vertex3D,
pub point2: Vertex3D,
pub point3: Vertex3D,
}
#[cfg_attr(feature = "bitcode", derive(bitcode::Encode, bitcode::Decode))]
#[cfg_attr(
feature = "wincode",
derive(wincode::SchemaWrite, wincode::SchemaRead)
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "c_compatible", repr(C))]
pub struct Vertex3D {
pub x: f64,
pub y: f64,
pub z: f64,
pub u: f32,
pub v: f32,
}
#[cfg_attr(feature = "bitcode", derive(bitcode::Encode, bitcode::Decode))]
#[cfg_attr(
feature = "wincode",
derive(wincode::SchemaWrite, wincode::SchemaRead)
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "c_compatible", repr(C))]
pub struct Point3D {
pub x: f64,
pub y: f64,
pub z: f64,
}
#[cfg_attr(feature = "bitcode", derive(bitcode::Encode, bitcode::Decode))]
#[cfg_attr(
feature = "wincode",
derive(wincode::SchemaWrite, wincode::SchemaRead)
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "c_compatible", repr(C))]
pub struct Point2D {
pub x: f64,
pub y: f64,
}
#[must_use]
#[allow(clippy::cast_precision_loss)]
#[allow(clippy::cast_possible_truncation)]
pub fn vertex_3d_to_2d(
vertex: &Vertex3D,
width: usize,
height: usize,
) -> (isize, isize) {
let half_width = (width / 2) as f64;
let half_height = (height / 2) as f64;
let x = vertex.x;
let y = vertex.y;
let z = vertex.z;
let screen_x = (x - half_width) / z + half_width;
let screen_y = (y - half_height) / z + half_height;
(screen_x as isize, screen_y as isize)
}