170 lines
7.4 KiB
Rust
170 lines
7.4 KiB
Rust
use crate::model::Color;
|
|
use crate::peripherals::{Gfx, InputSignals, Pad, Touch};
|
|
|
|
/// PROMETEU "hardware lógico" (v0).
|
|
/// O Host alimenta INPUT SIGNALS e chama `step_frame()` em 60Hz.
|
|
pub struct Machine {
|
|
pub gfx: Gfx,
|
|
pub pad: Pad,
|
|
pub touch: Touch,
|
|
pub frame_index: u64,
|
|
}
|
|
|
|
impl Machine {
|
|
pub const W: usize = 320;
|
|
pub const H: usize = 180;
|
|
|
|
pub fn new() -> Self {
|
|
Self {
|
|
gfx: Gfx::new(Self::W, Self::H),
|
|
pad: Pad::default(),
|
|
touch: Touch::default(),
|
|
frame_index: 0,
|
|
}
|
|
}
|
|
|
|
/// "Contrato de frame" do PROMETEU (Template Method sem loop).
|
|
/// O Host controla tempo/event loop; o Core define a sequência do frame.
|
|
pub fn step_frame(&mut self, signals: &InputSignals) {
|
|
self.begin_frame(signals);
|
|
self.tick(); // futuro: executa cartucho/VM
|
|
self.gfx.render_all(); // A máquina executa o pipeline gráfico (Ação física)
|
|
self.end_frame(); // present/housekeeping
|
|
}
|
|
|
|
/// Início do frame: zera flags transitórias.
|
|
pub fn begin_frame(&mut self, signals: &InputSignals) {
|
|
self.frame_index += 1;
|
|
|
|
// Flags transitórias do TOUCH devem durar 1 frame.
|
|
self.touch.begin_frame(signals);
|
|
|
|
// Se você quiser input com pressed/released depois:
|
|
self.pad.begin_frame(signals);
|
|
}
|
|
|
|
/// Lógica do frame (demo hardcoded por enquanto).
|
|
pub fn tick(&mut self) {
|
|
// Limpa a tela com um azul escuro "estilo console"
|
|
self.gfx.clear(Color::BLACK);
|
|
|
|
// Simula o carregamento de um banco se estiver vazio (apenas para teste)
|
|
if self.gfx.banks[0].is_none() {
|
|
let mut test_bank = crate::model::TileBank::new(crate::model::TileSize::Size8, 128, 128);
|
|
// Pinta o primeiro tile (ID 1) de Branco para teste
|
|
// Ele começa no pixel (8, 0) pois o ID 0 é o primeiro (0,0)
|
|
let tile_size = 8;
|
|
let start_x = 8; // ID 1 está na segunda posição da primeira linha
|
|
let start_y = 0;
|
|
|
|
for y in 0..tile_size {
|
|
for x in 0..tile_size {
|
|
let px = start_x + x;
|
|
let py = start_y + y;
|
|
let idx = py * 128 + px;
|
|
test_bank.pixels[idx] = Color::GREEN;
|
|
}
|
|
}
|
|
self.gfx.banks[0] = Some(test_bank);
|
|
}
|
|
|
|
// Simula o carregamento de um banco se estiver vazio (apenas para teste)
|
|
if self.gfx.banks[1].is_none() {
|
|
let mut test_bank = crate::model::TileBank::new(crate::model::TileSize::Size16, 128, 128);
|
|
// Pinta o primeiro tile (ID 1) de Branco para teste
|
|
// Ele começa no pixel (16, 0) pois o ID 0 é o primeiro (0,0)
|
|
let tile_size = 16;
|
|
let start_x = 16; // ID 1 está na segunda posição da primeira linha
|
|
let start_y = 0;
|
|
|
|
for y in 0..tile_size {
|
|
for x in 0..tile_size {
|
|
let px = start_x + x;
|
|
let py = start_y + y;
|
|
let idx = py * 128 + px;
|
|
test_bank.pixels[idx] = Color::RED;
|
|
}
|
|
}
|
|
self.gfx.banks[1] = Some(test_bank);
|
|
}
|
|
|
|
// Simula o carregamento de um banco se estiver vazio (apenas para teste)
|
|
if self.gfx.banks[2].is_none() {
|
|
let mut test_bank = crate::model::TileBank::new(crate::model::TileSize::Size16, 128, 128);
|
|
// Pinta o primeiro tile (ID 1) de Branco para teste
|
|
// Ele começa no pixel (16, 0) pois o ID 0 é o primeiro (0,0)
|
|
let tile_size = 16;
|
|
let start_x = 16; // ID 1 está na segunda posição da primeira linha
|
|
let start_y = 0;
|
|
|
|
for y in 0..tile_size {
|
|
for x in 0..tile_size {
|
|
let px = start_x + x;
|
|
let py = start_y + y;
|
|
let idx = py * 128 + px;
|
|
test_bank.pixels[idx] = Color::INDIGO;
|
|
}
|
|
}
|
|
self.gfx.banks[2] = Some(test_bank);
|
|
}
|
|
|
|
// Coloca o Tile ID 1 no mapa do HUD (canto superior esquerdo)
|
|
self.gfx.hud.map.set_tile(18, 6, crate::model::Tile { id: 1, ..Default::default() });
|
|
|
|
self.gfx.layers[0].bank_id = 1;
|
|
self.gfx.layers[0].map.set_tile(8, 1, crate::model::Tile { id: 1, ..Default::default() });
|
|
self.gfx.layers[0].map.set_tile(8, 2, crate::model::Tile { id: 1, ..Default::default() });
|
|
self.gfx.layers[0].map.set_tile(8, 3, crate::model::Tile { id: 1, ..Default::default() });
|
|
self.gfx.layers[0].map.set_tile(8, 4, crate::model::Tile { id: 1, ..Default::default() });
|
|
self.gfx.layers[0].map.set_tile(8, 5, crate::model::Tile { id: 1, ..Default::default() });
|
|
self.gfx.layers[1].bank_id = 1;
|
|
self.gfx.layers[1].map.set_tile(9, 1, crate::model::Tile { id: 1, ..Default::default() });
|
|
self.gfx.layers[1].map.set_tile(9, 2, crate::model::Tile { id: 1, ..Default::default() });
|
|
self.gfx.layers[1].map.set_tile(9, 3, crate::model::Tile { id: 1, ..Default::default() });
|
|
self.gfx.layers[1].map.set_tile(9, 4, crate::model::Tile { id: 1, ..Default::default() });
|
|
self.gfx.layers[1].map.set_tile(9, 5, crate::model::Tile { id: 1, ..Default::default() });
|
|
self.gfx.layers[2].bank_id = 1;
|
|
self.gfx.layers[2].map.set_tile(10, 1, crate::model::Tile { id: 1, ..Default::default() });
|
|
self.gfx.layers[2].map.set_tile(10, 2, crate::model::Tile { id: 1, ..Default::default() });
|
|
self.gfx.layers[2].map.set_tile(10, 3, crate::model::Tile { id: 1, ..Default::default() });
|
|
self.gfx.layers[2].map.set_tile(10, 4, crate::model::Tile { id: 1, ..Default::default() });
|
|
self.gfx.layers[2].map.set_tile(10, 5, crate::model::Tile { id: 1, ..Default::default() });
|
|
self.gfx.layers[3].bank_id = 1;
|
|
self.gfx.layers[3].map.set_tile(11, 1, crate::model::Tile { id: 1, ..Default::default() });
|
|
self.gfx.layers[3].map.set_tile(11, 2, crate::model::Tile { id: 1, ..Default::default() });
|
|
self.gfx.layers[3].map.set_tile(11, 3, crate::model::Tile { id: 1, ..Default::default() });
|
|
self.gfx.layers[3].map.set_tile(11, 4, crate::model::Tile { id: 1, ..Default::default() });
|
|
self.gfx.layers[3].map.set_tile(11, 5, crate::model::Tile { id: 1, ..Default::default() });
|
|
|
|
for i in 0..512 {
|
|
let s = &mut self.gfx.sprites[i];
|
|
s.active = true;
|
|
|
|
// Distribui os sprites entre os 3 bancos de teste que você criou
|
|
s.bank_id = (i % 2) as u8 + 1;
|
|
s.tile.id = 1;
|
|
|
|
// Cria um movimento caótico baseado no index do sprite e no frame_index
|
|
let speed = (1 + (i % 3)) as u64;
|
|
s.x = (((self.frame_index * speed) + (i as u64 * 10)) % 400) as i32 - 40;
|
|
s.y = (((self.frame_index * speed) + (i as u64 * 4)) % 180) as i32;
|
|
if i % 2 != 0 {
|
|
s.y = 179 - s.y;
|
|
}
|
|
|
|
// Distribui as prioridades de 0 a 4
|
|
// Isso vai fazer alguns sprites passarem atrás do cenário e outros na frente
|
|
s.priority = (i % 5) as u8;
|
|
|
|
// Efeito de flip alternado para testar a lógica de espelhamento
|
|
s.flip_x = i % 2 == 0;
|
|
s.flip_y = i % 3 == 0;
|
|
}
|
|
}
|
|
|
|
/// Final do frame: troca buffers.
|
|
pub fn end_frame(&mut self) {
|
|
self.gfx.present();
|
|
}
|
|
}
|