diff --git a/presets/gb/gb/metasprites.h b/presets/gb/gb/metasprites.h index af9d077e..52c9e735 100644 --- a/presets/gb/gb/metasprites.h +++ b/presets/gb/gb/metasprites.h @@ -67,7 +67,7 @@ #ifndef _METASPRITES_H_INCLUDE #define _METASPRITES_H_INCLUDE -#include +//#include #include "types.h" #include diff --git a/presets/gb/gbtext.h b/presets/gb/gbtext.h new file mode 100644 index 00000000..bbcbee47 --- /dev/null +++ b/presets/gb/gbtext.h @@ -0,0 +1,136 @@ +/* + * gbtext.h - 8x8 text font + helpers for Game Boy presets. + * + * Glyphs are the NES "chr_generic" font (ASCII tiles 0x20-0x7a). + * That font stores two bitplanes: plane 0 is a drop shadow and + * plane 1 is the glyph. Game Boy 2bpp tiles use the same + * color-index layout (index = plane0 | plane1<<1), so the bytes + * are copied verbatim, just interleaved per scanline. + * + * Tile indices equal ASCII codes, so a C string can be written + * straight to the tile map with put_str(). + */ +#ifndef GBTEXT_H +#define GBTEXT_H + +#include +#include +#include "gb/types.h" +#include "gb/hardware.h" +#include "gb/gb.h" + +#define FONT_TILE_BASE 0x20U +#define FONT_NUM_TILES 91U + +const uint8_t font_tiles[FONT_NUM_TILES*16] = { +/*;;{w:8,h:8,bpp:1,count:91,brev:1,np:2,pofs:1,sl:2};;*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x3c,0x38,0x3c,0x38,0x3c,0x30,0x38,0x30,0x38,0x30,0x38,0x00,0x38,0x30,0x38,0x00, + 0x3c,0x28,0x3c,0x28,0x3c,0x28,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x3c,0x28,0x7e,0x7c,0x7e,0x28,0x7e,0x7c,0x7e,0x28,0x3c,0x00,0x00,0x00, + 0x0c,0x08,0x3f,0x3e,0x3f,0x28,0x3e,0x3c,0x3e,0x14,0x7e,0x7c,0x7e,0x10,0x18,0x00, + 0x00,0x00,0x76,0x64,0x7e,0x48,0x7c,0x10,0x3e,0x24,0x7e,0x4c,0x6e,0x00,0x00,0x00, + 0x00,0x00,0x38,0x30,0x7c,0x48,0x7c,0x30,0x7e,0x5c,0x7e,0x48,0x7e,0x34,0x3e,0x00, + 0x30,0x20,0x30,0x20,0x70,0x40,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x0e,0x0c,0x1e,0x18,0x3c,0x30,0x38,0x30,0x38,0x30,0x3c,0x18,0x1e,0x0c,0x0e,0x00, + 0x70,0x60,0x78,0x30,0x3c,0x18,0x1c,0x18,0x1c,0x18,0x3c,0x30,0x78,0x60,0x70,0x00, + 0x00,0x00,0x00,0x00,0x3e,0x3c,0x3e,0x18,0x3e,0x3c,0x3e,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x18,0x10,0x18,0x10,0x7e,0x7c,0x7e,0x10,0x18,0x10,0x18,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x30,0x38,0x30,0x78,0x60,0x70,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x3c,0x3e,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x30,0x38,0x30,0x38,0x00, + 0x06,0x04,0x0e,0x0c,0x0e,0x08,0x1c,0x18,0x1c,0x10,0x38,0x30,0x38,0x20,0x30,0x00, + 0x3c,0x38,0x7e,0x6c,0x7e,0x6c,0x7e,0x6c,0x7e,0x6c,0x7e,0x6c,0x7e,0x38,0x3c,0x00, + 0x1c,0x18,0x3c,0x38,0x3c,0x18,0x1c,0x18,0x1c,0x18,0x1c,0x18,0x1c,0x18,0x1c,0x00, + 0x3c,0x38,0x7e,0x6c,0x7e,0x0c,0x3e,0x38,0x7c,0x60,0x7e,0x6c,0x7e,0x7c,0x7e,0x00, + 0x3c,0x38,0x7e,0x6c,0x7e,0x0c,0x3e,0x38,0x3e,0x0c,0x7e,0x6c,0x7e,0x38,0x3c,0x00, + 0x7e,0x6c,0x7e,0x6c,0x7e,0x6c,0x7e,0x7c,0x7e,0x0c,0x0e,0x0c,0x0e,0x0c,0x0e,0x00, + 0x7e,0x7c,0x7e,0x6c,0x7e,0x60,0x7c,0x78,0x7e,0x0c,0x7e,0x6c,0x7e,0x38,0x3c,0x00, + 0x3c,0x38,0x7e,0x6c,0x7e,0x60,0x7c,0x78,0x7e,0x6c,0x7e,0x6c,0x7e,0x38,0x3c,0x00, + 0x7e,0x7c,0x7e,0x6c,0x7e,0x6c,0x7e,0x0c,0x0e,0x0c,0x0e,0x0c,0x0e,0x0c,0x0e,0x00, + 0x3c,0x38,0x7e,0x6c,0x7e,0x6c,0x7e,0x38,0x7e,0x6c,0x7e,0x6c,0x7e,0x38,0x3c,0x00, + 0x3c,0x38,0x7e,0x6c,0x7e,0x6c,0x7e,0x3c,0x3e,0x0c,0x7e,0x6c,0x7e,0x38,0x3c,0x00, + 0x00,0x00,0x38,0x30,0x38,0x30,0x38,0x00,0x38,0x30,0x38,0x30,0x38,0x00,0x00,0x00, + 0x00,0x00,0x38,0x30,0x38,0x30,0x38,0x00,0x38,0x30,0x38,0x30,0x78,0x60,0x70,0x00, + 0x0e,0x0c,0x1e,0x18,0x3c,0x30,0x78,0x60,0x78,0x30,0x3c,0x18,0x1e,0x0c,0x0e,0x00, + 0x00,0x00,0x00,0x00,0x3e,0x3c,0x3e,0x00,0x3e,0x3c,0x3e,0x00,0x00,0x00,0x00,0x00, + 0x70,0x60,0x78,0x30,0x3c,0x18,0x1e,0x0c,0x1e,0x18,0x3c,0x30,0x78,0x60,0x70,0x00, + 0x3c,0x38,0x7e,0x6c,0x7e,0x0c,0x1e,0x18,0x3c,0x30,0x38,0x00,0x38,0x30,0x38,0x00, + 0x3c,0x38,0x7e,0x44,0x7e,0x5c,0x7e,0x54,0x7e,0x5c,0x7e,0x40,0x7e,0x3c,0x3e,0x00, + 0x3e,0x3c,0x7f,0x66,0x77,0x66,0x7f,0x7e,0x7f,0x66,0x77,0x66,0x77,0x66,0x77,0x00, + 0x7e,0x7c,0x7f,0x66,0x77,0x66,0x7f,0x7c,0x7f,0x66,0x77,0x66,0x7f,0x7c,0x7e,0x00, + 0x3e,0x3c,0x7f,0x66,0x77,0x60,0x70,0x60,0x70,0x60,0x77,0x66,0x7f,0x3c,0x3e,0x00, + 0x7c,0x78,0x7e,0x6c,0x7f,0x66,0x77,0x66,0x77,0x66,0x7f,0x6c,0x7e,0x78,0x7c,0x00, + 0x7f,0x7e,0x7f,0x60,0x70,0x60,0x7f,0x7e,0x7f,0x60,0x70,0x60,0x7f,0x7e,0x7f,0x00, + 0x7f,0x7e,0x7f,0x60,0x70,0x60,0x7c,0x78,0x7c,0x60,0x70,0x60,0x70,0x60,0x70,0x00, + 0x3e,0x3c,0x7f,0x66,0x77,0x60,0x7f,0x6e,0x7f,0x66,0x77,0x66,0x7f,0x3c,0x3e,0x00, + 0x77,0x66,0x77,0x66,0x77,0x66,0x7f,0x7e,0x7f,0x66,0x77,0x66,0x77,0x66,0x77,0x00, + 0x7f,0x7e,0x7f,0x18,0x1c,0x18,0x1c,0x18,0x1c,0x18,0x1c,0x18,0x7f,0x7e,0x7f,0x00, + 0x07,0x06,0x07,0x06,0x07,0x06,0x07,0x06,0x77,0x66,0x77,0x66,0x7f,0x3c,0x3e,0x00, + 0x77,0x66,0x7f,0x6c,0x7e,0x78,0x7c,0x70,0x7c,0x78,0x7e,0x6c,0x7f,0x66,0x77,0x00, + 0x70,0x60,0x70,0x60,0x70,0x60,0x70,0x60,0x70,0x60,0x70,0x60,0x7f,0x7e,0x7f,0x00, + 0xfe,0xec,0xff,0xfe,0xff,0xd6,0xff,0xd6,0xff,0xc6,0xe7,0xc6,0xe7,0xc6,0xe7,0x00, + 0x77,0x66,0x7f,0x76,0x7f,0x7e,0x7f,0x7e,0x7f,0x6e,0x7f,0x66,0x77,0x66,0x77,0x00, + 0x3e,0x3c,0x7f,0x66,0x77,0x66,0x77,0x66,0x77,0x66,0x77,0x66,0x7f,0x3c,0x3e,0x00, + 0x7e,0x7c,0x7f,0x66,0x77,0x66,0x7f,0x7c,0x7e,0x60,0x70,0x60,0x70,0x60,0x70,0x00, + 0x3e,0x3c,0x7f,0x66,0x77,0x66,0x77,0x66,0x77,0x66,0x7f,0x6c,0x7f,0x3e,0x3f,0x00, + 0x7e,0x7c,0x7f,0x66,0x77,0x66,0x7f,0x7c,0x7e,0x78,0x7e,0x6c,0x7f,0x66,0x77,0x00, + 0x3e,0x3c,0x7f,0x66,0x77,0x60,0x7e,0x3c,0x3f,0x06,0x77,0x66,0x7f,0x3c,0x3e,0x00, + 0x7f,0x7e,0x7f,0x18,0x1c,0x18,0x1c,0x18,0x1c,0x18,0x1c,0x18,0x1c,0x18,0x1c,0x00, + 0x77,0x66,0x77,0x66,0x77,0x66,0x77,0x66,0x77,0x66,0x77,0x66,0x7f,0x3c,0x3e,0x00, + 0x77,0x66,0x77,0x66,0x77,0x66,0x77,0x66,0x7f,0x3c,0x3e,0x3c,0x3e,0x18,0x1c,0x00, + 0xe7,0xc6,0xe7,0xc6,0xff,0xd6,0xff,0xd6,0xff,0xd6,0xff,0xfe,0xff,0x6c,0x7e,0x00, + 0x77,0x66,0x77,0x66,0x7f,0x3c,0x3e,0x18,0x3e,0x3c,0x7f,0x66,0x77,0x66,0x77,0x00, + 0x77,0x66,0x77,0x66,0x77,0x66,0x7f,0x3c,0x3e,0x18,0x1c,0x18,0x1c,0x18,0x1c,0x00, + 0x7f,0x7e,0x7f,0x06,0x0f,0x0c,0x1e,0x18,0x3c,0x30,0x78,0x60,0x7f,0x7e,0x7f,0x00, + 0x1f,0x1e,0x1f,0x18,0x1c,0x18,0x1c,0x18,0x1c,0x18,0x1c,0x18,0x1f,0x1e,0x1f,0x00, + 0x30,0x20,0x38,0x30,0x38,0x10,0x1c,0x18,0x1c,0x08,0x0e,0x0c,0x0e,0x04,0x06,0x00, + 0xf8,0xf0,0xf8,0x30,0x38,0x30,0x38,0x30,0x38,0x30,0x38,0x30,0xf8,0xf0,0xf8,0x00, + 0x18,0x10,0x3c,0x38,0x7e,0x6c,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x7e,0x7f,0x00, + 0x30,0x20,0x30,0x20,0x38,0x10,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x3c,0x38,0x3e,0x0c,0x3e,0x3c,0x7e,0x4c,0x7e,0x34,0x3e,0x00, + 0x70,0x60,0x70,0x60,0x7c,0x78,0x7e,0x6c,0x7e,0x6c,0x7e,0x6c,0x7e,0x78,0x7c,0x00, + 0x00,0x00,0x00,0x00,0x3c,0x38,0x7e,0x6c,0x7e,0x60,0x7e,0x6c,0x7e,0x38,0x3c,0x00, + 0x0e,0x0c,0x0e,0x0c,0x3e,0x3c,0x7e,0x6c,0x7e,0x6c,0x7e,0x6c,0x7e,0x3c,0x3e,0x00, + 0x00,0x00,0x00,0x00,0x3c,0x38,0x7e,0x64,0x7e,0x7c,0x7e,0x60,0x7e,0x3c,0x3e,0x00, + 0x00,0x00,0x3c,0x38,0x7e,0x6c,0x7e,0x60,0x7c,0x78,0x7c,0x60,0x70,0x60,0x70,0x00, + 0x00,0x00,0x00,0x00,0x3e,0x3c,0x7e,0x6c,0x7e,0x3c,0x3e,0x0c,0x7e,0x78,0x7c,0x00, + 0x70,0x60,0x70,0x60,0x7c,0x78,0x7e,0x6c,0x7e,0x6c,0x7e,0x6c,0x7e,0x6c,0x7e,0x00, + 0x00,0x00,0x1c,0x18,0x1c,0x00,0x1c,0x18,0x1c,0x18,0x1c,0x18,0x1c,0x18,0x1c,0x00, + 0x00,0x00,0x0e,0x0c,0x0e,0x00,0x0e,0x0c,0x0e,0x0c,0x7e,0x6c,0x7e,0x38,0x3c,0x00, + 0x70,0x60,0x70,0x60,0x7e,0x6c,0x7e,0x78,0x7c,0x70,0x7c,0x78,0x7e,0x6c,0x7e,0x00, + 0x3c,0x38,0x3c,0x18,0x1c,0x18,0x1c,0x18,0x1c,0x18,0x1c,0x18,0x1c,0x18,0x1c,0x00, + 0x00,0x00,0x00,0x00,0x7e,0x6c,0x7f,0x7e,0x7f,0x56,0x7f,0x66,0x77,0x66,0x77,0x00, + 0x00,0x00,0x00,0x00,0x7c,0x78,0x7e,0x6c,0x7e,0x6c,0x7e,0x6c,0x7e,0x6c,0x7e,0x00, + 0x00,0x00,0x00,0x00,0x3c,0x38,0x7e,0x6c,0x7e,0x6c,0x7e,0x6c,0x7e,0x38,0x3c,0x00, + 0x00,0x00,0x00,0x00,0x7c,0x78,0x7e,0x6c,0x7e,0x78,0x7c,0x60,0x70,0x60,0x70,0x00, + 0x00,0x00,0x00,0x00,0x3e,0x3c,0x7e,0x6c,0x7e,0x3c,0x3e,0x0c,0x0e,0x0c,0x0e,0x00, + 0x00,0x00,0x00,0x00,0x7c,0x78,0x7e,0x6c,0x7e,0x60,0x70,0x60,0x70,0x60,0x70,0x00, + 0x00,0x00,0x00,0x00,0x3e,0x3c,0x7e,0x60,0x7c,0x38,0x3e,0x0c,0x7e,0x78,0x7c,0x00, + 0x00,0x00,0x1c,0x18,0x3e,0x3c,0x3e,0x18,0x1c,0x18,0x1c,0x18,0x1e,0x0c,0x0e,0x00, + 0x00,0x00,0x00,0x00,0x7e,0x6c,0x7e,0x6c,0x7e,0x6c,0x7e,0x6c,0x7e,0x34,0x3e,0x00, + 0x00,0x00,0x00,0x00,0x7e,0x6c,0x7e,0x6c,0x7e,0x6c,0x7e,0x3c,0x3e,0x18,0x1c,0x00, + 0x00,0x00,0x00,0x00,0xe7,0xc6,0xe7,0xc6,0xff,0xd6,0xff,0x7c,0x7e,0x6c,0x7e,0x00, + 0x00,0x00,0x00,0x00,0x7e,0x6c,0x7e,0x38,0x3c,0x10,0x3c,0x38,0x7e,0x6c,0x7e,0x00, + 0x00,0x00,0x00,0x00,0x7e,0x6c,0x7e,0x6c,0x7e,0x3c,0x3e,0x18,0x7c,0x70,0x78,0x00, + 0x00,0x00,0x00,0x00,0x7e,0x7c,0x7e,0x18,0x3c,0x30,0x78,0x60,0x7e,0x7c,0x7e,0x00, +/*;;*/ +}; + +/* load the font into BG tile data (call with the LCD off) */ +static void font_init(void) { + set_bkg_data(FONT_TILE_BASE, FONT_NUM_TILES, font_tiles); +} + +/* write a string to the tile map; tile index == ASCII code */ +static void put_str(uint8_t x, uint8_t y, const char* s) { + set_bkg_tiles(x, y, strlen(s), 1, (uint8_t*)s); +} + +/* write a single character to the tile map */ +static void put_char(uint8_t x, uint8_t y, char c) { + set_bkg_tiles(x, y, 1, 1, (uint8_t*)&c); +} + +#endif diff --git a/presets/gb/hello.c b/presets/gb/hello.c index 7fa9e8bd..e05f7e14 100644 --- a/presets/gb/hello.c +++ b/presets/gb/hello.c @@ -1,78 +1,43 @@ +/* +Hello world for Game Boy. +Set the BG palette, write a message to the tile map, +then turn on the LCD. + +Ported from presets/nes/hello.c, using GBDK (gb/gb.h). +*/ //#link "gb/sfr.sgb" //#link "gb/crt0.sgb" //#resource "gb/global.sgb" + #include -#include #include "gb/types.h" #include "gb/hardware.h" #include "gb/gb.h" +#include "gbtext.h" -#define NUM_TILES 46 +// main function, run after console reset +void main(void) { -static const uint8_t font[NUM_TILES*16] = { -/*;;{w:8,h:8,bpp:1,count:46,brev:1,np:2,pofs:1,sl:2};;*/ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x81,0x81,0x42,0x42,0x24,0x24,0x18,0x18,0x18,0x18,0x24,0x24,0x42,0x42,0x81,0x81 -,0x00,0x00,0x24,0x24,0x00,0x00,0x00,0x00,0x24,0x24,0x18,0x18,0x00,0x00,0x00,0x00 -,0x00,0x00,0x24,0x24,0x00,0x00,0x00,0x00,0x18,0x18,0x24,0x24,0x00,0x00,0x00,0x00 -,0x00,0x00,0x36,0x36,0x49,0x49,0x41,0x41,0x22,0x22,0x14,0x14,0x08,0x08,0x00,0x00 -,0x00,0x00,0x00,0x00,0x08,0x08,0x04,0x04,0x7E,0x7E,0x04,0x04,0x08,0x08,0x00,0x00 -,0x00,0x00,0x00,0x00,0x10,0x10,0x20,0x20,0x7E,0x7E,0x20,0x20,0x10,0x10,0x00,0x00 -,0x00,0x00,0x10,0x10,0x38,0x38,0x54,0x54,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00 -,0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x54,0x54,0x38,0x38,0x10,0x10,0x00,0x00 -,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x7C,0x7C,0x10,0x10,0x10,0x10,0x00,0x00 -,0x00,0x00,0x1C,0x1C,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x1C,0x1C,0x00,0x00 -,0x00,0x00,0x06,0x06,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x00,0x00 -,0x00,0x00,0x1C,0x1C,0x02,0x02,0x04,0x04,0x08,0x08,0x10,0x10,0x1E,0x1E,0x00,0x00 -,0x00,0x00,0x1C,0x1C,0x02,0x02,0x0C,0x0C,0x02,0x02,0x02,0x02,0x1C,0x1C,0x00,0x00 -,0x00,0x00,0x12,0x12,0x12,0x12,0x1E,0x1E,0x02,0x02,0x02,0x02,0x02,0x02,0x00,0x00 -,0x00,0x00,0x1E,0x1E,0x10,0x10,0x1E,0x1E,0x02,0x02,0x02,0x02,0x1E,0x1E,0x00,0x00 -,0x00,0x00,0x0C,0x0C,0x10,0x10,0x1C,0x1C,0x12,0x12,0x12,0x12,0x0C,0x0C,0x00,0x00 -,0x00,0x00,0x1C,0x1C,0x04,0x04,0x0E,0x0E,0x04,0x04,0x04,0x04,0x04,0x04,0x00,0x00 -,0x00,0x00,0x1C,0x1C,0x22,0x22,0x1C,0x1C,0x22,0x22,0x22,0x22,0x1C,0x1C,0x00,0x00 -,0x00,0x00,0x1E,0x1E,0x12,0x12,0x1E,0x1E,0x02,0x02,0x02,0x02,0x02,0x02,0x00,0x00 -,0x00,0x00,0x18,0x18,0x24,0x24,0x3C,0x3C,0x24,0x24,0x24,0x24,0x24,0x24,0x00,0x00 -,0x00,0x00,0x38,0x38,0x24,0x24,0x38,0x38,0x24,0x24,0x24,0x24,0x38,0x38,0x00,0x00 -,0x00,0x00,0x1C,0x1C,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x1C,0x1C,0x00,0x00 -,0x00,0x00,0x38,0x38,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x38,0x38,0x00,0x00 -,0x00,0x00,0x3C,0x3C,0x20,0x20,0x38,0x38,0x20,0x20,0x20,0x20,0x3C,0x3C,0x00,0x00 -,0x00,0x00,0x3C,0x3C,0x20,0x20,0x38,0x38,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00 -,0x00,0x00,0x18,0x18,0x20,0x20,0x2C,0x2C,0x24,0x24,0x24,0x24,0x18,0x18,0x00,0x00 -,0x00,0x00,0x24,0x24,0x24,0x24,0x3C,0x3C,0x24,0x24,0x24,0x24,0x24,0x24,0x00,0x00 -,0x00,0x00,0x38,0x38,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x38,0x00,0x00 -,0x00,0x00,0x3C,0x3C,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x38,0x38,0x00,0x00 -,0x00,0x00,0x24,0x24,0x28,0x28,0x30,0x30,0x28,0x28,0x24,0x24,0x24,0x24,0x00,0x00 -,0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x38,0x38,0x00,0x00 -,0x00,0x00,0x22,0x22,0x36,0x36,0x2A,0x2A,0x22,0x22,0x22,0x22,0x22,0x22,0x00,0x00 -,0x00,0x00,0x24,0x24,0x34,0x34,0x2C,0x2C,0x24,0x24,0x24,0x24,0x24,0x24,0x00,0x00 -,0x00,0x00,0x18,0x18,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x18,0x18,0x00,0x00 -,0x00,0x00,0x38,0x38,0x24,0x24,0x38,0x38,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00 -,0x00,0x00,0x18,0x18,0x24,0x24,0x24,0x24,0x24,0x24,0x2C,0x2C,0x1C,0x1C,0x02,0x02 -,0x00,0x00,0x38,0x38,0x24,0x24,0x38,0x38,0x24,0x24,0x24,0x24,0x24,0x24,0x00,0x00 -,0x00,0x00,0x1C,0x1C,0x20,0x20,0x18,0x18,0x04,0x04,0x04,0x04,0x38,0x38,0x00,0x00 -,0x00,0x00,0x3E,0x3E,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x00 -,0x00,0x00,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x18,0x18,0x00,0x00 -,0x00,0x00,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x14,0x14,0x08,0x08,0x00,0x00 -,0x00,0x00,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x2A,0x2A,0x14,0x14,0x00,0x00 -,0x00,0x00,0x22,0x22,0x14,0x14,0x08,0x08,0x08,0x08,0x14,0x14,0x22,0x22,0x00,0x00 -,0x00,0x00,0x22,0x22,0x14,0x14,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x00 -,0x00,0x00,0x3C,0x3C,0x04,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x3C,0x3C,0x00,0x00 -/*;;*/ -}; - -void main(void) -{ + // GB can only write VRAM while the LCD is off DISPLAY_OFF; - memcpy(_VRAM8000, font, sizeof(font)); // copy tile data - memcpy(_SCRN0, font, 32*32); // copy garbage data to screen - BGP_REG = 0xe4; // palette - LCDC_REG = LCDCF_ON|LCDCF_BG8000|LCDCF_BG9800|LCDCF_BGON|LCDCF_OBJ16|LCDCF_OBJON|LCDCF_WIN9C00|LCDCF_WINOFF; + + // background palette: color 0 = white, 1 = light, 2 = dark, 3 = black + BGP_REG = 0xE4; + OBP0_REG = OBP1_REG = 0xE4; + + // copy the 8x8 font into BG tile data + font_init(); + + // write text to the tile map (tile index == ASCII code) + put_str(2, 2, "HELLO, WORLD!"); + + // enable the background layer, then the LCD + SHOW_BKG; DISPLAY_ON; - // Loop forever - while(1) { - // Game main loop processing goes here - // Done processing, yield CPU and wait for start of next frame + + // infinite loop + while (1) { wait_vbl_done(); } } diff --git a/presets/gb/metasprites.c b/presets/gb/metasprites.c new file mode 100644 index 00000000..47b3f444 --- /dev/null +++ b/presets/gb/metasprites.c @@ -0,0 +1,86 @@ +/* +Metasprites combine several hardware sprites to make a larger +sprite. Our demo uses 4 hardware sprites in a 2x2 pattern, +forming 16x16 pixel sprites. + +Ported from presets/nes/metasprites.c, using GBDK (gb/metasprites.h). +The Game Boy OAM holds 40 sprites, so 10 actors of 4 sprites each +fit on screen (the NES fits 16). +*/ + +//#link "gb/sfr.sgb" +//#link "gb/crt0.sgb" +//#resource "gb/global.sgb" + +#include +#include +#include "gb/types.h" +#include "gb/hardware.h" +#include "gb/gb.h" +#include "gb/metasprites.h" +#include "gbtext.h" + +///// METASPRITES + +// a 2x2 metasprite made from four font tiles +#define TILE 0x21 +const metasprite_t metasprite[] = { + METASPR_ITEM(0, 0, TILE+0, 0), + METASPR_ITEM(0, 8, TILE+1, 0), + METASPR_ITEM(8, 0, TILE+2, 0), + METASPR_ITEM(8, 8, TILE+3, 0), + METASPR_TERM +}; + +// number of actors (4 h/w sprites each; 10 * 4 = 40 sprites) +#define NUM_ACTORS 10 + +// actor x/y positions +uint8_t actor_x[NUM_ACTORS]; +uint8_t actor_y[NUM_ACTORS]; +// actor x/y deltas per frame (signed) +int8_t actor_dx[NUM_ACTORS]; +int8_t actor_dy[NUM_ACTORS]; + +// setup LCD and tile data +void setup_graphics(void) { + DISPLAY_OFF; + BGP_REG = OBP0_REG = OBP1_REG = 0xE4; + LCDC_REG |= LCDCF_BG8000; + font_init(); + SHOW_BKG; + SHOW_SPRITES; + DISPLAY_ON; +} + +// main program +void main(void) { + uint8_t i; // actor index + + // initialize PPU + setup_graphics(); + + // initialize actors with random values + for (i=0; i= 0x80 end of chord; low 6 bits = duration in frames + * 0xff end of score + * + * Notes < BASS_NOTE go to the wave channel, the rest to the pulses, + * exactly like the NES player routes low notes to the triangle. + * + * "The Easy Winners" by Scott Joplin. + */ + +//#link "gb/sfr.sgb" +//#link "gb/crt0.sgb" +//#resource "gb/global.sgb" +#include +#include +#include "gb/types.h" +#include "gb/hardware.h" +#include "gb/gb.h" +#include "gbtext.h" + +typedef uint8_t byte; +typedef uint16_t word; + +#define BASS_NOTE 36 + +/* Note indices match the NES score: MIDI note = index + 20. + * Pulse periods are 11-bit: f = 131072 / (2048 - X). Indices below 16 + * are under the pulse channel's range and clamp to X = 0. */ +const word note_table_pulse[64] = { + 0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000, + 0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000, + 0x02c,0x09d,0x107,0x16b,0x1c9,0x223,0x277,0x2c7, + 0x312,0x358,0x39b,0x3da,0x416,0x44e,0x483,0x4b5, + 0x4e5,0x511,0x53b,0x563,0x589,0x5ac,0x5ce,0x5ed, + 0x60b,0x627,0x642,0x65b,0x672,0x689,0x69e,0x6b2, + 0x6c4,0x6d6,0x6e7,0x6f7,0x706,0x714,0x721,0x72d, + 0x739,0x744,0x74f,0x759,0x762,0x76b,0x773,0x77b, +}; + +/* Wave-channel periods: f = 65536 / (2048 - X). The wave channel goes + * an octave lower than the pulses, so it covers the low bass notes. */ +const word note_table_wave[64] = { + 0x000,0x000,0x000,0x000,0x02c,0x09d,0x107,0x16b, + 0x1c9,0x223,0x277,0x2c7,0x312,0x358,0x39b,0x3da, + 0x416,0x44e,0x483,0x4b5,0x4e5,0x511,0x53b,0x563, + 0x589,0x5ac,0x5ce,0x5ed,0x60b,0x627,0x642,0x65b, + 0x672,0x689,0x69e,0x6b2,0x6c4,0x6d6,0x6e7,0x6f7, + 0x706,0x714,0x721,0x72d,0x739,0x744,0x74f,0x759, + 0x762,0x76b,0x773,0x77b,0x783,0x78a,0x790,0x797, + 0x79d,0x7a2,0x7a7,0x7ac,0x7b1,0x7b6,0x7ba,0x7be, +}; + +/* 32-sample triangle waveform, two 4-bit samples per byte. */ +const uint8_t wave_pattern[16] = { + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 +}; + +byte cur_duration = 0; +byte chs = 0; /* channels assigned for the current chord */ +const byte* music_ptr = 0; + +extern const byte music1[]; /* score -- see end of file */ + +byte next_music_byte(void) { + return *music_ptr++; +} + +void psg_init(void) { + byte i; + NR52_REG = 0x80; /* sound on */ + NR51_REG = 0xFF; /* all channels to both outputs */ + NR50_REG = 0x77; /* master volume */ + NR10_REG = 0x00; /* pulse 1 sweep off */ + /* load wave RAM with the wave DAC off */ + NR30_REG = 0x00; + for (i = 0; i < 16; i++) _AUD3WAVERAM[i] = wave_pattern[i]; + NR32_REG = 0x20; /* wave output level 100% */ +} + +void gb_pulse_note(byte ch, word period, byte vol) { + byte lo = (byte)(period & 0xff); + byte hi = (byte)((period >> 8) & 0x07); + byte env = (byte)((vol << 4) | 0x02); /* decay envelope from vol */ + if (ch == 0) { + NR11_REG = 0x80; /* 50% duty */ + NR12_REG = env; + NR13_REG = lo; + NR14_REG = (byte)(0x80 | hi); /* trigger */ + } else { + NR21_REG = 0x80; + NR22_REG = env; + NR23_REG = lo; + NR24_REG = (byte)(0x80 | hi); /* trigger */ + } +} + +void gb_wave_note(word period) { + NR30_REG = 0x80; /* wave DAC on */ + NR31_REG = 0x00; /* length (unused) */ + NR32_REG = 0x20; /* 100% volume */ + NR33_REG = (byte)(period & 0xff); + NR34_REG = (byte)(0x80 | ((period >> 8) & 0x07)); /* trigger */ +} + +void play_music(void) { + if (music_ptr) { + /* run out the duration timer, fetching notes as needed */ + while (cur_duration == 0) { + byte note = next_music_byte(); + if ((note & 0x80) == 0) { + /* pulses play higher notes, wave handles the low bass */ + if (note >= BASS_NOTE || (chs & 4)) { + word period = note_table_pulse[note & 63]; + /* use whichever pulse generator is free */ + if (!(chs & 1)) { + gb_pulse_note(0, period, 15); + chs |= 1; + } else if (!(chs & 2)) { + gb_pulse_note(1, period, 15); + chs |= 2; + } + } else { + gb_wave_note(note_table_wave[note & 63]); + chs |= 4; + } + } else { + /* end of chord: set duration and free every channel */ + if (note == 0xff) music_ptr = 0; + cur_duration = note & 63; + chs = 0; + } + } + cur_duration--; + } +} + +void start_music(const byte* music) { + music_ptr = music; + cur_duration = 0; + chs = 0; +} + +void main(void) { + /* title screen (LCD off while writing tiles and the tile map) */ + DISPLAY_OFF; + BGP_REG = 0xE4; + OBP0_REG = OBP1_REG = 0xE4; + font_init(); + put_str(1, 7, "THE EASY WINNERS"); + put_str(4, 9, "SCOTT JOPLIN"); + SHOW_BKG; + DISPLAY_ON; + + psg_init(); + music_ptr = 0; + while (1) { + if (!music_ptr) start_music(music1); + wait_vbl_done(); + play_music(); + } +} + +const byte music1[] = { +0x2a,0x1e,0x95,0x33,0x27,0x9f,0x31,0x25,0x8a,0x2f,0x23,0x8b,0x2e,0x22,0x89,0x2c,0x20,0x8b,0x2a,0x1e,0x95,0x28,0x1c,0x8a,0x27,0x1b,0x95,0x25,0x19,0x8b,0x23,0x17,0x89,0x22,0x12,0x8b,0x23,0x8a,0x25,0x8b,0x27,0x89,0x28,0x1e,0x8c,0x2a,0x1c,0x89,0x2c,0x1b,0x8c,0x2e,0x19,0x89,0x2f,0x17,0x95,0x27,0x23,0x1e,0x95,0x12,0x95,0x23,0x1e,0x27,0x95,0x2f,0x33,0x17,0x95,0x2f,0x33,0x27,0x94,0x12,0x95,0x33,0x36,0x23,0x95,0x38,0x32,0x17,0x8b,0x33,0x36,0x89,0x1e,0x27,0x23,0x8b,0x38,0x32,0x8a,0x33,0x36,0x12,0x8b,0x32,0x38,0x89,0x36,0x33,0x27,0x95,0x3d,0x37,0x10,0x8b,0x3b,0x38,0x8a,0x20,0x23,0x28,0x8b,0x37,0x3d,0x89,0x38,0x3b,0x10,0x8b,0x37,0x3d,0x8a,0x3b,0x38,0x28,0x8b,0x36,0x33,0x8a,0x17,0x95,0x2a,0x1e,0x23,0x8b,0x2c,0x89,0x2e,0x12,0x8b,0x2f,0x8a,0x31,0x27,0x23,0x8b,0x32,0x89,0x2f,0x33,0x17,0x95,0x33,0x2f,0x1e,0x95,0x12,0x94,0x36,0x33,0x1e,0x95,0x32,0x38,0x17,0x8b,0x36,0x33,0x89,0x23,0x1e,0x27,0x8b,0x38,0x32,0x8a,0x33,0x36,0x18,0x8b,0x33,0x36,0x8a,0x33,0x36,0x2a,0x95,0x36,0x19,0x8b,0x31,0x2e,0x89,0x25,0x22,0x2a,0x8b,0x36,0x8a,0x2f,0x35,0x19,0x8b,0x36,0x89,0x38,0x2f,0x29,0x95,0x2e,0x36,0x1e,0x95,0x1c,0x28,0x95,0x27,0x1b,0x8b,0x2a,0x8a,0x2e,0x25,0x19,0x8b,0x34,0x89,0x33,0x2f,0x23,0x95,0x33,0x2f,0x1e,0x95,0x12,0x94,0x33,0x36,0x23,0x95,0x32,0x38,0x17,0x8b,0x33,0x36,0x8a,0x23,0x27,0x1e,0x8b,0x38,0x32,0x89,0x36,0x33,0x12,0x8b,0x32,0x38,0x8a,0x33,0x36,0x1e,0x94,0x37,0x3d,0x10,0x8b,0x3b,0x38,0x8a,0x23,0x28,0x20,0x8b,0x3d,0x37,0x89,0x3b,0x38,0x1c,0x8b,0x38,0x3b,0x8a,0x3a,0x3d,0x38,0x8b,0x3f,0x37,0x3a,0x89,0x27,0x1b,0x8b,0x33,0x8a,0x37,0x22,0x16,0x8b,0x3a,0x8a,0x3f,0x0f,0x1b,0x95,0x3a,0x8b,0x3b,0x8a,0x3d,0x37,0x1c,0x8b,0x3b,0x38,0x89,0x23,0x28,0x20,0x8b,0x3d,0x37,0x8a,0x38,0x3b,0x10,0x8b,0x3d,0x37,0x89,0x38,0x3b,0x20,0x8b,0x36,0x33,0x8a,0x17,0x23,0x8b,0x38,0x34,0x8a,0x33,0x36,0x1e,0x8b,0x31,0x34,0x8a,0x2f,0x33,0x17,0x8b,0x36,0x33,0x8a,0x23,0x27,0x1e,0x8b,0x33,0x36,0x8a,0x36,0x30,0x12,0x8a,0x34,0x31,0x8a,0x1e,0x28,0x22,0x8b,0x30,0x36,0x89,0x34,0x31,0x12,0x8b,0x2e,0x28,0x33,0x8a,0x31,0x28,0x2e,0x95,0x27,0x2f,0x1e,0x95,0x12,0x95,0x14,0x94,0x16,0x95,0x2f,0x33,0x17,0x95,0x2f,0x33,0x27,0x94,0x12,0x95,0x36,0x33,0x23,0x95,0x32,0x38,0x17,0x8a,0x33,0x36,0x8a,0x23,0x27,0x1e,0x8b,0x32,0x38,0x8a,0x33,0x36,0x12,0x8b,0x38,0x32,0x8a,0x36,0x33,0x27,0x95,0x3d,0x37,0x10,0x8a,0x3b,0x38,0x8a,0x23,0x28,0x20,0x8b,0x37,0x3d,0x89,0x3b,0x38,0x10,0x8b,0x37,0x3d,0x8a,0x38,0x3b,0x23,0x8b,0x36,0x33,0x8a,0x17,0x95,0x2a,0x1e,0x23,0x8b,0x2c,0x8a,0x2e,0x12,0x8b,0x2f,0x89,0x31,0x23,0x1e,0x8b,0x32,0x8a,0x33,0x2f,0x17,0x95,0x2f,0x33,0x1e,0x94,0x12,0x95,0x36,0x33,0x27,0x95,0x38,0x32,0x17,0x8a,0x36,0x33,0x8a,0x23,0x1e,0x27,0x8b,0x38,0x32,0x89,0x33,0x36,0x18,0x8c,0x36,0x33,0x89,0x33,0x36,0x21,0x95,0x36,0x19,0x8b,0x2e,0x31,0x8a,0x25,0x2a,0x22,0x8b,0x36,0x89,0x35,0x2f,0x19,0x8b,0x36,0x8a,0x2f,0x38,0x25,0x94,0x36,0x2e,0x2a,0x95,0x1c,0x28,0x95,0x27,0x1b,0x8c,0x2a,0x89,0x2e,0x25,0x19,0x8b,0x34,0x8a,0x33,0x2f,0x23,0x95,0x2f,0x33,0x1e,0x94,0x12,0x95,0x33,0x36,0x23,0x95,0x32,0x38,0x17,0x8a,0x33,0x36,0x8a,0x23,0x1e,0x27,0x8b,0x32,0x38,0x89,0x36,0x33,0x12,0x8c,0x32,0x38,0x89,0x33,0x36,0x1e,0x95,0x37,0x3d,0x10,0x8b,0x3b,0x38,0x8a,0x23,0x20,0x28,0x8a,0x3d,0x37,0x8a,0x38,0x3b,0x1c,0x8b,0x3b,0x38,0x8a,0x3d,0x38,0x3a,0x8b,0x3a,0x3f,0x37,0x89,0x27,0x1b,0x8b,0x33,0x8a,0x37,0x22,0x16,0x8b,0x3a,0x8a,0x3f,0x0f,0x1b,0x95,0x3a,0x8b,0x3b,0x8a,0x3d,0x37,0x1c,0x8b,0x3b,0x38,0x8a,0x20,0x28,0x23,0x8b,0x3d,0x37,0x89,0x38,0x3b,0x10,0x8b,0x3d,0x37,0x8a,0x38,0x3b,0x20,0x8b,0x33,0x36,0x89,0x17,0x23,0x8b,0x38,0x34,0x8a,0x36,0x33,0x23,0x8b,0x34,0x31,0x89,0x2f,0x33,0x17,0x8c,0x36,0x33,0x89,0x1e,0x27,0x23,0x8c,0x33,0x36,0x89,0x36,0x30,0x12,0x8b,0x34,0x31,0x8a,0x1e,0x28,0x22,0x8a,0x30,0x36,0x8a,0x34,0x31,0x1e,0x8b,0x28,0x2e,0x33,0x89,0x28,0x31,0x2e,0x95,0x27,0x2f,0x17,0x95,0x12,0x1e,0x95,0x3b,0x36,0x33,0x96,0x2a,0x8b,0x2b,0x8a,0x2c,0x1e,0x12,0x8b,0x2d,0x89,0x2e,0x28,0x1e,0x8b,0x2e,0x31,0x8a,0x16,0x22,0x8b,0x36,0x89,0x34,0x1e,0x22,0x8b,0x31,0x8a,0x2c,0x25,0x19,0x8b,0x2d,0x89,0x2e,0x28,0x25,0x8b,0x33,0x2e,0x8a,0x25,0x19,0x8c,0x31,0x89,0x2c,0x1a,0x26,0x8b,0x2e,0x8a,0x2f,0x1b,0x27,0x8b,0x2a,0x89,0x2c,0x23,0x1e,0x8b,0x2e,0x8a,0x2f,0x12,0x1e,0x8b,0x30,0x89,0x31,0x27,0x23,0x8b,0x32,0x8a,0x33,0x17,0x23,0x8b,0x32,0x8a,0x33,0x1e,0x23,0x8b,0x38,0x33,0x8a,0x1e,0x12,0x8b,0x36,0x8a,0x31,0x1e,0x23,0x8b,0x33,0x89,0x34,0x25,0x19,0x8b,0x3d,0x89,0x1e,0x28,0x22,0x8b,0x33,0x89,0x34,0x12,0x1e,0x8b,0x3d,0x8a,0x1e,0x22,0x28,0x8a,0x33,0x8a,0x34,0x19,0x25,0x8b,0x3d,0x89,0x28,0x1e,0x22,0x8b,0x3b,0x89,0x3a,0x1e,0x12,0x8b,0x38,0x8a,0x36,0x22,0x16,0x8b,0x34,0x8a,0x33,0x23,0x17,0x8b,0x3b,0x8a,0x1e,0x23,0x27,0x8a,0x32,0x8a,0x33,0x12,0x1e,0x8b,0x3b,0x89,0x27,0x23,0x1e,0x8b,0x32,0x89,0x33,0x23,0x17,0x8b,0x3b,0x89,0x1e,0x23,0x27,0x8b,0x38,0x8a,0x36,0x12,0x1e,0x8b,0x33,0x89,0x31,0x1e,0x27,0x8b,0x2f,0x8a,0x2e,0x20,0x14,0x8b,0x2f,0x8a,0x30,0x2a,0x24,0x8b,0x30,0x38,0x8a,0x24,0x18,0x8b,0x36,0x89,0x33,0x24,0x20,0x8b,0x30,0x8a,0x2e,0x27,0x1b,0x8b,0x2f,0x89,0x30,0x24,0x2a,0x8b,0x30,0x38,0x8a,0x20,0x14,0x8b,0x33,0x36,0x8a,0x38,0x30,0x24,0x8b,0x33,0x36,0x89,0x34,0x31,0x19,0x8b,0x30,0x33,0x89,0x31,0x34,0x25,0x8b,0x2c,0x89,0x1c,0x8b,0x30,0x8a,0x31,0x20,0x28,0x8a,0x34,0x8a,0x38,0x19,0x8b,0x33,0x89,0x34,0x25,0x20,0x8b,0x31,0x8a,0x25,0x20,0x1c,0x8b,0x2c,0x8a,0x28,0x8b,0x25,0x8a,0x26,0x1d,0x8a,0x29,0x20,0x8a,0x2c,0x23,0x8b,0x2f,0x26,0x89,0x32,0x29,0x8b,0x32,0x29,0x94,0x32,0x29,0x94,0x35,0x2c,0x8a,0x38,0x2f,0x8a,0x3b,0x32,0x8a,0x35,0x3e,0xa8,0x2f,0x3f,0x36,0x8b,0x3b,0x8a,0x36,0x8b,0x33,0x94,0x2f,0x8a,0x27,0x8b,0x2a,0x89,0x2a,0x2e,0x28,0x8b,0x31,0x2a,0x2e,0x8a,0x1e,0x12,0x8b,0x2f,0x2a,0x27,0x8a,0x17,0x23,0x95,0x2a,0x8b,0x2b,0x8a,0x2c,0x1e,0x12,0x8a,0x2d,0x8a,0x2e,0x25,0x1e,0x8b,0x31,0x2e,0x89,0x22,0x16,0x8b,0x36,0x8a,0x34,0x1e,0x22,0x8a,0x31,0x8a,0x2c,0x25,0x19,0x8b,0x2d,0x89,0x2e,0x28,0x25,0x8b,0x33,0x2e,0x8a,0x19,0x25,0x8a,0x31,0x8a,0x2c,0x1a,0x26,0x8b,0x2e,0x89,0x2f,0x27,0x1b,0x8b,0x2a,0x89,0x2c,0x23,0x1e,0x8b,0x2e,0x8a,0x2f,0x1e,0x12,0x8b,0x30,0x89,0x31,0x27,0x23,0x8b,0x32,0x8a,0x33,0x17,0x23,0x8b,0x32,0x8a,0x33,0x1e,0x23,0x8b,0x33,0x38,0x8a,0x12,0x1e,0x8b,0x36,0x8a,0x31,0x27,0x1e,0x8b,0x33,0x89,0x34,0x25,0x19,0x8b,0x3d,0x89,0x28,0x1e,0x22,0x8b,0x33,0x8a,0x34,0x1e,0x12,0x8b,0x3d,0x89,0x1e,0x22,0x28,0x8b,0x33,0x89,0x34,0x19,0x25,0x8b,0x3d,0x8a,0x22,0x1e,0x28,0x8b,0x3b,0x89,0x3a,0x12,0x1e,0x8b,0x38,0x89,0x36,0x22,0x16,0x8b,0x34,0x8a,0x33,0x23,0x17,0x8b,0x3b,0x8a,0x1e,0x27,0x23,0x8b,0x32,0x8a,0x33,0x1e,0x12,0x8a,0x3b,0x8a,0x23,0x1e,0x27,0x8b,0x32,0x89,0x33,0x23,0x17,0x8b,0x3b,0x8a,0x27,0x1e,0x23,0x8a,0x38,0x8a,0x36,0x12,0x1e,0x8b,0x33,0x8a,0x31,0x1e,0x23,0x8b,0x2f,0x89,0x2e,0x14,0x20,0x8b,0x2f,0x8a,0x30,0x24,0x20,0x8b,0x38,0x30,0x89,0x18,0x24,0x8c,0x36,0x8a,0x33,0x24,0x20,0x8a,0x30,0x8a,0x2e,0x27,0x1b,0x8b,0x2f,0x89,0x30,0x24,0x20,0x8b,0x38,0x30,0x8a,0x14,0x20,0x8b,0x36,0x33,0x8a,0x30,0x38,0x20,0x8b,0x36,0x33,0x8a,0x31,0x34,0x19,0x8b,0x33,0x30,0x89,0x34,0x31,0x25,0x8b,0x2c,0x8a,0x1c,0x8a,0x30,0x8a,0x31,0x28,0x20,0x8b,0x34,0x89,0x38,0x19,0x8b,0x33,0x8a,0x34,0x25,0x20,0x8b,0x31,0x8a,0x25,0x20,0x1c,0x8b,0x2c,0x89,0x28,0x8b,0x25,0x8a,0x26,0x1d,0x8b,0x29,0x20,0x89,0x2c,0x23,0x8b,0x2f,0x26,0x8a,0x32,0x29,0x8a,0x32,0x29,0x95,0x32,0x29,0x94,0x35,0x2c,0x8a,0x38,0x2f,0x8b,0x3b,0x32,0x89,0x3e,0x35,0xa9,0x36,0x3f,0x2f,0x8b,0x3b,0x8a,0x36,0x8b,0x33,0x95,0x2f,0x89,0x27,0x8b,0x2a,0x89,0x28,0x31,0x2a,0x8b,0x2e,0x31,0x28,0x8a,0x12,0x1e,0x8b,0x27,0x2a,0x2f,0x8a,0x17,0x23,0x95,0x2a,0x94,0x33,0x2f,0x17,0x94,0x2f,0x33,0x1e,0x95,0x12,0x94,0x33,0x36,0x23,0x95,0x38,0x32,0x17,0x8a,0x33,0x36,0x8a,0x27,0x1e,0x23,0x8b,0x32,0x38,0x8a,0x33,0x36,0x12,0x8b,0x32,0x38,0x89,0x33,0x36,0x27,0x95,0x3d,0x37,0x10,0x8b,0x38,0x3b,0x8a,0x28,0x20,0x23,0x8b,0x3d,0x37,0x89,0x3b,0x38,0x10,0x8b,0x3d,0x37,0x8a,0x38,0x3b,0x23,0x8b,0x36,0x33,0x8a,0x17,0x95,0x2a,0x1e,0x23,0x8b,0x2c,0x89,0x2e,0x12,0x8b,0x2f,0x8a,0x31,0x23,0x1e,0x8b,0x32,0x89,0x33,0x2f,0x17,0x94,0x2f,0x33,0x1e,0x95,0x12,0x94,0x33,0x36,0x27,0x95,0x38,0x32,0x17,0x8b,0x36,0x33,0x8a,0x23,0x27,0x1e,0x8b,0x32,0x38,0x8a,0x33,0x36,0x18,0x8b,0x36,0x33,0x8a,0x33,0x36,0x2a,0x95,0x36,0x19,0x8b,0x31,0x2e,0x89,0x22,0x2a,0x25,0x8b,0x36,0x89,0x35,0x2f,0x19,0x8b,0x36,0x8a,0x2f,0x38,0x25,0x95,0x2e,0x36,0x2a,0x95,0x28,0x1c,0x95,0x27,0x1b,0x8b,0x2a,0x8a,0x2e,0x25,0x19,0x8b,0x34,0x89,0x33,0x2f,0x17,0x95,0x2f,0x33,0x23,0x94,0x12,0x95,0x33,0x36,0x1e,0x95,0x38,0x32,0x17,0x8b,0x36,0x33,0x8a,0x23,0x27,0x1e,0x8b,0x32,0x38,0x8a,0x33,0x36,0x12,0x8b,0x38,0x32,0x8a,0x33,0x36,0x1e,0x95,0x3d,0x37,0x10,0x8b,0x3b,0x38,0x89,0x23,0x28,0x20,0x8b,0x37,0x3d,0x8a,0x38,0x3b,0x1c,0x8b,0x38,0x3b,0x89,0x38,0x3d,0x3a,0x8b,0x3f,0x3a,0x37,0x8a,0x1b,0x27,0x8b,0x33,0x8a,0x37,0x22,0x16,0x8b,0x3a,0x8a,0x3f,0x0f,0x1b,0x95,0x3a,0x8b,0x3b,0x89,0x3d,0x37,0x1c,0x8b,0x38,0x3b,0x8a,0x28,0x20,0x23,0x8a,0x3d,0x37,0x8a,0x38,0x3b,0x10,0x8b,0x3d,0x37,0x89,0x3b,0x38,0x20,0x8b,0x33,0x36,0x8a,0x23,0x17,0x8b,0x38,0x34,0x8a,0x33,0x36,0x27,0x8b,0x34,0x31,0x8a,0x33,0x2f,0x23,0x8b,0x36,0x33,0x8a,0x1e,0x23,0x27,0x8b,0x33,0x36,0x8a,0x36,0x30,0x12,0x8b,0x34,0x31,0x89,0x1e,0x28,0x22,0x8b,0x30,0x36,0x89,0x31,0x34,0x1e,0x8b,0x2e,0x28,0x33,0x8a,0x28,0x31,0x2e,0x95,0x2f,0x27,0x17,0x95,0x12,0x1e,0x95,0x36,0x33,0x3b,0xa9,0x34,0x28,0x95,0x34,0x28,0xa0,0x2f,0x23,0x8a,0x34,0x28,0x8b,0x36,0x2a,0x8a,0x38,0x2c,0x94,0x2c,0x38,0xa1,0x2f,0x23,0x89,0x28,0x34,0x8b,0x2c,0x38,0x8a,0x39,0x3b,0x2f,0x8b,0x3f,0x39,0x36,0x94,0x33,0x39,0x3d,0x8a,0x17,0x23,0x8b,0x3b,0x33,0x39,0x89,0x33,0x2f,0x2d,0x95,0x34,0x2c,0x2f,0x95,0x1c,0x10,0x95,0x12,0x1e,0x95,0x2f,0x14,0x20,0x8b,0x30,0x89,0x31,0x21,0x15,0x8b,0x39,0x8a,0x28,0x2d,0x25,0x8b,0x36,0x8a,0x30,0x1e,0x2a,0x8b,0x39,0x89,0x1f,0x2b,0x8b,0x36,0x8a,0x2f,0x2c,0x20,0x8b,0x34,0x8a,0x38,0x23,0x28,0x8b,0x3d,0x89,0x1c,0x28,0x8b,0x3b,0x8a,0x38,0x23,0x28,0x8b,0x34,0x8a,0x33,0x17,0x23,0x8b,0x3b,0x89,0x36,0x2d,0x23,0x8b,0x33,0x8a,0x31,0x1e,0x2a,0x8b,0x33,0x89,0x1f,0x2b,0x8c,0x2f,0x89,0x34,0x20,0x2c,0x8b,0x34,0x8a,0x38,0x28,0x1c,0x8b,0x3b,0x89,0x40,0x23,0x17,0x8b,0x3d,0x8a,0x3b,0x14,0x20,0x8b,0x38,0x8a,0x31,0x15,0x21,0x8b,0x39,0x89,0x28,0x25,0x2d,0x8b,0x36,0x8a,0x30,0x1e,0x2a,0x8b,0x39,0x8a,0x2b,0x1f,0x8b,0x36,0x89,0x2f,0x2c,0x20,0x8b,0x34,0x8a,0x38,0x28,0x2c,0x8b,0x3d,0x8a,0x28,0x1c,0x8b,0x3b,0x89,0x38,0x28,0x2c,0x8b,0x34,0x8a,0x36,0x19,0x25,0x8b,0x38,0x8a,0x36,0x28,0x2e,0x8b,0x34,0x89,0x33,0x12,0x1e,0x8b,0x34,0x8a,0x2a,0x2e,0x28,0x8b,0x31,0x89,0x2f,0x27,0x2a,0x81,0x23,0x94,0x32,0x38,0x1d,0x8b,0x33,0x36,0x1e,0x8a,0x33,0x3b,0x17,0x95,0x2f,0x32,0x20,0x94,0x31,0x15,0x21,0x8b,0x39,0x8a,0x2d,0x28,0x25,0x8b,0x36,0x8a,0x30,0x1e,0x2a,0x8b,0x39,0x8a,0x1f,0x2b,0x8b,0x36,0x89,0x20,0x2c,0x8b,0x2f,0x8a,0x34,0x23,0x2c,0x8b,0x38,0x8a,0x3d,0x28,0x1c,0x8b,0x3b,0x8a,0x38,0x2c,0x28,0x8b,0x34,0x89,0x33,0x17,0x23,0x8b,0x3b,0x8a,0x36,0x23,0x2d,0x8b,0x33,0x8a,0x31,0x1e,0x2a,0x8b,0x33,0x8a,0x2b,0x1f,0x8b,0x2f,0x89,0x2c,0x20,0x8b,0x34,0x8a,0x38,0x28,0x1c,0x8b,0x3b,0x8a,0x38,0x40,0x17,0x8b,0x3d,0x8a,0x32,0x3b,0x20,0x8b,0x38,0x89,0x31,0x15,0x21,0x8b,0x39,0x8a,0x25,0x19,0x8b,0x36,0x8a,0x30,0x2a,0x1e,0x8b,0x39,0x8a,0x21,0x2d,0x8b,0x36,0x89,0x2c,0x20,0x8b,0x2f,0x8a,0x34,0x28,0x1c,0x8b,0x38,0x89,0x3d,0x23,0x17,0x8b,0x3b,0x8a,0x38,0x28,0x1c,0x8b,0x2f,0x89,0x2e,0x19,0x25,0x8b,0x31,0x34,0x8a,0x12,0x1e,0x95,0x2d,0x0b,0x17,0x8b,0x33,0x36,0x95,0x34,0x2c,0x8a,0x1c,0x10,0x96,0x38,0x1c,0x28,0x8b,0x34,0x89,0x36,0x23,0x17,0x8b,0x38,0x8b,0x2f,0x14,0x20,0x8b,0x30,0x89,0x31,0x21,0x15,0x8b,0x39,0x8a,0x28,0x25,0x2d,0x8b,0x36,0x89,0x30,0x2a,0x1e,0x8b,0x39,0x8a,0x1f,0x2b,0x8b,0x36,0x8a,0x2f,0x2c,0x20,0x8b,0x34,0x89,0x38,0x23,0x28,0x8b,0x3d,0x8a,0x1c,0x28,0x8b,0x3b,0x8a,0x38,0x23,0x28,0x8b,0x34,0x89,0x33,0x17,0x23,0x8b,0x3b,0x8a,0x36,0x2d,0x27,0x8b,0x33,0x8a,0x31,0x2a,0x1e,0x8b,0x33,0x89,0x2b,0x1f,0x8b,0x2f,0x8a,0x34,0x20,0x2c,0x8b,0x34,0x8a,0x38,0x28,0x1c,0x8b,0x3b,0x8a,0x40,0x17,0x23,0x8b,0x3d,0x89,0x3b,0x20,0x14,0x8c,0x38,0x89,0x31,0x15,0x21,0x8b,0x39,0x8a,0x2d,0x25,0x28,0x8b,0x36,0x8a,0x30,0x1e,0x2a,0x8b,0x39,0x8a,0x2b,0x1f,0x8b,0x36,0x8a,0x2f,0x2c,0x20,0x8b,0x34,0x8a,0x38,0x23,0x28,0x8b,0x3d,0x8a,0x28,0x1c,0x8b,0x3b,0x89,0x38,0x23,0x28,0x8c,0x34,0x89,0x36,0x19,0x25,0x8b,0x38,0x8a,0x36,0x28,0x2e,0x8b,0x34,0x89,0x33,0x12,0x1e,0x8c,0x34,0x89,0x2e,0x28,0x2a,0x8c,0x31,0x89,0x2f,0x2a,0x27,0x81,0x23,0x94,0x32,0x38,0x1d,0x8c,0x33,0x36,0x1e,0x89,0x3b,0x33,0x17,0x95,0x2f,0x32,0x20,0x95,0x31,0x21,0x15,0x8b,0x39,0x8a,0x2d,0x28,0x25,0x8b,0x36,0x8a,0x30,0x2a,0x1e,0x8b,0x39,0x8a,0x1f,0x2b,0x8b,0x36,0x8a,0x2c,0x20,0x8b,0x2f,0x89,0x34,0x23,0x28,0x8c,0x38,0x89,0x3d,0x28,0x1c,0x8b,0x3b,0x8a,0x38,0x28,0x23,0x8b,0x34,0x8a,0x33,0x17,0x23,0x8b,0x3b,0x8a,0x36,0x2d,0x27,0x8b,0x33,0x8a,0x31,0x2a,0x1e,0x8b,0x33,0x8a,0x2b,0x1f,0x8b,0x2f,0x89,0x2c,0x20,0x8c,0x34,0x89,0x38,0x1c,0x28,0x8b,0x3b,0x8a,0x40,0x38,0x23,0x8b,0x3d,0x8a,0x32,0x3b,0x14,0x8b,0x38,0x8a,0x31,0x15,0x21,0x8b,0x39,0x8a,0x19,0x25,0x8b,0x36,0x8a,0x30,0x2a,0x1e,0x8b,0x39,0x8a,0x2d,0x21,0x8b,0x36,0x8a,0x2c,0x20,0x8b,0x2f,0x89,0x34,0x1c,0x28,0x8b,0x38,0x8a,0x3d,0x23,0x17,0x8b,0x3b,0x89,0x38,0x1c,0x28,0x8c,0x2f,0x89,0x2e,0x19,0x25,0x8b,0x31,0x34,0x8a,0x12,0x1e,0x95,0x2d,0x0b,0x17,0x8c,0x33,0x36,0x95,0x2c,0x34,0x8a,0x1c,0x10,0x95,0x17,0x96,0x10,0x8b,0x3b,0x2f,0x8a,0x31,0x3d,0x8b,0x3e,0x32,0x8a,0x3f,0x33,0x39,0x94,0x3b,0x2f,0x23,0x8b,0x39,0x3d,0x31,0x8a,0x23,0x17,0x95,0x2d,0x23,0x27,0x95,0x3f,0x39,0x33,0x94,0x3b,0x2f,0x2d,0x8b,0x3d,0x39,0x31,0x8a,0x12,0x1e,0x8b,0x3b,0x2f,0x17,0x8a,0x31,0x3d,0x22,0x8b,0x3f,0x33,0x15,0x8a,0x38,0x40,0x34,0x95,0x38,0x3b,0x2f,0x8b,0x31,0x38,0x3d,0x89,0x1c,0x28,0x95,0x28,0x2c,0x23,0x95,0x34,0x40,0x38,0x95,0x38,0x2f,0x3b,0x8b,0x31,0x3d,0x38,0x89,0x28,0x1c,0x95,0x29,0x1d,0x95,0x1e,0x2a,0x95,0x3d,0x27,0x23,0x8b,0x39,0x3b,0x33,0x89,0x23,0x17,0x95,0x2d,0x27,0x23,0x95,0x2a,0x1e,0x95,0x3d,0x23,0x27,0x8b,0x33,0x3b,0x39,0x89,0x23,0x17,0x95,0x27,0x23,0x2d,0x95,0x1c,0x28,0x95,0x3d,0x28,0x2c,0x8b,0x34,0x3b,0x38,0x89,0x23,0x17,0x95,0x28,0x23,0x2c,0x95,0x1c,0x28,0x95,0x3d,0x28,0x23,0x8b,0x38,0x34,0x3b,0x8a,0x20,0x2c,0x8b,0x2f,0x3b,0x89,0x3d,0x31,0x1f,0x8b,0x32,0x3e,0x8a,0x3f,0x39,0x33,0x95,0x3b,0x2f,0x27,0x8b,0x39,0x31,0x3d,0x8a,0x23,0x17,0x94,0x27,0x2d,0x23,0x95,0x33,0x39,0x3f,0x95,0x3b,0x2f,0x27,0x8b,0x3d,0x31,0x39,0x8a,0x12,0x1e,0x8b,0x3b,0x2f,0x23,0x89,0x3d,0x31,0x22,0x8b,0x33,0x3f,0x15,0x8a,0x34,0x40,0x38,0x95,0x3b,0x38,0x2f,0x8b,0x3d,0x31,0x38,0x8a,0x1c,0x28,0x95,0x28,0x23,0x2c,0x95,0x20,0x2c,0x8c,0x34,0x8a,0x38,0x28,0x1c,0x8b,0x3b,0x8a,0x40,0x38,0x23,0x8b,0x3d,0x8a,0x32,0x3b,0x20,0x8b,0x38,0x8a,0x31,0x15,0x21,0x8b,0x39,0x8a,0x19,0x25,0x8b,0x36,0x8a,0x30,0x1e,0x2a,0x8b,0x39,0x8a,0x2d,0x21,0x8b,0x36,0x8a,0x2c,0x20,0x8b,0x2f,0x8a,0x34,0x28,0x1c,0x8b,0x38,0x89,0x3d,0x17,0x23,0x8b,0x3b,0x8a,0x38,0x1c,0x28,0x8b,0x2f,0x8a,0x2e,0x19,0x25,0x8b,0x34,0x31,0x89,0x1e,0x12,0x95,0x2d,0x17,0x0b,0x8b,0x36,0x33,0x95,0x2c,0x34,0x8a,0x10,0x1c,0x95,0x17,0x23,0x96,0x20,0x2c,0x8b,0x2f,0x3b,0x89,0x31,0x3d,0x2b,0x8b,0x32,0x3e,0x89,0x39,0x3f,0x33,0x95,0x2f,0x3b,0x23,0x8b,0x39,0x31,0x3d,0x8a,0x23,0x17,0x95,0x2d,0x23,0x27,0x95,0x3f,0x39,0x33,0x95,0x2f,0x3b,0x23,0x8b,0x31,0x3d,0x39,0x89,0x1e,0x12,0x8c,0x2f,0x3b,0x23,0x89,0x31,0x3d,0x22,0x8b,0x3f,0x33,0x15,0x89,0x40,0x38,0x34,0x95,0x3b,0x2f,0x38,0x8b,0x3d,0x31,0x38,0x8a,0x1c,0x28,0x95,0x23,0x28,0x2c,0x95,0x38,0x34,0x40,0x95,0x3b,0x38,0x2f,0x8b,0x31,0x3d,0x38,0x89,0x1c,0x28,0x95,0x29,0x1d,0x95,0x2a,0x1e,0x95,0x3d,0x27,0x23,0x8b,0x39,0x3b,0x33,0x89,0x17,0x23,0x95,0x2d,0x27,0x23,0x95,0x1e,0x2a,0x95,0x3d,0x27,0x23,0x8b,0x33,0x39,0x3b,0x8a,0x23,0x17,0x94,0x2d,0x23,0x27,0x95,0x1c,0x28,0x95,0x3d,0x2c,0x28,0x8b,0x34,0x3b,0x38,0x89,0x17,0x23,0x95,0x2c,0x28,0x23,0x95,0x1c,0x28,0x94,0x3d,0x23,0x2c,0x8b,0x38,0x34,0x3b,0x8a,0x2c,0x20,0x8b,0x2f,0x3b,0x89,0x31,0x3d,0x1f,0x8b,0x32,0x3e,0x8a,0x3f,0x39,0x33,0x94,0x3b,0x2f,0x2d,0x8b,0x31,0x39,0x3d,0x8a,0x23,0x17,0x95,0x2d,0x27,0x23,0x95,0x39,0x3f,0x33,0x95,0x3b,0x2f,0x27,0x8b,0x31,0x39,0x3d,0x89,0x12,0x1e,0x8b,0x3b,0x2f,0x17,0x8a,0x31,0x3d,0x22,0x8b,0x33,0x3f,0x15,0x89,0x34,0x40,0x38,0x95,0x3b,0x38,0x2f,0x8b,0x3d,0x31,0x38,0x8a,0x28,0x1c,0x95,0x28,0x23,0x2c,0x95,0x20,0x2c,0x8b,0x34,0x89,0x38,0x1c,0x28,0x8b,0x3b,0x8a,0x38,0x40,0x23,0x8b,0x3d,0x8a,0x3b,0x32,0x20,0x8b,0x38,0x89,0x31,0x15,0x21,0x8b,0x39,0x8a,0x19,0x25,0x8b,0x36,0x8a,0x30,0x1e,0x2a,0x8b,0x39,0x89,0x2d,0x21,0x8b,0x36,0x8a,0x20,0x2c,0x8b,0x2f,0x8a,0x34,0x28,0x1c,0x8a,0x38,0x8a,0x3d,0x23,0x17,0x8b,0x3b,0x8a,0x38,0x28,0x1c,0x8b,0x2f,0x89,0x2e,0x25,0x19,0x8c,0x31,0x34,0x89,0x1e,0x12,0x95,0x2d,0x17,0x0b,0x8c,0x33,0x36,0x95,0x34,0x2c,0x8a,0x1c,0x10,0x95,0x17,0x96,0x40,0x34,0x3b,0xff +}; diff --git a/presets/gb/scroll.c b/presets/gb/scroll.c new file mode 100644 index 00000000..f022123b --- /dev/null +++ b/presets/gb/scroll.c @@ -0,0 +1,58 @@ +/* +Scrolling demo for Game Boy. +The background tile map is 32x32 tiles (256x256 pixels) and +wraps around, so the scroll registers can move anywhere in it. +We put text at the top, middle and bottom rows and scroll the +view up and down through the whole map. + +Ported from presets/nes/scroll.c, using GBDK (gb/gb.h). +*/ + +//#link "gb/sfr.sgb" +//#link "gb/crt0.sgb" +//#resource "gb/global.sgb" + +#include +#include "gb/types.h" +#include "gb/hardware.h" +#include "gb/gb.h" +#include "gbtext.h" + +// scroll the window up and down until the end +void scroll_demo(void) { + int y = 0; // y scroll position + int dy = 1; // y scroll direction + // infinite loop + while (1) { + // wait for next frame + wait_vbl_done(); + // update y variable + y += dy; + // change direction when hitting either edge of scroll area + if (y >= 255) dy = -1; + if (y == 0) dy = 1; + // set the Y scroll register + SCY_REG = y; + } +} + +// main function, run after console reset +void main(void) { + DISPLAY_OFF; + // background palette: color 0 = white, 1 = light, 2 = dark, 3 = black + BGP_REG = 0xE4; + + font_init(); + + // write text to the tile map + put_str(2, 0, "Tile map row 0"); + put_str(2, 15, "Tile map row 15"); + put_str(2, 29, "Tile map row 29"); + + // enable rendering + SHOW_BKG; + DISPLAY_ON; + + // scroll the view back and forth + scroll_demo(); +} diff --git a/presets/gb/siegegame.c b/presets/gb/siegegame.c new file mode 100644 index 00000000..db0abfa8 --- /dev/null +++ b/presets/gb/siegegame.c @@ -0,0 +1,357 @@ +/* +Siege for Game Boy — port of presets/nes/siegegame.c. + +A character-based surround-the-opponent game. Two players (one +human, one AI) leave trails that box each other in; the first +one to hit a wall, a trail, or the other player loses the round. + +Porting notes: +- The NES version reads the nametable back from the PPU to + detect collisions and steer the AI (see getchar()). On the + Game Boy VRAM can only be accessed during VBlank, so we keep + a shadow copy of the playfield in RAM instead. +- Text uses the gbtext.h font (tile index == ASCII code), so + strings can be written straight to the tile map. +- The NES draws player tails as colored tiles; here we use two + custom dither tiles (light for player 1, dark for player 2) + appended after the font tiles. +- Flashing colliding players reuses the NES trick of XORing the + head tile index with 0x80: tiles 0x80 and up are blank, so + the head alternates between visible and hidden. +- Playfield is cropped to 20x17 tiles to fit the GB screen. + +Controls: D-pad moves player 1, Start starts the game. +*/ + +//#link "gb/sfr.sgb" +//#link "gb/crt0.sgb" +//#resource "gb/global.sgb" +#include +#include +#include +#include "gb/types.h" +#include "gb/hardware.h" +#include "gb/gb.h" +#include "gbtext.h" + +typedef uint8_t byte; +typedef uint16_t word; + +// screen is 20x18 tiles; leave the bottom row blank +#define COLS 20 +#define ROWS 17 + +////////// GAME DATA + +typedef struct { + byte x; + byte y; + byte dir; + word score; + char head_attr; + char tail_attr; + int collided:1; + int human:1; +} Player; + +Player players[2]; + +byte attract; +byte gameover; +byte frames_per_move; + +// shadow copy of the tile map, for collision checks and AI +// (GB VRAM can only be read during VBlank, so mirror in RAM) +byte playfield[COLS*ROWS]; + +#define START_SPEED 12 +#define MAX_SPEED 5 +#define MAX_SCORE 7 + +// two custom tail tiles appended after the font tiles +// (the NES version uses two colored tiles for the tails) +#define TAIL_TILE_P1 (FONT_TILE_BASE + FONT_NUM_TILES) // 0x7b +#define TAIL_TILE_P2 (FONT_TILE_BASE + FONT_NUM_TILES + 1) // 0x7c + +// three custom tiles for the border +#define BORDER_LR (FONT_TILE_BASE + FONT_NUM_TILES + 2) // 0x7d +#define BORDER_UD (FONT_TILE_BASE + FONT_NUM_TILES + 3) // 0x7e +#define BORDER_CORNER (FONT_TILE_BASE + FONT_NUM_TILES + 4) // 0x7f + +// blank tile used to clear tiles 0x80-0xff (see init) +const uint8_t zero_tile[16] = {0}; + +// tail tiles: dark checkerboard (player 1), light (player 2) +const uint8_t tail_tiles[5*16] = { +/*;;{w:8,h:8,bpp:1,count:5,brev:1,np:2,pofs:1,sl:2};;*/ + 0x55,0x55,0xAA,0xAA, 0x55,0x55,0xAA,0xAA, + 0x55,0x55,0xAA,0xAA, 0x55,0x55,0xAA,0xAA, + 0x55,0x00,0xAA,0x00, 0x55,0x00,0xAA,0x00, + 0x55,0x00,0xAA,0x00, 0x55,0x00,0xAA,0x00, + 0x00,0x00,0x00,0xFF, 0x55,0x00,0xAA,0x00, + 0x55,0x00,0xAA,0x00, 0x00,0xFF,0x00,0x00, + 0x14,0x42,0x28,0x42, 0x14,0x42,0x28,0x42, + 0x14,0x42,0x28,0x42, 0x14,0x42,0x28,0x42, + 0x00,0xFF,0x2A,0x81, 0x54,0x81,0x2A,0x81, + 0x54,0x81,0x2A,0x81, 0x54,0x81,0x00,0xFF, +/*;;*/ +}; + +////////// TEXT ROUTINES + +// read a playfield character: from the shadow buffer, +// no VBlank tricks needed (unlike the NES nametable read) +byte getchar(byte x, byte y) { + return playfield[y*COLS+x]; +} + +void cputcxy(byte x, byte y, char ch) { + put_char(x, y, ch); + // keep shadow buffer in sync with the screen + playfield[y*COLS+x] = ch; +} + +void cputsxy(byte x, byte y, const char* str) { + byte i; + for (i=0; str[i]; i++) + cputcxy(x+i, y, str[i]); +} + +void clrscr() { + byte x, y; + memset(playfield, 0, sizeof(playfield)); + // fill the visible tile map with spaces + for (y=0; yx, p->y, p->head_attr); +} + +void move_player(Player* p) { + cputcxy(p->x, p->y, p->tail_attr); + p->x += DIR_X[p->dir]; + p->y += DIR_Y[p->dir]; + if (getchar(p->x, p->y) != 0) + p->collided = 1; + draw_player(p); +} + +void human_control(Player* p) { + byte dir = 0xff; + byte joy = joypad(); + // start game if attract mode + if (attract && (joy & J_START)) + gameover = 1; + // do not allow movement unless human player + if (!p->human) return; + if (joy & J_LEFT) dir = D_LEFT; + if (joy & J_RIGHT) dir = D_RIGHT; + if (joy & J_UP) dir = D_UP; + if (joy & J_DOWN) dir = D_DOWN; + // don't let the player reverse + if (dir < 0x80 && dir != (p->dir ^ 2)) { + p->dir = dir; + } +} + +byte ai_try_dir(Player* p, dir_t dir, byte shift) { + byte x,y; + dir &= 3; + x = p->x + (DIR_X[dir] << shift); + y = p->y + (DIR_Y[dir] << shift); + if (x < COLS && y < ROWS && getchar(x, y) == 0) { + p->dir = dir; + return 1; + } else { + return 0; + } +} + +void ai_control(Player* p) { + dir_t dir; + if (p->human) return; + dir = p->dir; + if (!ai_try_dir(p, dir, 0)) { + ai_try_dir(p, dir+1, 0); + ai_try_dir(p, dir-1, 0); + } else { + ai_try_dir(p, dir-1, 0) && ai_try_dir(p, dir-1, 1+(rand() & 3)); + ai_try_dir(p, dir+1, 0) && ai_try_dir(p, dir+1, 1+(rand() & 3)); + ai_try_dir(p, dir, rand() & 3); + } +} + +void flash_colliders() { + byte i; + // flash players that collided by toggling the head tile + // between the glyph and the blank tile 0x80 up + for (i=0; i<56; i++) { + wait_vbl_done(); // head draws happen right after VBlank + if (players[0].collided) players[0].head_attr ^= 0x80; + if (players[1].collided) players[1].head_attr ^= 0x80; + draw_player(&players[0]); + draw_player(&players[1]); + wait_vbl_done(); // two frames per flash, like the NES version + } + // even number of flashes leaves head_attr restored +} + +void make_move() { + byte i; + for (i=0; i start + if (players[0].collided || players[1].collided) break; + } + flash_colliders(); + // add scores to players that didn't collide + if (players[0].collided) players[1].score++; + if (players[1].collided) players[0].score++; + // increase speed + if (frames_per_move > MAX_SPEED) frames_per_move--; + // game over? + if (players[0].score != players[1].score) { + if (players[0].score >= MAX_SCORE) + declare_winner(0); + else if (players[1].score >= MAX_SCORE) + declare_winner(1); + } +} + +void play_game() { + gameover = 0; + init_game(); + if (!attract) + players[0].human = 1; + while (!gameover) { + play_round(); + } +} + +void main() { + byte i, x, y; + DISPLAY_OFF; + // unsigned tile indexing so ASCII codes work; must be set before + // set_bkg_data(), which uses it to pick the VRAM tile base + LCDC_REG |= LCDCF_BG8000; + // load font (tiles 0x20-0x7a, tile index == ASCII) + tail tiles + font_init(); + set_bkg_data(TAIL_TILE_P1, sizeof(tail_tiles)/16, tail_tiles); + // clear tiles 0x80-0xff so head_attr^0x80 flashing shows blank + for (i=0x80; i!=0; i++) + set_bkg_data(i, 1, zero_tile); + // 4-shade palette + BGP_REG = 0xE4; + // fill the tile map with spaces + for (y=0; y +#include +#include "gb/types.h" +#include "gb/hardware.h" +#include "gb/gb.h" +#include "gbtext.h" + +// number of actors +#define NUM_ACTORS 40 // 40 sprites (Game Boy maximum) + +// actor x/y positions +uint8_t actor_x[NUM_ACTORS]; // horizontal coordinates +uint8_t actor_y[NUM_ACTORS]; // vertical coordinates + +// actor x/y deltas per frame (signed) +int8_t actor_dx[NUM_ACTORS]; // horizontal velocity +int8_t actor_dy[NUM_ACTORS]; // vertical velocity + +// setup LCD and tile data +void setup_graphics(void) { + DISPLAY_OFF; + // 4-shade palettes (index 0 is transparent for objects) + BGP_REG = OBP0_REG = OBP1_REG = 0xE4; + // use 0x8000 for BG tile data so background and objects + // share the same font tiles + LCDC_REG |= LCDCF_BG8000; + // load the font tiles at 0x8000 (shared by BG and objects) + font_init(); + SHOW_BKG; + SHOW_SPRITES; + DISPLAY_ON; +} + +// main program +void main(void) { + uint8_t i; // actor index + + // initialize actors with random values + for (i=0; i> 4 when the sprite +is moved. Arrow keys apply thrust; holding A gives a jump burst. +*/ + //#link "gb/sfr.sgb" //#link "gb/crt0.sgb" //#resource "gb/global.sgb" @@ -12,6 +20,7 @@ // Postion values are calculated as 16 bit numbers and their // lower 4 bits are dropped when applying them to the sprite +// 4 frames of a ball sprite (8x8, 1bpp) UINT8 sprite_data[] = { /*;;{w:8,h:8,bpp:1,count:4,brev:1,np:2,pofs:1,sl:2};;*/ 0x3C,0x3C,0x42,0x7E,0x99,0xFF,0xA9,0xFF,0x89,0xFF,0x89,0xFF,0x42,0x7E,0x3C,0x3C, @@ -23,12 +32,12 @@ UINT8 sprite_data[] = { joypads_t joypads; -// sprite coords -UINT16 PosX, PosY; -INT16 SpdX, SpdY; -UINT8 Jump; +// fixed-point sprite coords (fraction in lower 4 bits) +UINT16 PosX, PosY; // position +INT16 SpdX, SpdY; // velocity +UINT8 Jump; // frames of jump thrust remaining -// main funxction +// main function void main(void) { // init palettes BGP_REG = OBP0_REG = OBP1_REG = 0xE4; @@ -45,14 +54,16 @@ void main(void) { // init 2 joypads joypad_init(1, &joypads); + // start at screen center with zero velocity PosX = PosY = 64 << 4; Jump = SpdX = SpdY = 0; + // loop forever while(1) { // poll joypads joypad_ex(&joypads); - // game object + // game object: arrow keys apply thrust, clamped to a max speed if (joypads.joy0 & J_UP) { SpdY -= 2; if (SpdY < -64) SpdY = -64; @@ -67,24 +78,26 @@ void main(void) { SpdX += 2; if (SpdX > 64) SpdX = 64; } + // A button triggers a 3-frame jump (only when grounded) if ((joypads.joy0 & J_A) && (!Jump)) { Jump = 3; } - // jump + // jump: apply upward impulse while Jump counts down if (Jump) { SpdY -= 8; if (SpdY < -32) SpdY = -32; Jump--; } + // apply velocity to position PosX += SpdX, PosY += SpdY; // Translate to pixels and move sprite // Downshift by 4 bits to use the whole number values move_sprite(0, PosX >> 4, PosY >> 4); - // decelerate + // friction: velocities decay toward zero each frame if (SpdY >= 0) { if (SpdY) SpdY--; } else SpdY ++; diff --git a/presets/gb/tiles.c b/presets/gb/tiles.c new file mode 100644 index 00000000..7fa9e8bd --- /dev/null +++ b/presets/gb/tiles.c @@ -0,0 +1,78 @@ + +//#link "gb/sfr.sgb" +//#link "gb/crt0.sgb" +//#resource "gb/global.sgb" +#include +#include +#include "gb/types.h" +#include "gb/hardware.h" +#include "gb/gb.h" + +#define NUM_TILES 46 + +static const uint8_t font[NUM_TILES*16] = { +/*;;{w:8,h:8,bpp:1,count:46,brev:1,np:2,pofs:1,sl:2};;*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x81,0x81,0x42,0x42,0x24,0x24,0x18,0x18,0x18,0x18,0x24,0x24,0x42,0x42,0x81,0x81 +,0x00,0x00,0x24,0x24,0x00,0x00,0x00,0x00,0x24,0x24,0x18,0x18,0x00,0x00,0x00,0x00 +,0x00,0x00,0x24,0x24,0x00,0x00,0x00,0x00,0x18,0x18,0x24,0x24,0x00,0x00,0x00,0x00 +,0x00,0x00,0x36,0x36,0x49,0x49,0x41,0x41,0x22,0x22,0x14,0x14,0x08,0x08,0x00,0x00 +,0x00,0x00,0x00,0x00,0x08,0x08,0x04,0x04,0x7E,0x7E,0x04,0x04,0x08,0x08,0x00,0x00 +,0x00,0x00,0x00,0x00,0x10,0x10,0x20,0x20,0x7E,0x7E,0x20,0x20,0x10,0x10,0x00,0x00 +,0x00,0x00,0x10,0x10,0x38,0x38,0x54,0x54,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00 +,0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x54,0x54,0x38,0x38,0x10,0x10,0x00,0x00 +,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x7C,0x7C,0x10,0x10,0x10,0x10,0x00,0x00 +,0x00,0x00,0x1C,0x1C,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x1C,0x1C,0x00,0x00 +,0x00,0x00,0x06,0x06,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x00,0x00 +,0x00,0x00,0x1C,0x1C,0x02,0x02,0x04,0x04,0x08,0x08,0x10,0x10,0x1E,0x1E,0x00,0x00 +,0x00,0x00,0x1C,0x1C,0x02,0x02,0x0C,0x0C,0x02,0x02,0x02,0x02,0x1C,0x1C,0x00,0x00 +,0x00,0x00,0x12,0x12,0x12,0x12,0x1E,0x1E,0x02,0x02,0x02,0x02,0x02,0x02,0x00,0x00 +,0x00,0x00,0x1E,0x1E,0x10,0x10,0x1E,0x1E,0x02,0x02,0x02,0x02,0x1E,0x1E,0x00,0x00 +,0x00,0x00,0x0C,0x0C,0x10,0x10,0x1C,0x1C,0x12,0x12,0x12,0x12,0x0C,0x0C,0x00,0x00 +,0x00,0x00,0x1C,0x1C,0x04,0x04,0x0E,0x0E,0x04,0x04,0x04,0x04,0x04,0x04,0x00,0x00 +,0x00,0x00,0x1C,0x1C,0x22,0x22,0x1C,0x1C,0x22,0x22,0x22,0x22,0x1C,0x1C,0x00,0x00 +,0x00,0x00,0x1E,0x1E,0x12,0x12,0x1E,0x1E,0x02,0x02,0x02,0x02,0x02,0x02,0x00,0x00 +,0x00,0x00,0x18,0x18,0x24,0x24,0x3C,0x3C,0x24,0x24,0x24,0x24,0x24,0x24,0x00,0x00 +,0x00,0x00,0x38,0x38,0x24,0x24,0x38,0x38,0x24,0x24,0x24,0x24,0x38,0x38,0x00,0x00 +,0x00,0x00,0x1C,0x1C,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x1C,0x1C,0x00,0x00 +,0x00,0x00,0x38,0x38,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x38,0x38,0x00,0x00 +,0x00,0x00,0x3C,0x3C,0x20,0x20,0x38,0x38,0x20,0x20,0x20,0x20,0x3C,0x3C,0x00,0x00 +,0x00,0x00,0x3C,0x3C,0x20,0x20,0x38,0x38,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00 +,0x00,0x00,0x18,0x18,0x20,0x20,0x2C,0x2C,0x24,0x24,0x24,0x24,0x18,0x18,0x00,0x00 +,0x00,0x00,0x24,0x24,0x24,0x24,0x3C,0x3C,0x24,0x24,0x24,0x24,0x24,0x24,0x00,0x00 +,0x00,0x00,0x38,0x38,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x38,0x00,0x00 +,0x00,0x00,0x3C,0x3C,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x38,0x38,0x00,0x00 +,0x00,0x00,0x24,0x24,0x28,0x28,0x30,0x30,0x28,0x28,0x24,0x24,0x24,0x24,0x00,0x00 +,0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x38,0x38,0x00,0x00 +,0x00,0x00,0x22,0x22,0x36,0x36,0x2A,0x2A,0x22,0x22,0x22,0x22,0x22,0x22,0x00,0x00 +,0x00,0x00,0x24,0x24,0x34,0x34,0x2C,0x2C,0x24,0x24,0x24,0x24,0x24,0x24,0x00,0x00 +,0x00,0x00,0x18,0x18,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x18,0x18,0x00,0x00 +,0x00,0x00,0x38,0x38,0x24,0x24,0x38,0x38,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00 +,0x00,0x00,0x18,0x18,0x24,0x24,0x24,0x24,0x24,0x24,0x2C,0x2C,0x1C,0x1C,0x02,0x02 +,0x00,0x00,0x38,0x38,0x24,0x24,0x38,0x38,0x24,0x24,0x24,0x24,0x24,0x24,0x00,0x00 +,0x00,0x00,0x1C,0x1C,0x20,0x20,0x18,0x18,0x04,0x04,0x04,0x04,0x38,0x38,0x00,0x00 +,0x00,0x00,0x3E,0x3E,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x00 +,0x00,0x00,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x18,0x18,0x00,0x00 +,0x00,0x00,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x14,0x14,0x08,0x08,0x00,0x00 +,0x00,0x00,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x2A,0x2A,0x14,0x14,0x00,0x00 +,0x00,0x00,0x22,0x22,0x14,0x14,0x08,0x08,0x08,0x08,0x14,0x14,0x22,0x22,0x00,0x00 +,0x00,0x00,0x22,0x22,0x14,0x14,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x00 +,0x00,0x00,0x3C,0x3C,0x04,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x3C,0x3C,0x00,0x00 +/*;;*/ +}; + +void main(void) +{ + DISPLAY_OFF; + memcpy(_VRAM8000, font, sizeof(font)); // copy tile data + memcpy(_SCRN0, font, 32*32); // copy garbage data to screen + BGP_REG = 0xe4; // palette + LCDC_REG = LCDCF_ON|LCDCF_BG8000|LCDCF_BG9800|LCDCF_BGON|LCDCF_OBJ16|LCDCF_OBJON|LCDCF_WIN9C00|LCDCF_WINOFF; + DISPLAY_ON; + // Loop forever + while(1) { + // Game main loop processing goes here + // Done processing, yield CPU and wait for start of next frame + wait_vbl_done(); + } +} diff --git a/src/platform/gb.ts b/src/platform/gb.ts index e7c12815..6d8efbfb 100644 --- a/src/platform/gb.ts +++ b/src/platform/gb.ts @@ -4,12 +4,17 @@ import { PLATFORMS } from "../common/emu"; import { disassembleSM83 } from "../common/cpu/disasmSM83"; const GB_PRESETS: Preset[] = [ - { id: 'hello.c', name: 'Hello World (C)' }, - { id: 'testdrawing.c', name: 'Drawing Routines (C)' }, - { id: 'testphys.c', name: 'Sprite Test (C)' }, + { id: 'hello.c', name: 'Hello World', category: 'C' }, + { id: 'testdrawing.c', name: 'Drawing Routines' }, + { id: 'testphys.c', name: 'Joypad Sprite' }, + { id: 'sprites.c', name: 'Multiple Sprites' }, + { id: 'metasprites.c', name: 'Metasprites' }, + { id: 'scroll.c', name: 'Scrolling' }, + { id: 'music.c', name: 'Music Player' }, + { id: 'siegegame.c', name: 'Siege Game' }, { id: 'chase.c', name: "Shiru's Chase Game" }, { id: 'pakupaku.c', name: 'Paku Paku' }, - { id: 'hello.sgb', name: 'Hello World (ASM)' }, + { id: 'hello.sgb', name: 'Hello World (ASM)', category: 'assembler' }, { id: 'main.wiz', name: 'Snake Game (Wiz)' }, ];