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
// Shaders 3D - Iluminação e Efeitos
use crate::mesh3d::Vec3;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct Light3D {
    pub position: Vec3,
    pub color: [f32; 3],
    pub intensity: f32,
}

impl Light3D {
    pub fn new(position: Vec3, color: [f32; 3], intensity: f32) -> Self {
        Self {
            position,
            color,
            intensity,
        }
    }
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct Material {
    pub ambient: [f32; 3],
    pub diffuse: [f32; 3],
    pub specular: [f32; 3],
    pub shininess: f32,
}

impl Material {
    pub fn default() -> Self {
        Self {
            ambient: [0.2, 0.2, 0.2],
            diffuse: [0.8, 0.8, 0.8],
            specular: [1.0, 1.0, 1.0],
            shininess: 32.0,
        }
    }

    pub fn metal() -> Self {
        Self {
            ambient: [0.1, 0.1, 0.1],
            diffuse: [0.5, 0.5, 0.5],
            specular: [1.0, 1.0, 1.0],
            shininess: 128.0,
        }
    }

    pub fn plastic() -> Self {
        Self {
            ambient: [0.3, 0.3, 0.3],
            diffuse: [0.7, 0.7, 0.7],
            specular: [0.5, 0.5, 0.5],
            shininess: 16.0,
        }
    }
}

pub struct PhongShader {
    pub lights: Vec<Light3D>,
    pub ambient_light: [f32; 3],
}

impl PhongShader {
    pub fn new() -> Self {
        Self {
            lights: Vec::new(),
            ambient_light: [0.1, 0.1, 0.1],
        }
    }

    pub fn add_light(&mut self, light: Light3D) {
        self.lights.push(light);
    }

    // Calcula iluminação Phong
    pub fn calculate_lighting(
        &self,
        position: &Vec3,
        normal: &Vec3,
        view_dir: &Vec3,
        material: &Material,
        base_color: [u8; 4],
    ) -> [u8; 4] {
        let mut final_color = [
            material.ambient[0] * self.ambient_light[0],
            material.ambient[1] * self.ambient_light[1],
            material.ambient[2] * self.ambient_light[2],
        ];

        for light in &self.lights {
            // Direção da luz
            let light_dir = Vec3::new(
                light.position.x - position.x,
                light.position.y - position.y,
                light.position.z - position.z,
            )
            .normalize();

            // Componente difusa
            let diff = normal.dot(&light_dir).max(0.0);
            final_color[0] += material.diffuse[0] * diff * light.color[0] * light.intensity;
            final_color[1] += material.diffuse[1] * diff * light.color[1] * light.intensity;
            final_color[2] += material.diffuse[2] * diff * light.color[2] * light.intensity;

            // Componente especular
            let reflect_dir = self.reflect(&light_dir.normalize(), normal);
            let spec = reflect_dir.dot(view_dir).max(0.0).powf(material.shininess);
            final_color[0] += material.specular[0] * spec * light.color[0] * light.intensity;
            final_color[1] += material.specular[1] * spec * light.color[1] * light.intensity;
            final_color[2] += material.specular[2] * spec * light.color[2] * light.intensity;
        }

        // Aplica cor base
        let r = (base_color[0] as f32 * final_color[0].min(1.0)) as u8;
        let g = (base_color[1] as f32 * final_color[1].min(1.0)) as u8;
        let b = (base_color[2] as f32 * final_color[2].min(1.0)) as u8;

        [r, g, b, base_color[3]]
    }

    fn reflect(&self, incident: &Vec3, normal: &Vec3) -> Vec3 {
        let dot = incident.dot(normal);
        Vec3::new(
            incident.x - 2.0 * dot * normal.x,
            incident.y - 2.0 * dot * normal.y,
            incident.z - 2.0 * dot * normal.z,
        )
    }
}

// Shader de toon/cel shading aprimorado
pub struct ToonShader {
    pub levels: u8,
    pub outline_thickness: f32,
    pub outline_color: [u8; 4],
}

impl ToonShader {
    pub fn new(levels: u8) -> Self {
        Self {
            levels,
            outline_thickness: 0.1,
            outline_color: [0, 0, 0, 255],
        }
    }

    pub fn with_outline(mut self, thickness: f32, color: [u8; 4]) -> Self {
        self.outline_thickness = thickness;
        self.outline_color = color;
        self
    }

    pub fn apply(&self, color: [u8; 4], light_intensity: f32) -> [u8; 4] {
        let step = 1.0 / self.levels as f32;
        let quantized = (light_intensity / step).floor() * step;

        [
            (color[0] as f32 * quantized) as u8,
            (color[1] as f32 * quantized) as u8,
            (color[2] as f32 * quantized) as u8,
            color[3],
        ]
    }

    pub fn should_outline(&self, normal_dot_view: f32) -> bool {
        normal_dot_view.abs() < self.outline_thickness
    }
}

// Shader de wireframe colorido
pub struct WireframeShader {
    pub line_color: [u8; 4],
    pub fill_color: [u8; 4],
    pub line_width: f32,
}

impl WireframeShader {
    pub fn new() -> Self {
        Self {
            line_color: [255, 255, 255, 255],
            fill_color: [50, 50, 50, 255],
            line_width: 2.0,
        }
    }

