use blinc_core::draw::Vertex;
use std::f32::consts::PI;
type BoxFace = ([f32; 3], [f32; 3], [[f32; 3]; 4]);
pub struct Geometry;
impl Geometry {
pub fn cube(size: f32) -> (Vec<Vertex>, Vec<u32>) {
Self::box_(size, size, size)
}
pub fn box_(width: f32, height: f32, depth: f32) -> (Vec<Vertex>, Vec<u32>) {
let (hw, hh, hd) = (width * 0.5, height * 0.5, depth * 0.5);
#[rustfmt::skip]
let faces: &[BoxFace] = &[
([0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [[-hw,-hh, hd],[ hw,-hh, hd],[ hw, hh, hd],[-hw, hh, hd]]), ([0.0, 0.0,-1.0], [-1.0,0.0, 0.0], [[ hw,-hh,-hd],[-hw,-hh,-hd],[-hw, hh,-hd],[ hw, hh,-hd]]), ([0.0, 1.0, 0.0], [1.0, 0.0, 0.0], [[-hw, hh, hd],[ hw, hh, hd],[ hw, hh,-hd],[-hw, hh,-hd]]), ([0.0,-1.0, 0.0], [1.0, 0.0, 0.0], [[-hw,-hh,-hd],[ hw,-hh,-hd],[ hw,-hh, hd],[-hw,-hh, hd]]), ([1.0, 0.0, 0.0], [0.0, 0.0, 1.0], [[ hw,-hh, hd],[ hw,-hh,-hd],[ hw, hh,-hd],[ hw, hh, hd]]), ([-1.0,0.0, 0.0], [0.0, 0.0,-1.0], [[-hw,-hh,-hd],[-hw,-hh, hd],[-hw, hh, hd],[-hw, hh,-hd]]), ];
let uvs = [[0.0, 1.0], [1.0, 1.0], [1.0, 0.0], [0.0, 0.0]];
let mut vertices = Vec::with_capacity(24);
let mut indices = Vec::with_capacity(36);
for (normal, _, positions) in faces {
let base = vertices.len() as u32;
for (i, pos) in positions.iter().enumerate() {
vertices.push(Vertex::new(*pos).with_normal(*normal).with_uv(uvs[i]));
}
indices.extend_from_slice(&[base, base + 1, base + 2, base, base + 2, base + 3]);
}
(vertices, indices)
}
pub fn sphere(radius: f32, segments: u32) -> (Vec<Vertex>, Vec<u32>) {
let rings = segments;
let sectors = segments;
let mut vertices = Vec::with_capacity(((rings + 1) * (sectors + 1)) as usize);
let mut indices = Vec::with_capacity((rings * sectors * 6) as usize);
for r in 0..=rings {
let v = r as f32 / rings as f32;
let phi = v * PI;
let sin_phi = phi.sin();
let cos_phi = phi.cos();
for s in 0..=sectors {
let u = s as f32 / sectors as f32;
let theta = u * 2.0 * PI;
let sin_theta = theta.sin();
let cos_theta = theta.cos();
let nx = sin_phi * cos_theta;
let ny = cos_phi;
let nz = sin_phi * sin_theta;
vertices.push(
Vertex::new([nx * radius, ny * radius, nz * radius])
.with_normal([nx, ny, nz])
.with_uv([u, v]),
);
}
}
for r in 0..rings {
for s in 0..sectors {
let a = r * (sectors + 1) + s;
let b = a + sectors + 1;
indices.extend_from_slice(&[a, b, a + 1, b, b + 1, a + 1]);
}
}
(vertices, indices)
}
pub fn plane(width: f32, depth: f32) -> (Vec<Vertex>, Vec<u32>) {
let (hw, hd) = (width * 0.5, depth * 0.5);
let vertices = vec![
Vertex::new([-hw, 0.0, -hd])
.with_normal([0.0, 1.0, 0.0])
.with_uv([0.0, 0.0]),
Vertex::new([hw, 0.0, -hd])
.with_normal([0.0, 1.0, 0.0])
.with_uv([1.0, 0.0]),
Vertex::new([hw, 0.0, hd])
.with_normal([0.0, 1.0, 0.0])
.with_uv([1.0, 1.0]),
Vertex::new([-hw, 0.0, hd])
.with_normal([0.0, 1.0, 0.0])
.with_uv([0.0, 1.0]),
];
let indices = vec![0, 2, 1, 0, 3, 2];
(vertices, indices)
}
pub fn cylinder(radius: f32, height: f32, segments: u32) -> (Vec<Vertex>, Vec<u32>) {
let half_h = height * 0.5;
let mut vertices = Vec::new();
let mut indices = Vec::new();
for i in 0..=segments {
let u = i as f32 / segments as f32;
let theta = u * 2.0 * PI;
let (sin_t, cos_t) = (theta.sin(), theta.cos());
let nx = cos_t;
let nz = sin_t;
vertices.push(
Vertex::new([nx * radius, -half_h, nz * radius])
.with_normal([nx, 0.0, nz])
.with_uv([u, 1.0]),
);
vertices.push(
Vertex::new([nx * radius, half_h, nz * radius])
.with_normal([nx, 0.0, nz])
.with_uv([u, 0.0]),
);
}
for i in 0..segments {
let base = i * 2;
indices.extend_from_slice(&[base, base + 1, base + 2, base + 1, base + 3, base + 2]);
}
let top_center = vertices.len() as u32;
vertices.push(
Vertex::new([0.0, half_h, 0.0])
.with_normal([0.0, 1.0, 0.0])
.with_uv([0.5, 0.5]),
);
for i in 0..=segments {
let theta = (i as f32 / segments as f32) * 2.0 * PI;
let (sin_t, cos_t) = (theta.sin(), theta.cos());
vertices.push(
Vertex::new([cos_t * radius, half_h, sin_t * radius])
.with_normal([0.0, 1.0, 0.0])
.with_uv([cos_t * 0.5 + 0.5, sin_t * 0.5 + 0.5]),
);
}
for i in 0..segments {
indices.extend_from_slice(&[top_center, top_center + 1 + i, top_center + 2 + i]);
}
let bot_center = vertices.len() as u32;
vertices.push(
Vertex::new([0.0, -half_h, 0.0])
.with_normal([0.0, -1.0, 0.0])
.with_uv([0.5, 0.5]),
);
for i in 0..=segments {
let theta = (i as f32 / segments as f32) * 2.0 * PI;
let (sin_t, cos_t) = (theta.sin(), theta.cos());
vertices.push(
Vertex::new([cos_t * radius, -half_h, sin_t * radius])
.with_normal([0.0, -1.0, 0.0])
.with_uv([cos_t * 0.5 + 0.5, sin_t * 0.5 + 0.5]),
);
}
for i in 0..segments {
indices.extend_from_slice(&[bot_center, bot_center + 2 + i, bot_center + 1 + i]);
}
(vertices, indices)
}
pub fn torus(
major_radius: f32,
minor_radius: f32,
major_segments: u32,
minor_segments: u32,
) -> (Vec<Vertex>, Vec<u32>) {
let mut vertices = Vec::new();
let mut indices = Vec::new();
for i in 0..=major_segments {
let u = i as f32 / major_segments as f32;
let theta = u * 2.0 * PI;
let (sin_t, cos_t) = (theta.sin(), theta.cos());
for j in 0..=minor_segments {
let v = j as f32 / minor_segments as f32;
let phi = v * 2.0 * PI;
let (sin_p, cos_p) = (phi.sin(), phi.cos());
let x = (major_radius + minor_radius * cos_p) * cos_t;
let y = minor_radius * sin_p;
let z = (major_radius + minor_radius * cos_p) * sin_t;
let nx = cos_p * cos_t;
let ny = sin_p;
let nz = cos_p * sin_t;
vertices.push(
Vertex::new([x, y, z])
.with_normal([nx, ny, nz])
.with_uv([u, v]),
);
}
}
for i in 0..major_segments {
for j in 0..minor_segments {
let a = i * (minor_segments + 1) + j;
let b = a + minor_segments + 1;
indices.extend_from_slice(&[a, b, a + 1, b, b + 1, a + 1]);
}
}
(vertices, indices)
}
pub fn grid(
size: f32,
divisions: u32,
subdivisions: u32,
line_width: f32,
) -> (Vec<Vertex>, Vec<u32>) {
let mut vertices = Vec::new();
let mut indices = Vec::new();
let half = size * 0.5;
let total_lines = divisions * subdivisions;
let step = size / total_lines as f32;
let hw = line_width * 0.5;
let minor_color = [0.35, 0.35, 0.35, 0.4];
let major_color = [0.5, 0.5, 0.5, 0.6];
let x_axis_color = [0.7, 0.2, 0.2, 0.7];
let z_axis_color = [0.2, 0.3, 0.7, 0.7];
for i in 0..=total_lines {
let t = -half + i as f32 * step;
let is_major = subdivisions > 0 && i % subdivisions == 0;
let color_x = if t.abs() < step * 0.5 {
z_axis_color
} else if is_major {
major_color
} else {
minor_color
};
let base = vertices.len() as u32;
vertices.push(
Vertex::new([t - hw, 0.0, -half])
.with_normal([0.0, 1.0, 0.0])
.with_color(color_x),
);
vertices.push(
Vertex::new([t + hw, 0.0, -half])
.with_normal([0.0, 1.0, 0.0])
.with_color(color_x),
);
vertices.push(
Vertex::new([t + hw, 0.0, half])
.with_normal([0.0, 1.0, 0.0])
.with_color(color_x),
);
vertices.push(
Vertex::new([t - hw, 0.0, half])
.with_normal([0.0, 1.0, 0.0])
.with_color(color_x),
);
indices.extend_from_slice(&[base, base + 1, base + 2, base, base + 2, base + 3]);
let color_z = if t.abs() < step * 0.5 {
x_axis_color
} else if is_major {
major_color
} else {
minor_color
};
let base = vertices.len() as u32;
vertices.push(
Vertex::new([-half, 0.0, t - hw])
.with_normal([0.0, 1.0, 0.0])
.with_color(color_z),
);
vertices.push(
Vertex::new([half, 0.0, t - hw])
.with_normal([0.0, 1.0, 0.0])
.with_color(color_z),
);
vertices.push(
Vertex::new([half, 0.0, t + hw])
.with_normal([0.0, 1.0, 0.0])
.with_color(color_z),
);
vertices.push(
Vertex::new([-half, 0.0, t + hw])
.with_normal([0.0, 1.0, 0.0])
.with_color(color_z),
);
indices.extend_from_slice(&[base, base + 1, base + 2, base, base + 2, base + 3]);
}
(vertices, indices)
}
}