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
// Demo 3D v0.2.7 - Cubo com Texturas, Materiais PBR, Partículas e Shaders
use sevenx_engine::*;
use sevenx_engine::world::World;

struct Game3D {
    renderer3d: Renderer3D,
    cube: Mesh3D,
    sphere: Mesh3D,
    torus: Mesh3D,
    rotation_speed: f32,
    particle_system: ParticleSystem3D,
    phong_shader: PhongShader,
    fresnel_shader: FresnelShader,
    fog_shader: FogShader,
    time: f32,
    shader_mode: usize,
    material_mode: usize,
    show_help: bool,
}

impl GameState for Game3D {
    fn new() -> Self {
        println!("🎮 SevenX Engine v0.2.7 - Demo 3D Avançado");
        println!("✨ Texturas 3D + Materiais PBR + Shaders");
        println!();
        
        // Cubo com textura checkerboard (v0.2.7!)
        let mut cube = Mesh3D::cube(2.0);
        cube.position = Vec3::new(-3.0, 0.0, 0.0);
        let texture = Texture3D::checkerboard(32, [255, 50, 50, 255], [255, 200, 200, 255]);
        let material = Material3D::new([255, 255, 255, 255])
            .with_texture(texture)
            .with_metallic(0.3)
            .with_roughness(0.5);
        cube.set_material(material);
        
        // Esfera com material metálico (v0.2.7!)
        let mut sphere = Mesh3D::sphere(1.2, 16);
        sphere.position = Vec3::new(0.0, 0.0, 0.0);
        sphere.set_material(Material3D::metal());
        
        // Torus com material plástico (v0.2.7!)
        let mut torus = Mesh3D::torus(1.0, 0.3, 16, 12);
        torus.position = Vec3::new(3.0, 0.0, 0.0);
        torus.set_material(Material3D::plastic());

        let mut renderer3d = Renderer3D::new(800, 600);
        renderer3d.camera.position = Vec3::new(0.0, 3.0, 10.0);
        renderer3d.camera.look_at(Vec3::zero());
        renderer3d.wireframe = false;
        renderer3d.backface_culling = true;

        // Sistema de partículas 3D
        let particle_system = ParticleSystem3D::new(500);

        // Shaders 3D avançados
        let mut phong_shader = PhongShader::new();
        phong_shader.add_light(Light3D::new(
            Vec3::new(5.0, 10.0, 5.0),
            [1.0, 1.0, 1.0],
            1.5,
        ));
        phong_shader.add_light(Light3D::new(
            Vec3::new(-5.0, 5.0, -5.0),
            [0.5, 0.5, 1.0],
            0.8,
        ));

        let fresnel_shader = FresnelShader::new();
        let fog_shader = FogShader::new();

        Self {
            renderer3d,
            cube,
            sphere,
            torus,
            rotation_speed: 1.0,
            particle_system,
            phong_shader,
            fresnel_shader,
            fog_shader,
            time: 0.0,
            shader_mode: 0,
            material_mode: 0,
            show_help: true,
        }
    }

