#define word char #include "LIB/MATH.C" #include "LIB/STDLIB.C" #include "LIB/SYS.C" #include "LIB/GFX.C" #define SCREEN_WIDTH 40 #define SCREEN_HEIGHT 25 #define MAX_RAIN_LENGTH 15 #define MIN_RAIN_LENGTH 5 #define RAIN_DELAY_MS 32 // ~30fps #define VRAM_PALETTE_TABLE_ADDR 0xC00400 #define VRAM_WINDOW_TILE_ADDR 0xC01420 #define MEMSTATUS_ADDR 0x440000 // Window tile vram. vidMem[Y][X] (bottom right is [24][39]) char (*vidMem)[SCREEN_WIDTH] = (char (*)[SCREEN_WIDTH]) VRAM_WINDOW_TILE_ADDR; // Hidden vram layer for pixel status char (*memStatus)[SCREEN_WIDTH] = (char (*)[SCREEN_WIDTH]) MEMSTATUS_ADDR; // Chars: 33 to 126 unsigned word rngLfsr = 0xACE1; word rngBit = 0; word rngRand() { rngBit = ((rngLfsr >> 0) ^ (rngLfsr >> 2) ^ (rngLfsr >> 3) ^ (rngLfsr >> 5) ) & 1; rngLfsr = (rngLfsr >> 1) | (rngBit << 15); return rngLfsr; } void initGraphics() { GFX_clearWindowtileTable(); // set default green palette word* palette = (word*) VRAM_PALETTE_TABLE_ADDR; palette[0] = 28; // green -> 0b00011100 word x, y; for (x = 0; x < SCREEN_WIDTH; x++) { for (y = 0; y < SCREEN_HEIGHT; y++) { vidMem[y][x] = 0; memStatus[y][x] = 0; } } } // Return a random character to print char getRandomChar() { rngRand(); rngRand(); return MATH_modU(rngRand(), 93) + 33; } // Update all rain on screen void updateRain() { word x, y; // do last line for (x = 0; x < SCREEN_WIDTH; x++) { if (memStatus[SCREEN_HEIGHT-1][x] > 0) { memStatus[SCREEN_HEIGHT-1][x]--; if (memStatus[SCREEN_HEIGHT-1][x] == 0) { vidMem[SCREEN_HEIGHT-1][x] = 0; // clear the character on screen } } } // skip last line for (y = SCREEN_HEIGHT-2; y >= 0; y--) { for (x = 0; x < SCREEN_WIDTH; x++) { if (memStatus[y][x] > 0) { // create new char if at bottom of rain if (memStatus[y+1][x] == 0) { vidMem[y+1][x] = getRandomChar(); } memStatus[y+1][x] = memStatus[y][x]; // propagate downwards memStatus[y][x]--; // decrease so it eventually ends if (memStatus[y][x] == 0) { vidMem[y][x] = 0; // clear the character on screen } } } } } // Generate a falling line at position x void genRainLine(word x) { // return if x is not free if (memStatus[0][x] != 0 || memStatus[1][x] != 0) { return; } word rainLen = MATH_modU(rngRand(), (MAX_RAIN_LENGTH + 1) - MIN_RAIN_LENGTH) + MIN_RAIN_LENGTH; memStatus[0][x] = rainLen; vidMem[0][x] = getRandomChar(); } int main() { initGraphics(); while (1) { if (HID_FifoAvailable()) { word c = HID_FifoRead(); if (c == 27) // escape { GFX_clearWindowtileTable(); return 'q'; } } updateRain(); rngRand(); rngRand(); rngRand(); genRainLine(MATH_modU(rngRand(), SCREEN_WIDTH)); rngRand(); rngRand(); rngRand(); genRainLine(MATH_modU(rngRand(), SCREEN_WIDTH)); delay(RAIN_DELAY_MS); } return 'q'; } void interrupt() { // handle all interrupts word i = getIntID(); switch(i) { case INTID_TIMER1: timer1Value = 1; // notify ending of timer1 break; case INTID_TIMER2: break; case INTID_UART0: break; case INTID_GPU: break; case INTID_TIMER3: break; case INTID_PS2: break; case INTID_UART1: break; case INTID_UART2: break; } }