sevenx_engine 0.2.11

Engine de jogos 2D/3D completa com suporte Android, física, áudio, partículas, tilemap, UI, eventos e sistema 3D avançado com PBR.
Documentation
// Sistema de texturas 3D
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Texture3D {
    pub width: u32,
    pub height: u32,
    pub data: Vec<u8>, // RGBA
}

impl Texture3D {
    pub fn new(width: u32, height: u32) -> Self {
        Self {
            width,
            height,
            data: vec![255; (width * height * 4) as usize],
        }
    }

    pub fn from_color(width: u32, height: u32, color: [u8; 4]) -> Self {
        let mut data = Vec::with_capacity((width * height * 4) as usize);
        for _ in 0..(width * height) {
            data.extend_from_slice(&color);
        }
        Self { width, height, data }
    }

    pub fn checkerboard(size: u32, color1: [u8; 4], color2: [u8; 4]) -> Self {
        let mut data = Vec::with_capacity((size * size * 4) as usize);
        for y in 0..size {
            for x in 0..size {
                let checker = ((x / 8) + (y / 8)) % 2 == 0;
                let color = if checker { color1 } else { color2 };
                data.extend_from_slice(&color);
            }
        }
        Self { width: size, height: size, data }
    }

    pub fn gradient_horizontal(width: u32, height: u32, color1: [u8; 4], color2: [u8; 4]) -> Self {
        let mut data = Vec::with_capacity((width * height * 4) as usize);
        for _y in 0..height {
            for x in 0..width {
                let t = x as f32 / width as f32;
                let r = (color1[0] as f32 * (1.0 - t) + color2[0] as f32 * t) as u8;
                let g = (color1[1] as f32 * (1.0 - t) + color2[1] as f32 * t) as u8;
                let b = (color1[2] as f32 * (1.0 - t) + color2[2] as f32 * t) as u8;
                let a = (color1[3] as f32 * (1.0 - t) + color2[3] as f32 * t) as u8;
                data.extend_from_slice(&[r, g, b, a]);
            }
        }
        Self { width, height, data }
    }

    pub fn sample(&self, u: f32, v: f32) -> [u8; 4] {
        let u = u.fract();
        let v = v.fract();
        
        let x = (u * self.width as f32) as u32 % self.width;
        let y = (v * self.height as f32) as u32 % self.height;
        
        let idx = ((y * self.width + x) * 4) as usize;
        if idx + 3 < self.data.len() {
            [
                self.data[idx],
                self.data[idx + 1],
                self.data[idx + 2],
                self.data[idx + 3],
            ]
        } else {
            [255, 255, 255, 255]
        }
    }

    pub fn sample_bilinear(&self, u: f32, v: f32) -> [u8; 4] {
        let u = u.fract();
        let v = v.fract();
        
        let x = u * (self.width - 1) as f32;
        let y = v * (self.height - 1) as f32;
        
        let x0 = x.floor() as u32;
        let y0 = y.floor() as u32;
        let x1 = (x0 + 1).min(self.width - 1);
        let y1 = (y0 + 1).min(self.height - 1);
        
        let fx = x - x0 as f32;
        let fy = y - y0 as f32;
        
        let c00 = self.get_pixel(x0, y0);
        let c10 = self.get_pixel(x1, y0);
        let c01 = self.get_pixel(x0, y1);
        let c11 = self.get_pixel(x1, y1);
        
        let mut result = [0u8; 4];
        for i in 0..4 {
            let top = c00[i] as f32 * (1.0 - fx) + c10[i] as f32 * fx;
            let bottom = c01[i] as f32 * (1.0 - fx) + c11[i] as f32 * fx;
            result[i] = (top * (1.0 - fy) + bottom * fy) as u8;
        }
        result
    }

    fn get_pixel(&self, x: u32, y: u32) -> [u8; 4] {
        let idx = ((y * self.width + x) * 4) as usize;
        if idx + 3 < self.data.len() {
            [
                self.data[idx],
                self.data[idx + 1],
                self.data[idx + 2],
                self.data[idx + 3],
            ]
        } else {
            [255, 255, 255, 255]
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Material3D {
    pub albedo: [u8; 4],
    pub metallic: f32,
    pub roughness: f32,
    pub emission: [u8; 4],
    pub emission_strength: f32,
    pub texture: Option<Texture3D>,
    pub normal_map: Option<Texture3D>,
    pub use_texture: bool,
}

impl Material3D {
    pub fn new(color: [u8; 4]) -> Self {
        Self {
            albedo: color,
            metallic: 0.0,
            roughness: 0.5,
            emission: [0, 0, 0, 0],
            emission_strength: 0.0,
            texture: None,
            normal_map: None,
            use_texture: false,
        }
    }

    pub fn with_texture(mut self, texture: Texture3D) -> Self {
        self.texture = Some(texture);
        self.use_texture = true;
        self
    }

    pub fn with_normal_map(mut self, normal_map: Texture3D) -> Self {
        self.normal_map = Some(normal_map);
        self
    }

    pub fn with_metallic(mut self, metallic: f32) -> Self {
        self.metallic = metallic.clamp(0.0, 1.0);
        self
    }

    pub fn with_roughness(mut self, roughness: f32) -> Self {
        self.roughness = roughness.clamp(0.0, 1.0);
        self
    }

    pub fn with_emission(mut self, color: [u8; 4], strength: f32) -> Self {
        self.emission = color;
        self.emission_strength = strength;
        self
    }

    pub fn get_color(&self, u: f32, v: f32) -> [u8; 4] {
        if self.use_texture {
            if let Some(tex) = &self.texture {
                return tex.sample_bilinear(u, v);
            }
        }
        self.albedo
    }
}

// Presets de materiais
impl Material3D {
    pub fn metal() -> Self {
        Self::new([200, 200, 200, 255])
            .with_metallic(1.0)
            .with_roughness(0.2)
    }

    pub fn plastic() -> Self {
        Self::new([255, 255, 255, 255])
            .with_metallic(0.0)
            .with_roughness(0.4)
    }

    pub fn rubber() -> Self {
        Self::new([50, 50, 50, 255])
            .with_metallic(0.0)
            .with_roughness(0.9)
    }

    pub fn glass() -> Self {
        Self::new([255, 255, 255, 100])
            .with_metallic(0.0)
            .with_roughness(0.0)
    }

    pub fn emissive(color: [u8; 4], strength: f32) -> Self {
        Self::new(color)
            .with_emission(color, strength)
    }
}