    pub fn with_colors(mut self, line_color: [u8; 4], fill_color: [u8; 4]) -> Self {
        self.line_color = line_color;
        self.fill_color = fill_color;
        self
    }

    pub fn with_line_width(mut self, width: f32) -> Self {
        self.line_width = width;
        self
    }
}

// Shader de Fresnel (efeito de borda brilhante)
pub struct FresnelShader {
    pub rim_color: [f32; 3],
    pub rim_power: f32,
    pub rim_intensity: f32,
}

impl FresnelShader {
    pub fn new() -> Self {
        Self {
            rim_color: [1.0, 1.0, 1.0],
            rim_power: 3.0,
            rim_intensity: 1.0,
        }
    }

    pub fn calculate(&self, normal: &Vec3, view_dir: &Vec3, base_color: [u8; 4]) -> [u8; 4] {
        let fresnel = (1.0 - normal.dot(view_dir).abs()).powf(self.rim_power) * self.rim_intensity;
        
        let r = (base_color[0] as f32 + self.rim_color[0] * fresnel * 255.0).min(255.0) as u8;
        let g = (base_color[1] as f32 + self.rim_color[1] * fresnel * 255.0).min(255.0) as u8;
        let b = (base_color[2] as f32 + self.rim_color[2] * fresnel * 255.0).min(255.0) as u8;
        
        [r, g, b, base_color[3]]
    }
}

// Shader de Normal Mapping (simulado)
pub struct NormalMapShader {
    pub bump_strength: f32,
}

impl NormalMapShader {
    pub fn new(bump_strength: f32) -> Self {
        Self { bump_strength }
    }

    pub fn perturb_normal(&self, normal: &Vec3, u: f32, v: f32) -> Vec3 {
        // Simula um bump map procedural
        let bump_x = (u * 10.0).sin() * self.bump_strength;
        let bump_y = (v * 10.0).sin() * self.bump_strength;
        
        Vec3::new(
            normal.x + bump_x,
            normal.y + bump_y,
            normal.z,
        ).normalize()
    }
}

// Shader de Reflexão
pub struct ReflectionShader {
    pub reflectivity: f32,
    pub environment_color: [f32; 3],
}

impl ReflectionShader {
    pub fn new() -> Self {
        Self {
            reflectivity: 0.5,
            environment_color: [0.5, 0.7, 1.0],
        }
    }

    pub fn calculate(&self, normal: &Vec3, view_dir: &Vec3, base_color: [u8; 4]) -> [u8; 4] {
        let reflect_dir = self.reflect(view_dir, normal);
        let reflection_factor = reflect_dir.y.max(0.0) * self.reflectivity;
        
        let r = ((base_color[0] as f32 * (1.0 - reflection_factor)) + 
                 (self.environment_color[0] * 255.0 * reflection_factor)).min(255.0) as u8;
        let g = ((base_color[1] as f32 * (1.0 - reflection_factor)) + 
                 (self.environment_color[1] * 255.0 * reflection_factor)).min(255.0) as u8;
        let b = ((base_color[2] as f32 * (1.0 - reflection_factor)) + 
                 (self.environment_color[2] * 255.0 * reflection_factor)).min(255.0) as u8;
        
        [r, g, b, base_color[3]]
    }

    fn reflect(&self, incident: &Vec3, normal: &Vec3) -> Vec3 {
        let dot = incident.dot(normal);
        Vec3::new(
            incident.x - 2.0 * dot * normal.x,
            incident.y - 2.0 * dot * normal.y,
            incident.z - 2.0 * dot * normal.z,
        )
    }
}

// Shader de Fog (neblina)
pub struct FogShader {
    pub fog_color: [u8; 4],
    pub fog_density: f32,
    pub fog_start: f32,
    pub fog_end: f32,
}

impl FogShader {
    pub fn new() -> Self {
        Self {
            fog_color: [200, 200, 220, 255],
            fog_density: 0.05,
            fog_start: 10.0,
            fog_end: 50.0,
        }
    }

    pub fn apply(&self, color: [u8; 4], distance: f32) -> [u8; 4] {
        let fog_factor = if distance < self.fog_start {
            0.0
        } else if distance > self.fog_end {
            1.0
        } else {
            (distance - self.fog_start) / (self.fog_end - self.fog_start)
        };
        
        let fog_factor = fog_factor * self.fog_density;
        let fog_factor = fog_factor.clamp(0.0, 1.0);
        
        [
            ((color[0] as f32 * (1.0 - fog_factor)) + (self.fog_color[0] as f32 * fog_factor)) as u8,
            ((color[1] as f32 * (1.0 - fog_factor)) + (self.fog_color[1] as f32 * fog_factor)) as u8,
            ((color[2] as f32 * (1.0 - fog_factor)) + (self.fog_color[2] as f32 * fog_factor)) as u8,
            color[3],
        ]
    }
}