reng 0.1.1

A simple OpenGL engine with physics, UI, complex model handling and much more!
Documentation
use std::{cell::RefCell, rc::{Rc, Weak}};

use glam::{vec3, EulerRot, Mat3, Mat4, Quat, Vec3, Vec4};

use crate::{line::Line, mesh::Mesh, shapes::{make_shape, Shapes}, transform::Transform};

#[derive(Clone)]
pub struct GameObject<T>{
    pub object: T,
    pub transform: Transform,
    color: Vec4,
    pub shape: Shapes,
    pub tag: String,
    pub name: String,
    pub parent: Option<Weak<RefCell<GameObject<T>>>>,
    pub children: Vec<Rc<RefCell<GameObject<T>>>>,
}

impl GameObject<Vec<Mesh>>{
    pub fn new(meshes: Vec<Mesh>) -> Self{
        let transform = Transform::new();
        let mut object = meshes;
        for mesh in object.iter_mut(){
            mesh.set_shader("src/shaders/default_lit_shader.vs", "src/shaders/default_lit_shader.fs");
        }

        GameObject{
            object,
            transform,
            color: Vec4::ONE,
            shape: Shapes::Empty,
            tag: "".to_owned(),
            name: "".to_owned(),
            parent: None,
            children: Vec::new()
        }
    }

    pub fn draw(&self, view_position: Vec3){
        for mesh in self.object.iter(){
            mesh.draw(view_position, self.transform);
        }
        for child in self.children.iter(){
            child.borrow().draw(view_position);
        }
    }

    pub fn destroy(&mut self){
        for child in self.children.iter_mut(){
            child.borrow_mut().destroy();
        }

        for mesh in self.object.iter_mut(){
            mesh.destroy();
        }
    }

    pub fn set_shape(&mut self, new_shape: Shapes){
        self.object = make_shape(new_shape, self.transform, self.color);
        self.object[0].update_mesh();
        self.shape = new_shape;
    }

    pub fn add_shapes(&mut self, meshes: Vec<Mesh>){
        for mesh in meshes.iter(){
            self.object.push(mesh.clone());
        }
    }

    pub fn set_position(&mut self, position: Vec3){
        let delta_pos = position - self.transform.position;
        self.transform.position = position;

        for child in self.children.iter_mut(){
            child.borrow_mut().translate(delta_pos);
        }
    }

    pub fn translate(&mut self, change: Vec3){
        self.transform.position += change;
        
        for child in self.children.iter_mut(){
            child.borrow_mut().translate(change);
        }
    }

    pub fn scale(&mut self, scale: f32){
        self.transform.scale *= scale;

        for child in self.children.iter_mut(){
            child.borrow_mut().scale(scale);
        }
    }

    pub fn scale3d(&mut self, scale: Vec3){
        self.transform.scale = scale;

        for child in self.children.iter_mut(){
            child.borrow_mut().scale3d(scale);
        }
    }

    pub fn local_rotate(&mut self, rotation: Vec3) {
    // gira localmente
    self.transform.rotation *= Quat::from_euler(EulerRot::XYZ, rotation.x, rotation.y, rotation.z);

    let quat = Quat::from_euler(EulerRot::XYZ, rotation.x, rotation.y, rotation.z);
    let rot_mat = Mat4::from_quat(quat);
    let to_origin = Mat4::from_translation(-self.transform.position);
    let back = Mat4::from_translation(self.transform.position);
    let transform = back * rot_mat * to_origin;

    for child in self.children.iter_mut() {
        let mut c = child.borrow_mut();

        // atualiza posição girando em volta do parent
        let new_pos = transform.transform_point3(c.transform.position);
        c.set_position(new_pos);

        // gira o filho localmente também (se quiser que ele gire "em si")
        c.local_rotate(rotation);
    }
}



    pub fn global_rotate(&mut self, rotation: Vec3){
        let quat_rotation = Quat::from_euler(EulerRot::XYZ, rotation.x, rotation.y, rotation.z);

        self.transform.rotation = quat_rotation * self.transform.rotation;
        self.transform.position = quat_rotation * self.transform.position;

        for child in self.children.iter_mut(){
            
            let translate_to_origin = Mat4::from_translation(-self.transform.position);
            let quat = Quat::from_euler(glam::EulerRot::XYZ, rotation.x, rotation.y, rotation.z);
            let rotation_matrix = Mat4::from_quat(quat);
            let translate_back = Mat4::from_translation(self.transform.position);
            
            let mut c = child.borrow_mut();
            let transform = translate_back * rotation_matrix * translate_to_origin;

            let new_pos = transform.transform_point3(c.transform.position);
            c.global_rotate(rotation);
            c.set_position(new_pos);
        }
    }

