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 Post-Processing
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum PostEffect {
    Bloom { threshold: f32, intensity: f32 },
    MotionBlur { strength: f32 },
    ColorGrading { contrast: f32, saturation: f32, brightness: f32 },
    Vignette { intensity: f32, radius: f32 },
    ChromaticAberration { offset: f32 },
}

pub struct PostProcessor {
    effects: Vec<PostEffect>,
    pub enabled: bool,
}

impl PostProcessor {
    pub fn new() -> Self {
        Self {
            effects: Vec::new(),
            enabled: true,
        }
    }

    pub fn add_effect(&mut self, effect: PostEffect) {
        self.effects.push(effect);
    }

    pub fn clear_effects(&mut self) {
        self.effects.clear();
    }

    pub fn set_enabled(&mut self, enabled: bool) {
        self.enabled = enabled;
    }

    pub fn apply(&self, frame: &mut [u8], width: u32, height: u32) {
        if !self.enabled {
            return;
        }

        for effect in &self.effects {
            match effect {
                PostEffect::Bloom { threshold, intensity } => {
                    self.apply_bloom(frame, width, height, *threshold, *intensity);
                }
                PostEffect::Vignette { intensity, radius } => {
                    self.apply_vignette(frame, width, height, *intensity, *radius);
                }
                PostEffect::ColorGrading { contrast, saturation, brightness } => {
                    self.apply_color_grading(frame, *contrast, *saturation, *brightness);
                }
                _ => {}
            }
        }
    }

    fn apply_bloom(&self, frame: &mut [u8], width: u32, height: u32, threshold: f32, intensity: f32) {
        let mut bright_pixels = vec![0u8; frame.len()];
        
        for i in (0..frame.len()).step_by(4) {
            let r = frame[i] as f32 / 255.0;
            let g = frame[i + 1] as f32 / 255.0;
            let b = frame[i + 2] as f32 / 255.0;
            let brightness = (r + g + b) / 3.0;

            if brightness > threshold {
                bright_pixels[i] = frame[i];
                bright_pixels[i + 1] = frame[i + 1];
                bright_pixels[i + 2] = frame[i + 2];
            }
        }

        // Blur simples
        for y in 1..(height - 1) {
            for x in 1..(width - 1) {
                let idx = ((y * width + x) * 4) as usize;
                
                let mut r_sum = 0u32;
                let mut g_sum = 0u32;
                let mut b_sum = 0u32;
                
                for dy in -1..=1 {
                    for dx in -1..=1 {
                        let neighbor_idx = (((y as i32 + dy) as u32 * width + (x as i32 + dx) as u32) * 4) as usize;
                        r_sum += bright_pixels[neighbor_idx] as u32;
                        g_sum += bright_pixels[neighbor_idx + 1] as u32;
                        b_sum += bright_pixels[neighbor_idx + 2] as u32;
                    }
                }

                frame[idx] = ((frame[idx] as f32 + (r_sum / 9) as f32 * intensity).min(255.0)) as u8;
                frame[idx + 1] = ((frame[idx + 1] as f32 + (g_sum / 9) as f32 * intensity).min(255.0)) as u8;
                frame[idx + 2] = ((frame[idx + 2] as f32 + (b_sum / 9) as f32 * intensity).min(255.0)) as u8;
            }
        }
    }

    fn apply_vignette(&self, frame: &mut [u8], width: u32, height: u32, intensity: f32, radius: f32) {
        let center_x = width as f32 / 2.0;
        let center_y = height as f32 / 2.0;
        let max_dist = ((center_x * center_x + center_y * center_y).sqrt()) * radius;

        for y in 0..height {
            for x in 0..width {
                let dx = x as f32 - center_x;
                let dy = y as f32 - center_y;
                let dist = (dx * dx + dy * dy).sqrt();
                
                let vignette = (1.0 - (dist / max_dist).min(1.0) * intensity).max(0.0);
                
                let idx = ((y * width + x) * 4) as usize;
                frame[idx] = (frame[idx] as f32 * vignette) as u8;
                frame[idx + 1] = (frame[idx + 1] as f32 * vignette) as u8;
                frame[idx + 2] = (frame[idx + 2] as f32 * vignette) as u8;
            }
        }
    }

    fn apply_color_grading(&self, frame: &mut [u8], contrast: f32, saturation: f32, brightness: f32) {
        for i in (0..frame.len()).step_by(4) {
            let r = frame[i] as f32 / 255.0;
            let g = frame[i + 1] as f32 / 255.0;
            let b = frame[i + 2] as f32 / 255.0;

            // Brightness
            let mut r = (r + brightness).clamp(0.0, 1.0);
            let mut g = (g + brightness).clamp(0.0, 1.0);
            let mut b = (b + brightness).clamp(0.0, 1.0);

            // Contrast
            r = ((r - 0.5) * contrast + 0.5).clamp(0.0, 1.0);
            g = ((g - 0.5) * contrast + 0.5).clamp(0.0, 1.0);
            b = ((b - 0.5) * contrast + 0.5).clamp(0.0, 1.0);

            // Saturation
            let gray = 0.299 * r + 0.587 * g + 0.114 * b;
            r = (gray + (r - gray) * saturation).clamp(0.0, 1.0);
            g = (gray + (g - gray) * saturation).clamp(0.0, 1.0);
            b = (gray + (b - gray) * saturation).clamp(0.0, 1.0);

            frame[i] = (r * 255.0) as u8;
            frame[i + 1] = (g * 255.0) as u8;
            frame[i + 2] = (b * 255.0) as u8;
        }
    }
}