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 Iluminação 2D
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum LightType {
    Point,
    Directional,
    Spot,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Light {
    pub position: (f32, f32),
    pub color: [u8; 3],
    pub intensity: f32,
    pub radius: f32,
    pub light_type: LightType,
    pub direction: f32, // Para spot lights
    pub cone_angle: f32, // Para spot lights
    pub enabled: bool,
}

impl Light {
    pub fn point(x: f32, y: f32, radius: f32) -> Self {
        Self {
            position: (x, y),
            color: [255, 255, 255],
            intensity: 1.0,
            radius,
            light_type: LightType::Point,
            direction: 0.0,
            cone_angle: 45.0,
            enabled: true,
        }
    }

    pub fn spot(x: f32, y: f32, direction: f32, cone_angle: f32, radius: f32) -> Self {
        Self {
            position: (x, y),
            color: [255, 255, 255],
            intensity: 1.0,
            radius,
            light_type: LightType::Spot,
            direction,
            cone_angle,
            enabled: true,
        }
    }

    pub fn with_color(mut self, r: u8, g: u8, b: u8) -> Self {
        self.color = [r, g, b];
        self
    }

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

    // Calcula a intensidade da luz em um ponto
    pub fn calculate_intensity(&self, x: f32, y: f32) -> f32 {
        if !self.enabled {
            return 0.0;
        }

        let dx = x - self.position.0;
        let dy = y - self.position.1;
        let distance = (dx * dx + dy * dy).sqrt();

        if distance > self.radius {
            return 0.0;
        }

        match self.light_type {
            LightType::Point => {
                let attenuation = 1.0 - (distance / self.radius);
                attenuation * self.intensity
            }
            LightType::Spot => {
                let angle_to_point = dy.atan2(dx).to_degrees();
                let angle_diff = (angle_to_point - self.direction).abs();
                
                if angle_diff > self.cone_angle {
                    return 0.0;
                }

                let attenuation = 1.0 - (distance / self.radius);
                let cone_falloff = 1.0 - (angle_diff / self.cone_angle);
                attenuation * cone_falloff * self.intensity
            }
            LightType::Directional => self.intensity,
        }
    }
}

#[derive(Debug)]
pub struct LightingSystem {
    pub lights: Vec<Light>,
    pub ambient_color: [u8; 3],
    pub ambient_intensity: f32,
}

impl LightingSystem {
    pub fn new() -> Self {
        Self {
            lights: Vec::new(),
            ambient_color: [50, 50, 50],
            ambient_intensity: 0.2,
        }
    }

    pub fn add_light(&mut self, light: Light) -> usize {
        self.lights.push(light);
        self.lights.len() - 1
    }

    pub fn remove_light(&mut self, index: usize) {
        if index < self.lights.len() {
            self.lights.remove(index);
        }
    }

    pub fn set_ambient(&mut self, r: u8, g: u8, b: u8, intensity: f32) {
        self.ambient_color = [r, g, b];
        self.ambient_intensity = intensity.clamp(0.0, 1.0);
    }

    // Calcula a cor final de um pixel com iluminação
    pub fn apply_lighting(&self, x: f32, y: f32, base_color: [u8; 4]) -> [u8; 4] {
        let mut total_r = self.ambient_color[0] as f32 * self.ambient_intensity;
        let mut total_g = self.ambient_color[1] as f32 * self.ambient_intensity;
        let mut total_b = self.ambient_color[2] as f32 * self.ambient_intensity;

        for light in &self.lights {
            let intensity = light.calculate_intensity(x, y);
            if intensity > 0.0 {
                total_r += light.color[0] as f32 * intensity;
                total_g += light.color[1] as f32 * intensity;
                total_b += light.color[2] as f32 * intensity;
            }
        }

        let r = ((base_color[0] as f32 * total_r / 255.0).min(255.0)) as u8;
        let g = ((base_color[1] as f32 * total_g / 255.0).min(255.0)) as u8;
        let b = ((base_color[2] as f32 * total_b / 255.0).min(255.0)) as u8;

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