    pub fn set_rotation(&mut self, rotation: Vec3){
        let new_rotation = Quat::from_euler(EulerRot::XYZ, rotation.x, rotation.y, rotation.z);
        let delta_rotation = new_rotation * self.transform.rotation.conjugate();

        self.transform.rotation = new_rotation;

        for child in self.children.iter_mut(){
            let mut c = child.borrow_mut();
            
            c.set_rotation(rotation);
            c.transform.position = self.transform.position + delta_rotation * (c.transform.position - self.transform.position);
        }
    }

    pub fn look_at_raw(&mut self, target_position: Vec3) -> Quat {
        let forward = (target_position - self.transform.position).normalize();

        let right = vec3(0., 1., 0.).cross(forward).normalize();

        let new_up = forward.cross(right);

        let rotation_matrix = Mat3::from_cols(right, new_up, forward);

        for child in self.children.iter_mut(){
            child.borrow_mut().set_rotation(Vec3::from(rotation_matrix.to_euler(EulerRot::XYZ)));
        }

        Quat::from_mat3(&rotation_matrix)
    }

    pub fn look_at(&mut self, target_position: Vec3) {
        let forward = (target_position - self.transform.position).normalize();

        let right = vec3(0., 1., 0.).cross(forward).normalize();

        let new_up = forward.cross(right);

        let rotation_matrix = Mat3::from_cols(right, new_up, forward);
        
        self.set_rotation(Vec3::from(Quat::from_mat3(&rotation_matrix).to_euler(EulerRot::XYZ)));
    }

    pub fn set_color(&mut self, color: Vec4){
        let fixed_color = color.clamp(Vec4::ZERO, Vec4::ONE);

        for mesh in self.object.iter_mut(){
            self.color = fixed_color;
            mesh.set_color(fixed_color);
            mesh.update_mesh();
        }
    }

    pub fn get_color(&self) -> Vec4{
        self.color
    }

    pub fn set_texture(&mut self, texture: u32){
        for mesh in self.object.iter_mut(){
            mesh.set_texture(texture);
        }
    }

    pub fn set_shader(&mut self, vert_path: &str, frag_path: &str){
        for mesh in self.object.iter_mut(){
            mesh.set_shader(vert_path, frag_path);
        }
    }

    pub fn setup_meshes(&mut self){
        for mesh in self.object.iter_mut(){
            mesh.setup_mesh();
        }
    }
}

impl GameObject<Line>{
    pub fn new(begin: Vec3, end: Vec3, bidimensional: bool) -> Self{
        let mut object = Line::new(begin, end, Vec4::ONE, bidimensional);
        object.mesh.set_shader("src/shaders/default_lit_shader.vs", "src/shaders/default_lit_shader.fs");

        Self{
            object,
            transform: Transform::new(),
            color: Vec4::ONE,
            shape: Shapes::Line,
            tag: "".to_owned(),
            name: "".to_owned(),
            parent: None,
            children: Vec::new(),
        }
    }

    pub fn set_begin(&mut self, begin: Vec3){
        self.object.begin = begin;
        self.object.update();
    }

    pub fn set_end(&mut self, end: Vec3){
        self.object.end = end;
        self.object.update();
    }

    pub fn set_color(&mut self, color: Vec4){
        self.object.color = color;
        self.object.update();
    }

    pub fn setup_mesh(&mut self){
        self.object.mesh.setup_mesh();
    }

    pub fn set_texture(&mut self, texture: u32){
        self.object.mesh.set_texture(texture);
    }

    pub fn set_shader(&mut self, vert_path: &str, frag_path: &str){
        self.object.mesh.set_shader(vert_path, frag_path);
    }

    pub fn draw(&mut self, view_position: Vec3){
        self.object.draw(view_position, self.transform);

        for child in self.children.iter_mut(){
            child.borrow_mut().draw(view_position);
        }
    }
}

pub fn quick_go(shape: Shapes, texture: u32) -> GameObject<Vec<Mesh>>{
    let mut go = GameObject::<Vec<Mesh>>::new(Mesh::empty());

    match shape{
        Shapes::Cube => go.set_shape(Shapes::Cube),
        Shapes::Sphere => go.set_shape(Shapes::Sphere),
        Shapes::Empty => go.set_shape(Shapes::Empty),
        _ => go.set_shape(Shapes::Cube),
    }
    go.set_texture(texture);
    go.setup_meshes();

    go
}