    fn update(&mut self, dt: f32, input: &sevenx_engine::input::InputHandler, _world: &mut World) {
        self.time += dt;

        // Rotaciona os objetos
        self.cube.rotation.y += self.rotation_speed * dt;
        self.cube.rotation.x += self.rotation_speed * 0.5 * dt;
        
        self.sphere.rotation.y += self.rotation_speed * 1.5 * dt;
        
        self.torus.rotation.x += self.rotation_speed * dt;
        self.torus.rotation.y += self.rotation_speed * 0.7 * dt;

        // Controles da câmera usando movimento vetorial (v0.2.7!)
        let (move_x, move_y) = input.get_movement_vector();
        let camera_speed = if input.is_shift_pressed() { 10.0 } else { 5.0 };
        
        if move_y != 0.0 {
            self.renderer3d.camera.move_forward(move_y * camera_speed * dt);
        }
        if move_x != 0.0 {
            self.renderer3d.camera.rotate_around_target(0.0, -move_x * 2.0 * dt);
        }
        
        // Zoom com scroll (v0.2.7!)
        let scroll = input.get_mouse_wheel_delta();
        if scroll != 0.0 {
            self.renderer3d.camera.move_forward(scroll * 2.0);
        }

        // Toggle wireframe usando just_pressed (v0.2.7!)
        if input.is_key_just_pressed(KeyCode::Space) {
            self.renderer3d.wireframe = !self.renderer3d.wireframe;
            println!("🔲 Wireframe: {}", if self.renderer3d.wireframe { "ON" } else { "OFF" });
        }
        
        // Toggle ajuda
        if input.is_key_just_pressed(KeyCode::F1) {
            self.show_help = !self.show_help;
        }

        // Alterna modo de shader (1-3) usando just_pressed (v0.2.7!)
        if input.is_key_just_pressed(KeyCode::Digit1) {
            self.shader_mode = 0;
            println!("🎨 Shader: Normal");
        }
        if input.is_key_just_pressed(KeyCode::Digit2) {
            self.shader_mode = 1;
            println!("🎨 Shader: Fresnel");
        }
        if input.is_key_just_pressed(KeyCode::Digit3) {
            self.shader_mode = 2;
            println!("🎨 Shader: Fog");
        }
        
        // Alterna materiais (4-7) usando just_pressed (v0.2.7!)
        if input.is_key_just_pressed(KeyCode::Digit4) {
            self.sphere.set_material(Material3D::metal());
            println!("⚙️ Material: Metal");
        }
        if input.is_key_just_pressed(KeyCode::Digit5) {
            self.sphere.set_material(Material3D::plastic());
            println!("⚙️ Material: Plastic");
        }
        if input.is_key_just_pressed(KeyCode::Digit6) {
            self.sphere.set_material(Material3D::rubber());
            println!("⚙️ Material: Rubber");
        }
        if input.is_key_just_pressed(KeyCode::Digit7) {
            self.sphere.set_material(Material3D::glass());
            println!("⚙️ Material: Glass");
        }

        // Emite partículas usando just_pressed (v0.2.7!)
        if input.is_key_just_pressed(KeyCode::KeyE) {
            self.particle_system.explosion(Vec3::new(0.0, 0.0, 0.0));
        }
        if input.is_key_just_pressed(KeyCode::KeyF) {
            self.particle_system.fire(Vec3::new(0.0, -1.0, 0.0));
        }
        if input.is_key_just_pressed(KeyCode::KeyM) {
            self.particle_system.magic(Vec3::new(0.0, 0.0, 0.0));
        }
        if input.is_key_just_pressed(KeyCode::KeyT) {
            let direction = Vec3::new(
                (self.time * 2.0).cos(),
                0.5,
                (self.time * 2.0).sin(),
            );
            self.particle_system.trail(Vec3::new(0.0, 0.0, 0.0), direction);
        }

        // Atualiza partículas
        self.particle_system.update(dt);
    }

    fn draw(&mut self, _world: &World, frame: &mut [u8]) {
        // Limpa a tela com cor baseada no modo
        let bg_color = match self.shader_mode {
            0 => [20, 20, 40],
            1 => [40, 20, 40],
            2 => [20, 40, 40],
            _ => [20, 20, 40],
        };
        
        for pixel in frame.chunks_exact_mut(4) {
            pixel[0] = bg_color[0];
            pixel[1] = bg_color[1];
            pixel[2] = bg_color[2];
            pixel[3] = 255;
        }

        // Renderiza partículas 3D como esferas
        for particle in &self.particle_system.particles {
            let screen_pos = self.project_to_screen(particle.position);
            if let Some((sx, sy)) = screen_pos {
                let size = (particle.size * particle.scale * 10.0) as i32;
                self.draw_circle(frame, sx, sy, size, particle.color);
            }
        }

        // Renderiza os objetos 3D com texturas e materiais (v0.2.7!)
        self.renderer3d.render_mesh(&self.cube, frame, 800, 600);
        self.renderer3d.render_mesh(&self.sphere, frame, 800, 600);
        self.renderer3d.render_mesh(&self.torus, frame, 800, 600);

        // Desenha UI com informações
        self.draw_ui(frame);
    }
}

impl Game3D {
    fn project_to_screen(&self, pos: Vec3) -> Option<(i32, i32)> {
        // Projeção simples (você pode melhorar isso)
        let view_pos = Vec3::new(
            pos.x - self.renderer3d.camera.position.x,
            pos.y - self.renderer3d.camera.position.y,
            pos.z - self.renderer3d.camera.position.z,
        );

        if view_pos.z <= 0.0 {
            return None;
        }

        let fov = 70.0_f32.to_radians();
        let aspect = 800.0 / 600.0;
        let scale = (fov / 2.0).tan();

        let x = (view_pos.x / (view_pos.z * scale * aspect)) * 400.0 + 400.0;
        let y = (view_pos.y / (view_pos.z * scale)) * -300.0 + 300.0;

        Some((x as i32, y as i32))
    }

