use super::{Mesh, Vertex};
use nalgebra_glm::vec3;
use std::f32::consts::PI;
pub fn create_cube_mesh() -> Mesh {
let positions = vec![
vec3(-0.5, -0.5, 0.5),
vec3(0.5, -0.5, 0.5),
vec3(0.5, 0.5, 0.5),
vec3(-0.5, 0.5, 0.5),
vec3(-0.5, -0.5, -0.5),
vec3(-0.5, 0.5, -0.5),
vec3(0.5, 0.5, -0.5),
vec3(0.5, -0.5, -0.5),
vec3(0.5, -0.5, -0.5),
vec3(0.5, 0.5, -0.5),
vec3(0.5, 0.5, 0.5),
vec3(0.5, -0.5, 0.5),
vec3(-0.5, -0.5, -0.5),
vec3(-0.5, -0.5, 0.5),
vec3(-0.5, 0.5, 0.5),
vec3(-0.5, 0.5, -0.5),
vec3(-0.5, 0.5, -0.5),
vec3(-0.5, 0.5, 0.5),
vec3(0.5, 0.5, 0.5),
vec3(0.5, 0.5, -0.5),
vec3(-0.5, -0.5, -0.5),
vec3(0.5, -0.5, -0.5),
vec3(0.5, -0.5, 0.5),
vec3(-0.5, -0.5, 0.5),
];
let normals = vec![
vec3(0.0, 0.0, 1.0),
vec3(0.0, 0.0, 1.0),
vec3(0.0, 0.0, 1.0),
vec3(0.0, 0.0, 1.0),
vec3(0.0, 0.0, -1.0),
vec3(0.0, 0.0, -1.0),
vec3(0.0, 0.0, -1.0),
vec3(0.0, 0.0, -1.0),
vec3(1.0, 0.0, 0.0),
vec3(1.0, 0.0, 0.0),
vec3(1.0, 0.0, 0.0),
vec3(1.0, 0.0, 0.0),
vec3(-1.0, 0.0, 0.0),
vec3(-1.0, 0.0, 0.0),
vec3(-1.0, 0.0, 0.0),
vec3(-1.0, 0.0, 0.0),
vec3(0.0, 1.0, 0.0),
vec3(0.0, 1.0, 0.0),
vec3(0.0, 1.0, 0.0),
vec3(0.0, 1.0, 0.0),
vec3(0.0, -1.0, 0.0),
vec3(0.0, -1.0, 0.0),
vec3(0.0, -1.0, 0.0),
vec3(0.0, -1.0, 0.0),
];
let uvs = vec![
[0.0, 1.0],
[1.0, 1.0],
[1.0, 0.0],
[0.0, 0.0],
[0.0, 1.0],
[0.0, 0.0],
[1.0, 0.0],
[1.0, 1.0],
[0.0, 1.0],
[0.0, 0.0],
[1.0, 0.0],
[1.0, 1.0],
[0.0, 1.0],
[1.0, 1.0],
[1.0, 0.0],
[0.0, 0.0],
[0.0, 1.0],
[1.0, 1.0],
[1.0, 0.0],
[0.0, 0.0],
[0.0, 1.0],
[1.0, 1.0],
[1.0, 0.0],
[0.0, 0.0],
];
let indices = vec![
0, 1, 2, 2, 3, 0, 4, 5, 6, 6, 7, 4, 8, 9, 10, 10, 11, 8, 12, 13, 14, 14, 15, 12, 16, 17,
18, 18, 19, 16, 20, 21, 22, 22, 23, 20,
];
let vertices = positions
.into_iter()
.zip(normals)
.zip(uvs)
.map(|((pos, norm), uv)| Vertex::with_tex_coords(pos, norm, uv))
.collect();
Mesh::new(vertices, indices)
}
pub fn create_sphere_mesh(radius: f32, segments: u32) -> Mesh {
let mut vertices = Vec::new();
let mut indices = Vec::new();
for i in 0..=segments {
let lat = PI * (i as f32) / segments as f32;
let v = i as f32 / segments as f32;
for j in 0..=segments {
let lon = 2.0 * PI * (j as f32) / segments as f32;
let u = j as f32 / segments as f32;
let x = radius * lat.sin() * lon.cos();
let y = radius * lat.cos();
let z = radius * lat.sin() * lon.sin();
let pos = vec3(x, y, z);
let normal = nalgebra_glm::normalize(&pos);
vertices.push(Vertex::with_tex_coords(pos, normal, [u, v]));
}
}
for i in 0..segments {
for j in 0..segments {
let first = i * (segments + 1) + j;
let second = first + segments + 1;
indices.extend_from_slice(&[first, first + 1, second, second, first + 1, second + 1]);
}
}
Mesh::new(vertices, indices)
}
pub fn create_plane_mesh(size: f32) -> Mesh {
let half_size = size / 2.0;
let positions = vec![
vec3(-half_size, 0.0, -half_size),
vec3(half_size, 0.0, -half_size),
vec3(half_size, 0.0, half_size),
vec3(-half_size, 0.0, half_size),
];
let uvs = vec![[0.0, 1.0], [1.0, 1.0], [1.0, 0.0], [0.0, 0.0]];
let normal = vec3(0.0, 1.0, 0.0);
let vertices = positions
.into_iter()
.zip(uvs)
.map(|(pos, uv)| Vertex::with_tex_coords(pos, normal, uv))
.collect();
let indices = vec![0, 2, 1, 2, 0, 3];
Mesh::new(vertices, indices)
}
pub fn create_subdivided_plane_mesh(size: f32, subdivisions: u32) -> Mesh {
let half = size / 2.0;
let step = size / subdivisions as f32;
let uv_step = 1.0 / subdivisions as f32;
let mut vertices = Vec::new();
let mut indices = Vec::new();
let normal = vec3(0.0, 1.0, 0.0);
for row in 0..=subdivisions {
for col in 0..=subdivisions {
let x = -half + col as f32 * step;
let z = -half + row as f32 * step;
let u = col as f32 * uv_step;
let v = row as f32 * uv_step;
vertices.push(Vertex::with_tex_coords(
vec3(x, 0.0, z),
normal,
[u, 1.0 - v],
));
}
}
let verts_per_row = subdivisions + 1;
for row in 0..subdivisions {
for col in 0..subdivisions {
let top_left = row * verts_per_row + col;
let top_right = top_left + 1;
let bottom_left = top_left + verts_per_row;
let bottom_right = bottom_left + 1;
indices.push(top_left);
indices.push(bottom_right);
indices.push(top_right);
indices.push(bottom_right);
indices.push(top_left);
indices.push(bottom_left);
}
}
Mesh::new(vertices, indices)
}
pub fn create_cylinder_mesh(radius: f32, height: f32, segments: u32) -> Mesh {
let mut vertices = Vec::new();
let mut indices = Vec::new();
let half_height = height / 2.0;
for i in 0..=segments {
let angle = 2.0 * PI * (i as f32) / segments as f32;
let u = i as f32 / segments as f32;
let x = radius * angle.cos();
let z = radius * angle.sin();
vertices.push(Vertex::with_tex_coords(
vec3(x, half_height, z),
vec3(angle.cos(), 0.0, angle.sin()),
[u, 0.0],
));
vertices.push(Vertex::with_tex_coords(
vec3(x, -half_height, z),
vec3(angle.cos(), 0.0, angle.sin()),
[u, 1.0],
));
}
for i in 0..segments {
let start = 2 * i;
indices.extend_from_slice(&[start, start + 2, start + 1, start + 1, start + 2, start + 3]);
}
let top_center_idx = vertices.len() as u32;
vertices.push(Vertex::with_tex_coords(
vec3(0.0, half_height, 0.0),
vec3(0.0, 1.0, 0.0),
[0.5, 0.5],
));
vertices.push(Vertex::with_tex_coords(
vec3(0.0, -half_height, 0.0),
vec3(0.0, -1.0, 0.0),
[0.5, 0.5],
));
for i in 0..segments {
let angle = 2.0 * PI * (i as f32) / segments as f32;
let u = angle.cos() * 0.5 + 0.5;
let v = angle.sin() * 0.5 + 0.5;
let x = radius * angle.cos();
let z = radius * angle.sin();
vertices.push(Vertex::with_tex_coords(
vec3(x, half_height, z),
vec3(0.0, 1.0, 0.0),
[u, v],
));
vertices.push(Vertex::with_tex_coords(
vec3(x, -half_height, z),
vec3(0.0, -1.0, 0.0),
[u, v],
));
}
for i in 0..segments {
let top_idx = top_center_idx + 2 + (i * 2);
let next_top_idx = top_center_idx + 2 + (((i + 1) % segments) * 2);
let bottom_idx = top_center_idx + 3 + (i * 2);
let next_bottom_idx = top_center_idx + 3 + (((i + 1) % segments) * 2);
indices.extend_from_slice(&[top_center_idx, next_top_idx, top_idx]);
indices.extend_from_slice(&[top_center_idx + 1, bottom_idx, next_bottom_idx]);
}
Mesh::new(vertices, indices)
}
pub fn create_cone_mesh(radius: f32, height: f32, segments: u32) -> Mesh {
let mut vertices = Vec::new();
let mut indices = Vec::new();
let half_height = height / 2.0;
vertices.push(Vertex::with_tex_coords(
vec3(0.0, half_height, 0.0),
vec3(0.0, 1.0, 0.0),
[0.5, 0.5],
));
for i in 0..segments {
let angle = 2.0 * PI * (i as f32) / segments as f32;
let u = i as f32 / segments as f32;
let x = radius * angle.cos();
let z = radius * angle.sin();
let side_normal = vec3(angle.cos(), 0.5, angle.sin());
vertices.push(Vertex::with_tex_coords(
vec3(x, -half_height, z),
nalgebra_glm::normalize(&side_normal),
[u, 1.0],
));
}
for i in 1..=segments {
let next_index = if i == segments { 1 } else { i + 1 };
indices.extend_from_slice(&[0, next_index, i]);
}
let base_center_idx = vertices.len() as u32;
vertices.push(Vertex::with_tex_coords(
vec3(0.0, -half_height, 0.0),
vec3(0.0, -1.0, 0.0),
[0.5, 0.5],
));
for i in 0..segments {
let angle = 2.0 * PI * (i as f32) / segments as f32;
let u = angle.cos() * 0.5 + 0.5;
let v = angle.sin() * 0.5 + 0.5;
let x = radius * angle.cos();
let z = radius * angle.sin();
vertices.push(Vertex::with_tex_coords(
vec3(x, -half_height, z),
vec3(0.0, -1.0, 0.0),
[u, v],
));
}
for i in 0..segments {
let base_vertex = base_center_idx + 1 + i;
let next_vertex = base_center_idx + 1 + ((i + 1) % segments);
indices.extend_from_slice(&[base_center_idx, base_vertex, next_vertex]);
}
Mesh::new(vertices, indices)
}
pub fn create_torus_mesh(
major_radius: f32,
minor_radius: f32,
major_segments: u32,
minor_segments: u32,
) -> Mesh {
let mut vertices = Vec::new();
let mut indices = Vec::new();
for i in 0..=major_segments {
let major_angle = 2.0 * PI * (i as f32) / major_segments as f32;
let u = i as f32 / major_segments as f32;
let center_x = major_radius * major_angle.cos();
let center_z = major_radius * major_angle.sin();
for j in 0..=minor_segments {
let minor_angle = 2.0 * PI * (j as f32) / minor_segments as f32;
let v = j as f32 / minor_segments as f32;
let x = minor_angle.cos() * minor_radius;
let y = minor_angle.sin() * minor_radius;
let pos = vec3(
center_x + x * major_angle.cos(),
y,
center_z + x * major_angle.sin(),
);
let normal = vec3(
major_angle.cos() * minor_angle.cos(),
minor_angle.sin(),
major_angle.sin() * minor_angle.cos(),
);
vertices.push(Vertex::with_tex_coords(
pos,
nalgebra_glm::normalize(&normal),
[u, v],
));
}
}
for i in 0..major_segments {
for j in 0..minor_segments {
let current = i * (minor_segments + 1) + j;
let next_major = ((i + 1) % major_segments) * (minor_segments + 1) + j;
indices.extend_from_slice(&[
current,
current + 1,
next_major,
next_major,
current + 1,
next_major + 1,
]);
}
}
Mesh::new(vertices, indices)
}