diff --git a/include/rainbow.h b/include/rainbow.h new file mode 100644 index 0000000000..62d46b51d1 --- /dev/null +++ b/include/rainbow.h @@ -0,0 +1,42 @@ +#ifndef RAINBOW_H +#define RAINBOW_H + +#include "ultra64/ultratypes.h" +#include "libc/stdbool.h" +#include "libc/stddef.h" +#include "color.h" + +typedef enum ColorState { + STATE_RED_TO_YELLOW, + STATE_YELLOW_TO_GREEN, + STATE_GREEN_TO_LIGHTBLUE, + STATE_LIGHTBLUE_TO_BLUE, + STATE_BLUE_TO_PINK, + STATE_PINK_TO_RED, + STATE_MAX +} ColorState; + +typedef struct RainbowTarget { + u8 state; + Color_RGB8 color; +} RainbowTarget; + +typedef struct Rainbow { + Color_RGB8 color; + u8 state; + u8 speed; + u8 bAllowDebug; + u8 bPause; +} Rainbow; + +void Rainbow_Debug(Rainbow* this); +void Rainbow_InitColor(Rainbow* this); +void Rainbow_Init(Rainbow* this); +u8 Rainbow_CheckColor(Rainbow* this, Color_RGB8 rgb); +void Rainbow_UpdateColor(Rainbow* this); +void Rainbow_UpdateState(Rainbow* this, RainbowTarget target); +void Rainbow_Update(Rainbow* this); + +void osSyncPrintf(const char* fmt, ...); + +#endif diff --git a/include/variables.h b/include/variables.h index 6aa74e4c76..58adee89ae 100644 --- a/include/variables.h +++ b/include/variables.h @@ -245,4 +245,6 @@ extern u64 gGfxSPTaskStack[SP_DRAM_STACK_SIZE64]; // 0x400 bytes extern GfxPool gGfxPools[2]; // 0x24820 bytes extern u8 gAudioHeap[0x38000]; // 0x38000 bytes +extern Rainbow gRainbow; + #endif diff --git a/include/z64.h b/include/z64.h index 8da813d879..d76bf68a47 100644 --- a/include/z64.h +++ b/include/z64.h @@ -60,6 +60,7 @@ #include "jpeg.h" #include "prerender.h" #include "widescreen.h" +#include "rainbow.h" #define SCREEN_WIDTH 320 #define SCREEN_HEIGHT 240 diff --git a/spec b/spec index 9db4a1adf9..45c71751f0 100644 --- a/spec +++ b/spec @@ -623,6 +623,7 @@ beginseg #else include "$(BUILD_DIR)/data/rsp.rodata.o" #endif + include "$(BUILD_DIR)/src/code/rainbow.o" endseg beginseg diff --git a/src/code/game.c b/src/code/game.c index e2862f8979..f5dabd1ec8 100644 --- a/src/code/game.c +++ b/src/code/game.c @@ -271,6 +271,7 @@ void GameState_Update(GameState* gameState) { gameState->main(gameState); + Rainbow_Update(&gRainbow); func_800C4344(gameState); #if IS_DEBUG diff --git a/src/code/main.c b/src/code/main.c index 761e1e6a00..b04b2379bf 100644 --- a/src/code/main.c +++ b/src/code/main.c @@ -27,6 +27,8 @@ AudioMgr gAudioMgr; OSMesgQueue sSerialEventQueue; OSMesg sSerialMsgBuf[1]; +Rainbow gRainbow; + #if IS_DEBUG void Main_LogSystemHeap(void) { PRINTF(VT_FGCOL(GREEN)); @@ -74,6 +76,7 @@ void Main(void* arg) { DebugArena_Init(debugHeapStart, debugHeapSize); } + Rainbow_Init(&gRainbow); Regs_Init(); R_ENABLE_ARENA_DBG = 0; // ENABLE_SPEEDMETER diff --git a/src/code/rainbow.c b/src/code/rainbow.c new file mode 100644 index 0000000000..18629911b2 --- /dev/null +++ b/src/code/rainbow.c @@ -0,0 +1,83 @@ +#include "rainbow.h" +#include "macros.h" + +/** + * How to use: + * - Create a ``Rainbow`` variable (no pointer) + * - Call ``Rainbow_Init`` in an init function with the address of the variable you just created + * - Call ``Rainbow_Update`` in an update function with the same address + * See ``main.c`` and ``game.c`` for the global rainbow implementation. +*/ + +static RainbowTarget sRainbowTarget[STATE_MAX] = { + { STATE_YELLOW_TO_GREEN, { 255, 255, 0 } }, + { STATE_GREEN_TO_LIGHTBLUE, { 0, 255, 0 } }, + { STATE_LIGHTBLUE_TO_BLUE, { 0, 255, 255 } }, + { STATE_BLUE_TO_PINK, { 0, 0, 255 } }, + { STATE_PINK_TO_RED, { 255, 0, 255 } }, + { STATE_RED_TO_YELLOW, { 255, 0, 0 } }, +}; + +void Rainbow_Debug(Rainbow* this) { + PRINTF( + "state: %d, r: %d, g: %d, b: %d, speed: %d, sRainbowTarget.state: %d\n", + this->state, this->color.r, this->color.g, this->color.b, this->speed, sRainbowTarget[this->state].state + ); +} + +void Rainbow_InitColor(Rainbow* this) { + this->color = sRainbowTarget[this->state].color; +} + +void Rainbow_Init(Rainbow* this) { + this->state = STATE_RED_TO_YELLOW; + this->speed = 8; + this->bAllowDebug = false; + this->bPause = false; + Rainbow_InitColor(this); +} + +u8 Rainbow_CheckColor(Rainbow* this, Color_RGB8 rgb) { + return ((this->color.r == rgb.r) && (this->color.g == rgb.g) && (this->color.b == rgb.b)); +} + +void Rainbow_UpdateColor(Rainbow* this) { + u8* channel = NULL; + + switch (this->state) { + case STATE_YELLOW_TO_GREEN: + case STATE_BLUE_TO_PINK: + channel = &this->color.r; + break; + case STATE_RED_TO_YELLOW: + case STATE_LIGHTBLUE_TO_BLUE: + channel = &this->color.g; + break; + case STATE_GREEN_TO_LIGHTBLUE: + case STATE_PINK_TO_RED: + channel = &this->color.b; + break; + } + + if (channel != NULL) { + s16 newValue = (s16)(!(this->state % 2) ? (*channel + this->speed) : (*channel - this->speed)); + *channel = (u8)(newValue > 255 ? 255 : newValue < 0 ? 0 : newValue); + } +} + +void Rainbow_UpdateState(Rainbow* this, RainbowTarget target) { + if (Rainbow_CheckColor(this, target.color)) { + this->state = target.state; + } +} + +void Rainbow_Update(Rainbow* this) { + if (!this->bPause) { + Rainbow_UpdateColor(this); + Rainbow_UpdateState(this, sRainbowTarget[this->state]); + + if (this->bAllowDebug) { + Rainbow_Debug(this); + } + } +}