From 3d2c9d044bf4bba9c2c944f021bb5088d2d16a39 Mon Sep 17 00:00:00 2001 From: Damian Yerrick Date: Mon, 18 Jun 2018 23:16:55 -0400 Subject: [PATCH] GBA: finish manual lag test By now, I have added all tests except these five: Shadow sprite, Stopwatch, Scroll test (Hill zone and Vertical), and the PCM feature of Sound test. If I fit them in 31K (6.2K each), I fit the whole suite in 64K. Otherwise I have to go compressing stuff. But it looks like I can release what I have so far to early access. --- gba/CHANGES.txt | 6 +- gba/src/global.h | 5 ++ gba/src/helppages.txt | 23 +++---- gba/src/megaton.c | 157 +++++++++++++++++++++++++++++++++++++++--- gba/src/rand.c | 15 ++++ 5 files changed, 181 insertions(+), 25 deletions(-) diff --git a/gba/CHANGES.txt b/gba/CHANGES.txt index 663d83b..baf7c2f 100644 --- a/gba/CHANGES.txt +++ b/gba/CHANGES.txt @@ -1,3 +1,3 @@ -0.01 (2018-06-xx) -* initial release, with everything but Shadow sprite, Stopwatch, - Manual lag, Hill zone scroll, Vertical scroll, and PCM audio test +0.01 (2018-06-19) +* initial release, with all tests except Shadow sprite, Stopwatch, + Hill zone scroll, Vertical scroll, and PCM in audio test diff --git a/gba/src/global.h b/gba/src/global.h index 13588d5..9c63bf8 100644 --- a/gba/src/global.h +++ b/gba/src/global.h @@ -89,6 +89,11 @@ void ppu_clear_oam(size_t start); void ppu_copy_oam(void); void dma_memset16(void *s, unsigned int c, size_t n); +// rand.c +void lcg_srand(unsigned int in_seed); +int lcg_rand(void); +#define LCG_RAND_MAX 65535 + // vwfdraw.c void loadMapRowMajor(unsigned short *dst, unsigned int tilenum, unsigned int width, unsigned int height); diff --git a/gba/src/helppages.txt b/gba/src/helppages.txt index 8c464ef..29475cc 100644 --- a/gba/src/helppages.txt +++ b/gba/src/helppages.txt @@ -15,7 +15,7 @@ Overscan ---- (NYA) Shadow sprite (NYA) Stopwatch -(WIP) Manual lag test +Manual lag test (NYA) Hill zone scroll (NYA) Vertical scroll Grid scroll @@ -587,13 +587,11 @@ Select: Show or hide == 160p Test Suite == -Ver. 0.00 +Version 0.01 (2018-06-19) We're just getting started -© 2011-2016 - Artemio Urbina -© 2015-2018 - Damian Yerrick +© 2011-2016 Artemio Urbina +© 2015-2018 Damian Yerrick This is free software; see the source for copying conditions. The program @@ -627,16 +625,15 @@ You can help: Roadmap 0.02: Stopwatch -0.03: Manual lag test -0.04: Scroll test -0.05: Shadow sprite -0.06: PCM in Sound test -0.07: Compress under 64 KiB +0.03: Scroll test +0.04: Shadow sprite +0.05: PCM in Sound test +0.06: Compress under 64 KiB ---- Size watch -As of 0.01, all but 5 tests -fit in 32 KiB, but some of the +As of 0.01, all but 4 tests +fit in 33 KiB, but some of the remaining tests are the most asset-intensive. Should they bust my 64 KiB diff --git a/gba/src/megaton.c b/gba/src/megaton.c index 2aaa0ee..79bfd59 100644 --- a/gba/src/megaton.c +++ b/gba/src/megaton.c @@ -2,14 +2,21 @@ #include #include #include +#include "posprintf.h" extern const unsigned char helpsect_manual_lag_test[]; #define PFMAP 23 -#define NUM_PRESSES 10 +#define NUM_TRIALS 10 #define BLANK_TILE 0x0004 +#define ARROW_TILE 0x0005 +#define CHECKED_TILE 0x0027 +#define UNCHECKED_TILE 0x0026 +#define RETICLE_TILE 0x0028 +#define WORD_OFF 0x0044 +#define WORD_ON 0x0046 // The "On" and "Off" labels must come first because they cause -// text to be allocated with off at 0x0030 and on at 0x0032 +// text to be allocated with off and on at WORD_OFF and WORD_ON static const char megaton_labels[] = "\x83""\x88""off\n" "\x84""\x90""on\n" @@ -20,11 +27,39 @@ static const char megaton_labels[] = "\x44""\x88""Randomize\n" "\x44""\x90""Audio"; +static void megaton_draw_boolean(unsigned int y, unsigned int value) { + MAP[PFMAP][y][15] = value ? CHECKED_TILE : UNCHECKED_TILE; + unsigned int onoff = value ? WORD_ON : WORD_OFF; + MAP[PFMAP][y][16] = onoff; + MAP[PFMAP][y][17] = onoff + 1; +} + +static void megaton_draw_reticle(unsigned int x, unsigned int y) { + unsigned int i = oam_used; + y = OBJ_Y(y) | OBJ_16_COLOR | ATTR0_SQUARE; + x = OBJ_X(x) | ATTR1_SIZE_16; + + SOAM[i].attr0 = y; + SOAM[i].attr1 = x; + SOAM[i++].attr2 = RETICLE_TILE; + SOAM[i].attr0 = y; + SOAM[i].attr1 = x + 16 + OBJ_HFLIP; + SOAM[i++].attr2 = RETICLE_TILE; + y += 16; + SOAM[i].attr0 = y; + SOAM[i].attr1 = x + OBJ_VFLIP; + SOAM[i++].attr2 = RETICLE_TILE; + SOAM[i].attr0 = y; + SOAM[i].attr1 = x + 16 + OBJ_HFLIP + OBJ_VFLIP; + SOAM[i++].attr2 = RETICLE_TILE; + oam_used = i; +} + void activity_megaton() { - signed char lag[NUM_PRESSES] = {-1}; + signed char lag[NUM_TRIALS] = {-1}; unsigned int x = 129, xtarget = 160; unsigned int with_audio = 1, dir = 1, randomize = 1; - unsigned int progress = 0; + unsigned int progress = 0, y = 0; load_common_bg_tiles(); load_common_obj_tiles(); @@ -34,17 +69,84 @@ void activity_megaton() { REG_SOUNDCNT_L = 0xFF77; // PSG vol/pan REG_SOUND1CNT_L = 0x08; // no sweep dma_memset16(MAP[PFMAP], BLANK_TILE, 32*20*2); - vwfDrawLabels(megaton_labels, PFMAP, 0x30); + vwfDrawLabels(megaton_labels, PFMAP, 0x44); + + // Draw stationary reticle + for (unsigned int y = 0; y < 2; ++y) { + for (unsigned int x = 0; x < 2; ++x) { + unsigned int t = 0x0028 + y * 2 + x; + MAP[PFMAP][7+y][13+x] = t; + MAP[PFMAP][7+y][16-x] = t ^ 0x400; + MAP[PFMAP][10-y][13+x] = t ^ 0x800; + MAP[PFMAP][10-y][16-x] = t ^ 0xC00; + } + } + + // Make space for results + dma_memset16(PATRAM4(0, 0x30), 0x0000, 32 * 20); + loadMapRowMajor(&(MAP[PFMAP][2][2]), 0x30, 2, 10); do { read_pad_help_check(helpsect_manual_lag_test); - if (new_keys && KEY_B) { + if (new_keys & KEY_B) { break; } + if (new_keys & KEY_A) { + signed int diff = x - 128; + if (xtarget < 128) diff = -diff; + unsigned int early = diff < 0; + unsigned int value = early ? -diff : diff; + uint32_t *tileaddr = PATRAM4(0, 0x30 + progress * 2); + dma_memset16(tileaddr, 0x0000, 32 * 2); + if (early) { + vwf8PutTile(tileaddr, 'E', 0, 1); + } + unsigned int tens = value / 10; + if (tens) { + vwf8PutTile(tileaddr, tens + '0', 6, 1); + } + vwf8PutTile(tileaddr, (value - tens * 10) + '0', 11, 1); + if (!early && value <= 25) lag[progress++] = value; + } + REG_SOUND2CNT_L = ((new_keys & KEY_A) && with_audio) ? 0xA080 : 0x0000; + REG_SOUND2CNT_H = (2048 - 262) | 0x8000; + if ((new_keys & KEY_UP) && y > 0) { + --y; + } + if ((new_keys & KEY_DOWN) && y < 2) { + ++y; + } + if (new_keys & (KEY_LEFT | KEY_RIGHT)) { + switch (y) { + case 0: // change direction + dir += (new_keys & KEY_LEFT) ? 2 : 1; + if (dir > 3) dir -= 3; + break; + case 1: + randomize = !randomize; + break; + case 2: + with_audio = !with_audio; + break; + } + } + // Move reticle + x += (xtarget > x) ? 1 : -1; + if (x == xtarget) { + xtarget = 36 + 128; + if (randomize) xtarget += (lcg_rand() >> 12) - 8; + if (x > 128) xtarget = 256 - xtarget; + } + oam_used = 0; - // Draw sprites + if (dir & 0x01) { + megaton_draw_reticle(104 + x - 128, 56); + } + if (dir & 0x02) { + megaton_draw_reticle(104, 56 + x - 128); + } ppu_clear_oam(oam_used); VBlankIntrWait(); @@ -53,12 +155,49 @@ void activity_megaton() { BG_OFFSET[0].x = BG_OFFSET[0].y = 0; BG_COLORS[0] = (x == 128 && with_audio) ? RGB5(31, 31, 31) : RGB5(0, 0, 0); BG_COLORS[1] = OBJ_COLORS[1] = RGB5(31, 31, 31); + BG_COLORS[2] = RGB5(20, 25, 31); ppu_copy_oam(); - } while (!(new_keys & KEY_B)); + // Draw the cursor + for (unsigned int i = 0; i < 3; ++i) { + unsigned int tilenum = (i == y) ? ARROW_TILE : BLANK_TILE; + MAP[PFMAP][i + 16][7] = tilenum; + } + MAP[PFMAP][16][15] = (dir & 0x01) ? CHECKED_TILE : UNCHECKED_TILE; + MAP[PFMAP][16][19] = (dir & 0x02) ? CHECKED_TILE : UNCHECKED_TILE; + megaton_draw_boolean(17, randomize); + megaton_draw_boolean(18, with_audio); + + // TODO: beep + REG_SOUND1CNT_H = (x == 128 && with_audio) ? 0xA080 : 0x0000; + REG_SOUND1CNT_X = (2048 - 131) | 0x8000; + } while (!(new_keys & KEY_B) && (progress < NUM_TRIALS)); + BG_COLORS[0] = RGB5(0, 0, 0); REG_SOUNDCNT_X = 0; // reset audio + if (progress < 10) return; + + // Display average: First throw away all labels below Y=120 + dma_memset16(MAP[PFMAP][15], BLANK_TILE, 32*4*2); + + unsigned int sum = 0; + for (unsigned int i = 0; i < NUM_TRIALS; ++i) { + sum += lag[i]; + } + unsigned int whole_frames = sum / NUM_TRIALS; + posprintf(help_line_buffer, "\x40\x80""Average lag: %d.%d frames", + whole_frames, sum - whole_frames * NUM_TRIALS); + vwfDrawLabels(help_line_buffer, PFMAP, 0x44); + + // Ignore spurious presses + for (unsigned int i = 20; i > 0; --i) { + VBlankIntrWait(); + } - if (new_keys && KEY_B) return; + do { + VBlankIntrWait(); + read_pad(); + } while (!new_keys); + // TODO: Display average lag } diff --git a/gba/src/rand.c b/gba/src/rand.c index e69de29..a76670e 100644 --- a/gba/src/rand.c +++ b/gba/src/rand.c @@ -0,0 +1,15 @@ +#include "global.h" + +// This uses the same linear congruential generator as cc65's +// random function, but with different tempering. + +static unsigned int seed = 1; + +void lcg_srand(unsigned int in_seed) { + seed = in_seed; +} + +int lcg_rand(void) { + seed = (seed * 0x01010101) + 0x31415927; + return (seed ^ (seed >> 16)) & 0xFFFF; +}