From babbda0d43c1b509aa6d09dd3469b7cc829da3c3 Mon Sep 17 00:00:00 2001 From: Rekai Musuka Date: Fri, 13 May 2022 07:34:28 -0300 Subject: [PATCH] feat: MVP for 2d_sprites.gba --- .gitignore | 3 +- src/2d_sprites.zig | 164 ++++++++++++++++++++++++--------------------- 2 files changed, 88 insertions(+), 79 deletions(-) diff --git a/.gitignore b/.gitignore index 45eb591..d13d7cc 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ zig-cache/ **/*.s **/*.asm -**/*.bin \ No newline at end of file +**/*.bin +**/*.sav \ No newline at end of file diff --git a/src/2d_sprites.zig b/src/2d_sprites.zig index 29a0849..a9cbf3e 100644 --- a/src/2d_sprites.zig +++ b/src/2d_sprites.zig @@ -11,8 +11,83 @@ const SquareSpriteTuple = std.meta.Tuple(&[_]type{ Rainbow, Bebe16, Bebe32, Bebe // TODO: ZigGBA should support spaces in the ROM Title IIRC export var gameHeader linksection(".gbaheader") = GBA.Header.setup("2DSPRITE", "PAOD", "00", 0); -// 16x16 4BPP Sprite depicting -// denpa artist Nanahira's pet rabbit: Bebe-chan +// To-do List: +// TODO: 8BPP variants? +// TODO: Tall Sprites +// TODO: Wide Sprites +// TODO: 8x8 Bebe-chan + +const square_sprites = initSquareSpriteTuple(); + +fn initSquareSpriteTuple() SquareSpriteTuple { + return .{ Rainbow{}, Bebe16{}, Bebe32{}, Bebe64{} }; +} + +pub fn main() noreturn { + LCD.setupDisplayControl(.{ + .mode = .Mode0, // No Affine BGs + .objectLayer = .Show, // Enable Sprites + .objVramCharacterMapping = .TwoDimension, // 2D Sprite Mapping + }); + + OAM.init(); + + square_sprites[0].load(); // Copy Mapping to VRAM and Palette to PALRAM + + var sprite: *OAM.Attribute = OAM.allocate(); + sprite.paletteMode = square_sprites[0].paletteMode(); + sprite.palette = 0; + sprite.tileIndex = 0; + sprite.setSize(square_sprites[0].size()); + + var x: i32 = 96; + var y: i32 = 32; + + var i: i32 = 0; + + while (true) { + LCD.naiveVSync(); + Input.readInput(); + + const shoulder = Input.getShoulderJustPressed(); + if (shoulder != 0) { + i = (i + shoulder) & 0b11; + + // Index must be comptime known unfortunately + // so we need this ugly switch statement + switch (i) { + 0 => { + square_sprites[0].load(); + sprite.setSize(square_sprites[0].size()); + }, + 1 => { + square_sprites[1].load(); + sprite.setSize(square_sprites[1].size()); + }, + 2 => { + square_sprites[2].load(); + sprite.setSize(square_sprites[2].size()); + }, + 3 => { + square_sprites[3].load(); + sprite.setSize(square_sprites[3].size()); + }, + else => unreachable, + } + } + + x += Input.getHorizontal() * 2; + y += Input.getVertical() * 2; + + sprite.setPosition(x, y); + + OAM.update(1); + } +} + +/// 16x16 4bpp Sprite +/// Denpa vocalist Nanahira's pet rabbit: Bebe-chan +// Ad: If you're weeb enough, check out Denpasongs const Bebe16 = struct { const Self = @This(); @@ -34,6 +109,7 @@ const Bebe16 = struct { fn size(_: Self) OAM.ObjectSize { return .Size16x16; } + fn load(_: Self) void { // In Memory, Tile Map is laid out like: 1 2 // 3 4 @@ -48,7 +124,8 @@ const Bebe16 = struct { } }; -// Bebe-chan but bigger +/// 32x32 Bebe-chan +/// Same art as Bebe16, but scaled up const Bebe32 = struct { const Self = @This(); @@ -102,7 +179,8 @@ const Bebe32 = struct { } }; -// The Biggest Bebe-chan yet +/// 64x64 Bebe-chan +/// Same art as Bebe16, just scaled up const Bebe64 = struct { const Self = @This(); @@ -214,9 +292,7 @@ const Bebe64 = struct { } }; -// 8x8 4bpp Sprite depicting a Rainbow -// (it's more of a gradiant, I don't know english, whatever.) -// source: Laziness? I can't draw, especially within the confines of 8x8 pixels +/// 8x8 4bpp Sprite depicting a Rainbow-like gradient 'cause I can't draw const Rainbow = struct { const Self = @This(); @@ -228,15 +304,15 @@ const Rainbow = struct { 0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555, 0x66666666, 0x77777777, 0x88888888, }; - inline fn paletteMode(_: Self) GBA.PaletteMode { + fn paletteMode(_: Self) GBA.PaletteMode { return .Color16; } - inline fn size(_: Self) OAM.ObjectSize { + fn size(_: Self) OAM.ObjectSize { return .Size8x8; } - inline fn load(_: Self) void { + fn load(_: Self) void { // 8x8 Sprites don't differ in any meaningful way between 1D and 2D mapping // Copy Tile Mapping @@ -246,71 +322,3 @@ const Rainbow = struct { GBA.memcpy32(GBA.OBJ_PALETTE_RAM, &Self.pal, Self.pal.len * @sizeOf(u32)); } }; - -const square_sprites = withoutThisMethodZigComplains(); - -fn withoutThisMethodZigComplains() SquareSpriteTuple { - return .{ Rainbow{}, Bebe16{}, Bebe32{}, Bebe64{} }; -} - -pub fn main() noreturn { - LCD.setupDisplayControl(.{ - .mode = .Mode0, // No Affine BGs - .objectLayer = .Show, // Enable Sprites - .objVramCharacterMapping = .TwoDimension, // 2D Sprite Mapping - }); - - OAM.init(); - - square_sprites[0].load(); // Copy Mapping to VRAM and Palette to PALRAM - - var sprite: *OAM.Attribute = OAM.allocate(); - sprite.paletteMode = square_sprites[0].paletteMode(); - sprite.palette = 0; - sprite.tileIndex = 0; - sprite.setSize(square_sprites[0].size()); - - var x: i32 = 96; - var y: i32 = 32; - - var i: i32 = 0; - - while (true) { - LCD.naiveVSync(); - Input.readInput(); - - const shoulder = Input.getShoulderJustPressed(); - if (shoulder != 0) { - i = (i + shoulder) & 0b11; - - // Index must be comptime known unfortunately - // so we need this ugly switch statement - switch (i) { - 0 => { - square_sprites[0].load(); - sprite.setSize(square_sprites[0].size()); - }, - 1 => { - square_sprites[1].load(); - sprite.setSize(square_sprites[1].size()); - }, - 2 => { - square_sprites[2].load(); - sprite.setSize(square_sprites[2].size()); - }, - 3 => { - square_sprites[3].load(); - sprite.setSize(square_sprites[3].size()); - }, - else => unreachable, - } - } - - x += Input.getHorizontal() * 2; - y += Input.getVertical() * 2; - - sprite.setPosition(x, y); - - OAM.update(1); - } -}