use glam::{vec2, vec3, Vec3, Vec4};
use crate::{mesh::Mesh, shader::Shader, transform::Transform, vertex::Vertex};
pub struct Line{
pub begin: Vec3,
pub end: Vec3,
pub color: Vec4,
pub bidimensional: bool,
pub mesh: Mesh,
}
impl Line{
pub fn new(begin: Vec3, end: Vec3, color: Vec4, bidimensional: bool) -> Self{
let mesh: Mesh;
if bidimensional{
mesh = make_line_2d(begin, end, color, Option::None);
}
else{
mesh = make_line_3d(begin, end, color, Option::None);
}
Self{
begin,
end,
color,
bidimensional,
mesh,
}
}
pub fn update(&mut self){
if self.bidimensional{
update_line_2d(&mut self.mesh, self.begin, self.end, self.color);
}
else{
update_line_3d(&mut self.mesh, self.begin, self.end, self.color);
}
self.mesh.update_mesh();
}
pub fn set_shader(&mut self, vert_path: &str, frag_path: &str){
self.mesh.set_shader(vert_path, frag_path);
}
pub fn draw(&self, view_position: Vec3, transform: Transform){
self.mesh.draw(view_position, transform);
}
}
pub fn make_line_2d(begin: Vec3, end: Vec3, color: Vec4, thickness: Option<f32>) -> Mesh {
let mut vertices = Vec::new();
let indices = vec![0, 1, 2, 1, 2, 3];
let line_direction = (end - begin).normalize();
let width = thickness.unwrap_or(0.1);
let perpendicular = vec3(-line_direction.y, line_direction.x, 0.0) * width;
vertices.push(Vertex {
position: begin - perpendicular, color,
tex_coords: vec2(0.0, 0.0),
normal: Vec3::ONE,
});
vertices.push(Vertex {
position: end - perpendicular, color,
tex_coords: vec2(0.0, 0.0),
normal: Vec3::ONE,
});
vertices.push(Vertex {
position: begin + perpendicular, color,
tex_coords: vec2(0.0, 0.0),
normal: Vec3::ONE,
});
vertices.push(Vertex {
position: end + perpendicular, color,
tex_coords: vec2(0.0, 0.0),
normal: Vec3::ONE,
});
Mesh::new(vertices, indices, Shader::new("src/shaders/basic_shader.vs", "src/shaders/basic_shader.fs"))
}
pub fn make_line_3d(begin: Vec3, end: Vec3, color: Vec4, thickness: Option<f32>) -> Mesh {
let mut vertices = Vec::new();
let mut indices = Vec::new();
let segments = 16;
let radius = thickness.unwrap_or(0.05);
let line_direction = (end - begin).normalize();
let up = if line_direction.dot(vec3(0.0, 1.0, 0.0)).abs() > 0.99 {
vec3(1.0, 0.0, 0.0) } else {
vec3(0.0, 1.0, 0.0)
};
let perpendicular = line_direction.cross(up).normalize() * radius;
let perpendicular2 = line_direction.cross(perpendicular).normalize() * radius;
for i in 0..segments {
let angle = 2.0 * std::f32::consts::PI * i as f32 / segments as f32;
let rotation = perpendicular * angle.cos() + perpendicular2 * angle.sin();
vertices.push(Vertex {
position: begin + rotation,
color,
tex_coords: vec2(i as f32 / segments as f32, 0.0),
normal: rotation.normalize(),
});
vertices.push(Vertex {
position: end + rotation,
color,
tex_coords: vec2(i as f32 / segments as f32, 1.0),
normal: rotation.normalize(),
});
}
for i in 0..segments {
let next = (i + 1) % segments;
indices.push(i as u32 * 2); indices.push(next as u32 * 2); indices.push(i as u32 * 2 + 1);
indices.push(next as u32 * 2); indices.push(next as u32 * 2 + 1); indices.push(i as u32 * 2 + 1); }
Mesh::new(vertices, indices, Shader::new("src/shaders/basic_shader.vs", "src/shaders/basic_shader.fs"))
}
pub fn update_line_2d(mesh: &mut Mesh, begin: Vec3, end: Vec3, color: Vec4) {
let mut vertices = Vec::new();
let indices = vec![0, 1, 2, 1, 2, 3];
let line_direction = (end - begin).normalize(); let width = 0.1;
let perpendicular = vec3(-line_direction.y, line_direction.x, 0.0) * width;
vertices.push(Vertex {
position: begin - perpendicular, color,
tex_coords: vec2(0.0, 0.0),
normal: Vec3::ONE,
});
vertices.push(Vertex {
position: end - perpendicular, color,
tex_coords: vec2(0.0, 0.0),
normal: Vec3::ONE,
});
vertices.push(Vertex {
position: begin + perpendicular, color,
tex_coords: vec2(0.0, 0.0),
normal: Vec3::ONE,
});
vertices.push(Vertex {
position: end + perpendicular, color,
tex_coords: vec2(0.0, 0.0),
normal: Vec3::ONE,
});
mesh.vertices = vertices;
mesh.indices = indices;
for vert in mesh.vertices.iter_mut(){
vert.color = color;
}
}
pub fn update_line_3d(mesh: &mut Mesh, begin: Vec3, end: Vec3, color: Vec4) {
let mut vertices = Vec::new();
let mut indices = Vec::new();
let segments = 16; let radius = 0.05;
let line_direction = (end - begin).normalize();
let up = if line_direction.dot(vec3(0.0, 1.0, 0.0)).abs() > 0.99 {
vec3(1.0, 0.0, 0.0) } else {
vec3(0.0, 1.0, 0.0)
};
let perpendicular = line_direction.cross(up).normalize() * radius;
let perpendicular2 = line_direction.cross(perpendicular).normalize() * radius;
for i in 0..segments {
let angle = 2.0 * std::f32::consts::PI * i as f32 / segments as f32;
let rotation = perpendicular * angle.cos() + perpendicular2 * angle.sin();
vertices.push(Vertex {
position: begin + rotation,
color,
tex_coords: vec2(i as f32 / segments as f32, 0.0),
normal: rotation.normalize(),
});
vertices.push(Vertex {
position: end + rotation,
color,
tex_coords: vec2(i as f32 / segments as f32, 1.0),
normal: rotation.normalize(),
});
}
for i in 0..segments {
let next = (i + 1) % segments;
indices.push(i as u32 * 2); indices.push(next as u32 * 2); indices.push(i as u32 * 2 + 1);
indices.push(next as u32 * 2); indices.push(next as u32 * 2 + 1); indices.push(i as u32 * 2 + 1); }
mesh.vertices = vertices;
mesh.indices = indices;
for vert in mesh.vertices.iter_mut(){
vert.color = color;
}
}
pub fn draw_line_2d(begin: Vec3, end: Vec3, color: Vec4, width: Option<f32>, texture: u32, view_position: Vec3) {
let mut mesh = make_line_2d(begin, end, color, width);
mesh.set_texture(texture);
mesh.setup_mesh();
mesh.draw(view_position, Transform::new());
mesh.destroy();
}
pub fn draw_line_3d(begin: Vec3, end: Vec3, color: Vec4, width: Option<f32>, texture: u32, view_position: Vec3) {
let mut mesh = make_line_3d(begin, end, color, width);
mesh.set_texture(texture);
mesh.setup_mesh();
mesh.draw(view_position, Transform::new());
mesh.destroy();
}