use agb_fixnum::{num, Num, Vector2D};
use alloc::vec::Vec;
use alloc::{boxed::Box, vec};
use crate::display::object::{DynamicSprite, PaletteVram, Size, SpriteVram};
use crate::display::palette16::Palette16;
use crate::{
display::{object::ObjectUnmanaged, HEIGHT, WIDTH},
include_palette,
interrupt::VBlank,
};
const PALETTE: &[u16] = &include_palette!("gfx/pastel.png");
fn letters() -> Vec<Vec<Vector2D<Num<i32, 8>>>> {
vec![
vec![
(num!(0.), num!(0.)).into(),
(num!(1.), num!(1.)).into(),
(num!(2.), num!(2.)).into(),
(num!(3.), num!(3.)).into(),
(num!(0.), num!(1.)).into(),
(num!(0.), num!(2.)).into(),
(num!(0.), num!(3.)).into(),
(num!(3.), num!(0.)).into(),
(num!(3.), num!(1.)).into(),
(num!(3.), num!(2.)).into(),
(num!(3.), num!(3.)).into(),
],
vec![
(num!(0.), num!(0.)).into(),
(num!(0.), num!(1.)).into(),
(num!(0.), num!(2.)).into(),
(num!(0.), num!(3.)).into(),
(num!(1.), num!(3.)).into(),
(num!(2.), num!(3.)).into(),
(num!(3.), num!(3.)).into(),
(num!(3.), num!(2.)).into(),
(num!(3.), num!(1.)).into(),
(num!(3.), num!(0.)).into(),
(num!(2.), num!(0.)).into(),
(num!(1.), num!(0.)).into(),
],
vec![
(num!(3.), num!(0.)).into(),
(num!(2.), num!(0.)).into(),
(num!(1.), num!(0.)).into(),
(num!(0.), num!(0.)).into(),
(num!(0.), num!(1.)).into(),
(num!(0.), num!(2.)).into(),
(num!(0.), num!(3.)).into(),
(num!(1.), num!(3.)).into(),
(num!(2.), num!(3.)).into(),
(num!(3.), num!(3.)).into(),
(num!(3.), num!(2.25)).into(),
(num!(3.), num!(1.5)).into(),
(num!(2.), num!(1.5)).into(),
],
vec![
(num!(0.), num!(0.)).into(),
(num!(0.), num!(1.)).into(),
(num!(0.), num!(2.)).into(),
(num!(0.), num!(3.)).into(),
(num!(3.), num!(3.)).into(),
(num!(3.), num!(2.)).into(),
(num!(3.), num!(1.)).into(),
(num!(3.), num!(0.)).into(),
(num!(2.), num!(0.)).into(),
(num!(1.), num!(0.)).into(),
(num!(1.), num!(1.5)).into(),
(num!(2.), num!(1.5)).into(),
],
vec![
(num!(0.), num!(0.)).into(),
(num!(0.), num!(1.)).into(),
(num!(0.), num!(2.)).into(),
(num!(0.), num!(3.)).into(),
(num!(3.), num!(3.)).into(),
(num!(3.), num!(2.)).into(),
(num!(3.), num!(1.)).into(),
(num!(3.), num!(0.)).into(),
(num!(1.5), num!(1.5)).into(),
(num!(0.75), num!(0.75)).into(),
(num!(2.25), num!(0.75)).into(),
],
vec![
(num!(0.), num!(0.)).into(),
(num!(0.), num!(1.)).into(),
(num!(0.), num!(2.)).into(),
(num!(0.), num!(3.)).into(),
(num!(1.), num!(3.)).into(),
(num!(2.), num!(3.)).into(),
(num!(3.), num!(3.)).into(),
(num!(3.), num!(0.)).into(),
(num!(2.), num!(0.)).into(),
(num!(1.), num!(0.)).into(),
(num!(1.), num!(1.5)).into(),
(num!(2.), num!(1.5)).into(),
],
]
}
fn generate_sprites() -> Box<[SpriteVram]> {
let mut sprites = Vec::new();
let palettes: Vec<PaletteVram> = PALETTE
.chunks(15)
.map(|x| {
core::iter::once(0)
.chain(x.iter().copied())
.chain(core::iter::repeat(0))
.take(16)
.collect::<Vec<_>>()
})
.map(|palette| {
let palette = Palette16::new(palette.try_into().unwrap());
PaletteVram::new(&palette).unwrap()
})
.collect();
for (palette, colour) in (0..PALETTE.len()).map(|x| (x / 15, x % 15)) {
let mut sprite = DynamicSprite::new(Size::S8x8);
sprite.clear(colour + 1);
sprites.push(sprite.to_vram(palettes[palette].clone()));
}
sprites.into_boxed_slice()
}
pub fn no_game(mut gba: crate::Gba) -> ! {
let (mut oam, _) = gba.display.object.get_unmanaged();
let squares = generate_sprites();
let mut letter_positons = Vec::new();
let square_positions = {
let mut s = letters();
for letter in s.iter_mut() {
letter.sort_by_key(|a| a.magnitude_squared());
}
s
};
for (letter_idx, letter_parts) in square_positions.iter().enumerate() {
for part in letter_parts.iter() {
let position = part
.hadamard((8, 10).into())
.hadamard((num!(3.) / 2, num!(3.) / 2).into());
let letter_pos = Vector2D::new(
60 * (1 + letter_idx as i32 - ((letter_idx >= 2) as i32 * 3)),
70 * ((letter_idx >= 2) as i32),
);
letter_positons.push(position + letter_pos.change_base());
}
}
let bottom_right = letter_positons
.iter()
.copied()
.max_by_key(|x| x.manhattan_distance())
.unwrap();
let difference = (Vector2D::new(WIDTH - 8, HEIGHT - 8).change_base() - bottom_right) / 2;
for pos in letter_positons.iter_mut() {
*pos += difference;
}
let mut time: Num<i32, 8> = num!(0.);
let time_delta: Num<i32, 8> = num!(0.025);
let vblank = VBlank::get();
loop {
time += time_delta;
time %= 1;
let letters: Vec<ObjectUnmanaged> = letter_positons
.iter()
.enumerate()
.map(|(idx, position)| {
let time = time + Num::<i32, 8>::new(idx as i32) / 128;
(idx, *position + Vector2D::new(time.sin(), time.cos()) * 10)
})
.map(|(idx, pos)| {
let mut obj = ObjectUnmanaged::new(squares[idx % squares.len()].clone());
obj.show().set_position(pos.floor());
obj
})
.collect();
vblank.wait_for_vblank();
for (obj, slot) in letters.iter().zip(oam.iter()) {
slot.set(obj);
}
}
}