    fn draw_circle(&self, frame: &mut [u8], cx: i32, cy: i32, radius: i32, color: [u8; 4]) {
        for dy in -radius..=radius {
            for dx in -radius..=radius {
                if dx * dx + dy * dy <= radius * radius {
                    let x = cx + dx;
                    let y = cy + dy;
                    if x >= 0 && x < 800 && y >= 0 && y < 600 {
                        let idx = ((y * 800 + x) * 4) as usize;
                        if idx + 3 < frame.len() {
                            let alpha = color[3] as f32 / 255.0;
                            frame[idx] = ((color[0] as f32 * alpha) + (frame[idx] as f32 * (1.0 - alpha))) as u8;
                            frame[idx + 1] = ((color[1] as f32 * alpha) + (frame[idx + 1] as f32 * (1.0 - alpha))) as u8;
                            frame[idx + 2] = ((color[2] as f32 * alpha) + (frame[idx + 2] as f32 * (1.0 - alpha))) as u8;
                        }
                    }
                }
            }
        }
    }

    fn draw_ui(&self, frame: &mut [u8]) {
        if !self.show_help {
            // Apenas mostra contador de partículas
            let particles_text = format!("Partículas: {} | F1: Ajuda", self.particle_system.particles.len());
            self.draw_text_simple(frame, 10, 10, &particles_text);
            return;
        }
        
        // Desenha barra de informação no topo (fundo semi-transparente)
        for y in 0..180 {
            for x in 0..800 {
                let idx = ((y * 800 + x) * 4) as usize;
                if idx + 3 < frame.len() {
                    frame[idx] = (frame[idx] as f32 * 0.3) as u8;
                    frame[idx + 1] = (frame[idx + 1] as f32 * 0.3) as u8;
                    frame[idx + 2] = (frame[idx + 2] as f32 * 0.3) as u8;
                }
            }
        }
        
        // Informações detalhadas
        let shader_name = match self.shader_mode {
            0 => "Normal",
            1 => "Fresnel",
            2 => "Fog",
            _ => "Unknown",
        };
        
        self.draw_text_simple(frame, 10, 10, "=== SevenX Engine v0.2.7 - Demo 3D ===");
        self.draw_text_simple(frame, 10, 30, &format!("Shader: {} | Partículas: {}", shader_name, self.particle_system.particles.len()));
        self.draw_text_simple(frame, 10, 50, &format!("Wireframe: {}", if self.renderer3d.wireframe { "ON" } else { "OFF" }));
        
        self.draw_text_simple(frame, 10, 75, "Controles:");
        self.draw_text_simple(frame, 10, 95, "  WASD/Setas - Camera | Shift - Rapido | Scroll - Zoom");
        self.draw_text_simple(frame, 10, 115, "  Space - Wireframe | 1-3 - Shaders | 4-7 - Materiais");
        self.draw_text_simple(frame, 10, 135, "  E/F/M/T - Particulas | F1 - Toggle Ajuda");
        
        self.draw_text_simple(frame, 10, 160, "Objetos: Cubo (Textura) | Esfera (Material) | Torus (Plastico)");
    }
    
    fn draw_text_simple(&self, frame: &mut [u8], x: i32, y: i32, text: &str) {
        // Desenho de texto simplificado (você pode melhorar isso)
        for (i, _c) in text.chars().enumerate() {
            let px = x + (i as i32 * 8);
            if px >= 0 && px < 800 && y >= 0 && y < 600 {
                let idx = ((y * 800 + px) * 4) as usize;
                if idx + 3 < frame.len() {
                    frame[idx] = 255;
                    frame[idx + 1] = 255;
                    frame[idx + 2] = 255;
                }
            }
        }
    }
}

fn main() {
    println!("🎮 SevenX Engine v0.2.7 - Demo 3D Avançado");
    println!("✨ Novidades:");
    println!("   🎲 Texturas 3D (Checkerboard)");
    println!("   ⚙️ Materiais PBR (Metal, Plastic, Rubber, Glass)");
    println!("   🎨 Shaders Avançados (Phong, Fresnel, Fog)");
    println!("   💫 Sistema de Partículas 3D");
    println!("   🖱️ Input Avançado (Scroll, Just Pressed)");
    println!();
    
    let config = EngineConfig::default()
        .with_title("SevenX Engine v0.2.7 - Demo 3D (Texturas + Materiais + Shaders)")
        .with_size(800, 600);

    let engine = Engine::with_config(config);
    engine.run::<Game3D>();
}