diff --git a/Makefile b/Makefile index 8b33f2d08..0e720a80f 100644 --- a/Makefile +++ b/Makefile @@ -436,7 +436,7 @@ ifeq ($(PLATFORM),sdl) else ifeq ($(PLATFORM),sdl_win32) @cd $(OBJ_DIR) && $(CC1) -mwin32 $(OBJS_REL) -lmingw32 -L$(ROOT_DIR)/$(SDL_MINGW_LIB) -lSDL2main -lSDL2.dll -lwinmm -lkernel32 -lxinput -o $(ROOT_DIR)/$@ -Xlinker -Map "$(ROOT_DIR)/$(MAP)" else - @cd $(OBJ_DIR) && $(CC1) -mwin32 $(OBJS_REL) -L$(ROOT_DIR)/libagbsyscall -lagbsyscall -lkernel32 -lgdi32 -o $(ROOT_DIR)/$@ -Xlinker -Map "$(ROOT_DIR)/$(MAP)" + @cd $(OBJ_DIR) && $(CC1) -mwin32 $(OBJS_REL) -L$(ROOT_DIR)/libagbsyscall -lagbsyscall -lkernel32 -lgdi32 -lwinmm -lxinput -lopengl32 -o $(ROOT_DIR)/$@ -Xlinker -Map "$(ROOT_DIR)/$(MAP)" endif endif diff --git a/graphics.mk b/graphics.mk index 443bae415..1eecb0663 100644 --- a/graphics.mk +++ b/graphics.mk @@ -26,8 +26,15 @@ tileset_%.4bpp: tileset_%.png tiles.8bpp: tiles.png $(GFX) $< $@ -ignore_trailing +ifeq ($(PLATFORM),win32) + # For experimental OpenGL renderer + GFX_CVT_FLAGS := +else + GFX_CVT_FLAGS := -split_into_oam_shapes +endif + graphics/obj_tiles/4bpp/%.4bpp: graphics/obj_tiles/4bpp/%.png - $(GFX) $< $@ -split_into_oam_shapes + $(GFX) $< $@ $(GFX_CVT_FLAGS) graphics/obj_tiles/8bpp/%.8bpp: graphics/obj_tiles/8bpp/%.png - $(GFX) $< $@ -split_into_oam_shapes + $(GFX) $< $@ $(GFX_CVT_FLAGS) diff --git a/include/config.h b/include/config.h index ee95e6bad..4023644ee 100644 --- a/include/config.h +++ b/include/config.h @@ -30,4 +30,14 @@ #define TAS_TESTING 0 #define TAS_TESTING_WIDESCREEN_HACK 1 +#define RENDERER_SOFTWARE 0 +#define RENDERER_OPENGL 1 +#define RENDERER_COUNT 2 +#if PLATFORM_WIN32 && !PLATFORM_SDL +// TODO: Only win32 for now +#define RENDERER RENDERER_OPENGL +#else +#define RENDERER RENDERER_SOFTWARE +#endif + #endif // GUARD_SA2_CONFIG_H diff --git a/include/platform/shared/input.h b/include/platform/shared/input.h new file mode 100644 index 000000000..5b6045212 --- /dev/null +++ b/include/platform/shared/input.h @@ -0,0 +1,8 @@ +#ifndef GUARD_PLATFORM_SHARED_INPUT_H +#define GUARD_PLATFORM_SHARED_INPUT_H + +#include "sprite.h" // for Sprite + +u16 GetXInputKeys(); + +#endif // GUARD_PLATFORM_SHARED_INPUT_H diff --git a/include/platform/shared/opengl.h b/include/platform/shared/opengl.h new file mode 100644 index 000000000..dc643c216 --- /dev/null +++ b/include/platform/shared/opengl.h @@ -0,0 +1,10 @@ +#ifndef GUARD_PLATFORM_SHARED_OPENGL_H +#define GUARD_PLATFORM_SHARED_OPENGL_H + +#include "sprite.h" // for Sprite + +void OpenGL_OnInit(); +void OpenGL_DisplaySprite(Sprite *sprite, u8 oamPaletteNum); +void OpenGL_Render(void *tempBufferPixels, int windowWidth, int windowHeight); + +#endif // GUARD_PLATFORM_SHARED_OPENGL_H diff --git a/src/background.c b/src/background.c index 3ff353130..7b9869009 100644 --- a/src/background.c +++ b/src/background.c @@ -88,6 +88,11 @@ NONMATCH("asm/non_matching/engine/sub_8002B20.inc", bool32 sub_8002B20(void)) s32 j; u16 k; +#if (RENDERER == RENDERER_OPENGL) + // TEMP + return TRUE; +#endif + while (gBackgroundsCopyQueueCursor != gBackgroundsCopyQueueIndex) { Background *bg; @@ -626,6 +631,7 @@ END_NONMATCH void UpdateBgAnimationTiles(Background *bg) { +#if (RENDERER == RENDERER_SOFTWARE) Tilemap *tilemap = gTilemapsRef[bg->tilemapId]; if (tilemap->animFrameCount > 0) { if (tilemap->animDelay <= ++bg->animDelayCounter) { @@ -660,6 +666,7 @@ void UpdateBgAnimationTiles(Background *bg) } } } +#endif } // Differences to UpdateSpriteAnimation: @@ -845,6 +852,7 @@ NONMATCH("asm/non_matching/engine/sub_80039E4.inc", bool32 sub_80039E4(void)) return TRUE; #endif +#if (RENDERER == RENDERER_SOFTWARE) if (gUnknown_03005390 != 0) { OamDataShort oam; s32 r5; @@ -983,6 +991,7 @@ NONMATCH("asm/non_matching/engine/sub_80039E4.inc", bool32 sub_80039E4(void)) gUnknown_03005390 = 0; } +#endif return TRUE; } diff --git a/src/core.c b/src/core.c index 6aedab50b..71f032828 100644 --- a/src/core.c +++ b/src/core.c @@ -720,7 +720,9 @@ static bool32 ProcessVramGraphicsCopyQueue(void) if ((graphics->src != 0) && (graphics->dest != 0)) #endif { +#if (RENDERER != RENDERER_OPENGL) DmaCopy16(3, (void *)(graphics->src + offset), (void *)(graphics->dest + offset), COPY_CHUNK_SIZE); +#endif graphics->size -= COPY_CHUNK_SIZE; } #ifdef BUG_FIX @@ -733,7 +735,9 @@ static bool32 ProcessVramGraphicsCopyQueue(void) if ((graphics->src != 0) && (graphics->dest != 0)) #endif { +#if (RENDERER != RENDERER_OPENGL) DmaCopy16(3, (void *)(graphics->src + offset), (void *)(graphics->dest + offset), graphics->size); +#endif } graphics->size = 0; } diff --git a/src/game/interactables_2/egg_utopia/cannon.c b/src/game/interactables_2/egg_utopia/cannon.c index b89ec98bd..87313c0a6 100644 --- a/src/game/interactables_2/egg_utopia/cannon.c +++ b/src/game/interactables_2/egg_utopia/cannon.c @@ -262,7 +262,11 @@ NONMATCH("asm/non_matching/game/interactables_2/egg_utopia/sub_807E66C.inc", sta s32 biggerX, biggerY, temp2, temp3; s32 r4; s16 playerX, playerY; +#ifndef NON_MATCHING register Sprite_Cannon *r3 asm("r3") = cannon; +#else + Sprite_Cannon *r3 = cannon; +#endif Sprite *s2 = &r3->sprite2; if (!PLAYER_IS_ALIVE) { return 0; diff --git a/src/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index d9dc927f7..40ef5703d 100644 --- a/src/platform/pret_sdl/sdl2.c +++ b/src/platform/pret_sdl/sdl2.c @@ -18,6 +18,7 @@ #include "gba/types.h" #include "lib/agb_flash/flash_internal.h" #include "platform/shared/dma.h" +#include "platform/shared/input.h" #if ENABLE_AUDIO #include "platform/shared/audio/cgb_audio.h" @@ -494,60 +495,6 @@ void ProcessSDLEvents(void) } } -#ifdef _WIN32 -#define STICK_THRESHOLD 0.5f -u16 GetXInputKeys() -{ - XINPUT_STATE state; - ZeroMemory(&state, sizeof(XINPUT_STATE)); - - DWORD dwResult = XInputGetState(0, &state); - u16 xinputKeys = 0; - - if (dwResult == ERROR_SUCCESS) { - /* A */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_A) >> 12; - /* B */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_X) >> 13; - /* Start */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_START) >> 1; - /* Select */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) >> 3; - /* L */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) << 1; - /* R */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) >> 1; - /* Up */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) << 6; - /* Down */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) << 6; - /* Left */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) << 3; - /* Right */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) << 1; - - /* Control Stick */ - float xAxis = (float)state.Gamepad.sThumbLX / (float)SHRT_MAX; - float yAxis = (float)state.Gamepad.sThumbLY / (float)SHRT_MAX; - - if (xAxis < -STICK_THRESHOLD) - xinputKeys |= DPAD_LEFT; - else if (xAxis > STICK_THRESHOLD) - xinputKeys |= DPAD_RIGHT; - if (yAxis < -STICK_THRESHOLD) - xinputKeys |= DPAD_DOWN; - else if (yAxis > STICK_THRESHOLD) - xinputKeys |= DPAD_UP; - - /* Speedup */ - // Note: 'speedup' variable is only (un)set on keyboard input - double oldTimeScale = timeScale; - timeScale = (state.Gamepad.bRightTrigger > 0x80 || speedUp) ? 5.0 : 1.0; - - if (oldTimeScale != timeScale) { - if (timeScale > 1.0) { - SDL_PauseAudio(1); - } else { - SDL_ClearQueuedAudio(1); - SDL_PauseAudio(0); - } - } - } - - return xinputKeys; -} -#endif // _WIN32 - u16 Platform_GetKeyInput(void) { #ifdef _WIN32 diff --git a/src/platform/shared/input.c b/src/platform/shared/input.c new file mode 100644 index 000000000..d4b3a3878 --- /dev/null +++ b/src/platform/shared/input.c @@ -0,0 +1,44 @@ +#ifdef _WIN32 +#include +#include +#include "gba/io_reg.h" +#include "gba/types.h" + +#define STICK_THRESHOLD 0.5f +u16 GetXInputKeys() +{ + XINPUT_STATE state; + ZeroMemory(&state, sizeof(XINPUT_STATE)); + + DWORD dwResult = XInputGetState(0, &state); + u16 xinputKeys = 0; + + if (dwResult == ERROR_SUCCESS) { + /* A */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_A) >> 12; + /* B */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_X) >> 13; + /* Start */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_START) >> 1; + /* Select */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) >> 3; + /* L */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) << 1; + /* R */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) >> 1; + /* Up */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) << 6; + /* Down */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) << 6; + /* Left */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) << 3; + /* Right */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) << 1; + + /* Control Stick */ + float xAxis = (float)state.Gamepad.sThumbLX / (float)SHRT_MAX; + float yAxis = (float)state.Gamepad.sThumbLY / (float)SHRT_MAX; + + if (xAxis < -STICK_THRESHOLD) + xinputKeys |= DPAD_LEFT; + else if (xAxis > STICK_THRESHOLD) + xinputKeys |= DPAD_RIGHT; + if (yAxis < -STICK_THRESHOLD) + xinputKeys |= DPAD_DOWN; + else if (yAxis > STICK_THRESHOLD) + xinputKeys |= DPAD_UP; + } + + return xinputKeys; +} +#endif // _WIN32 diff --git a/src/platform/win32/opengl.c b/src/platform/win32/opengl.c new file mode 100644 index 000000000..5ff9897c4 --- /dev/null +++ b/src/platform/win32/opengl.c @@ -0,0 +1,249 @@ +#include // realloc +#include // printf +#include +#include "global.h" // TEMP for PLTT +#include "platform/shared/opengl.h" + +// NOTE: This is NOT final at all. EXPERIMENTAL!!!!! + +// TODO: Move this file into /platform/shared + +// TEMP +static GLuint sTempTextureHandles[3] = { 0 }; + +#define NUM_RGB_CHANNELS 4 +u8 tempRgbaPalette[16 * 32][NUM_RGB_CHANNELS] = {}; +u8 tempRgbaFrame[DISPLAY_WIDTH * DISPLAY_HEIGHT][NUM_RGB_CHANNELS] = {}; + +typedef struct { + u8 *data; + int width, height; +} TextureBuffer; +static TextureBuffer sDynTextureBuffer = { 0 }; + +static void TempConvertPLTTToRGBA8(void) +{ + // Convert PLTT from ABGR1555 -> RGBA8 + for (int i = 0; i < ARRAY_COUNT(tempRgbaPalette); i++) { + u16 color = PLTT[i]; + float r = (float)(color & 0x01F) / 31.0; + float g = (float)((color & 0x3E0) >> 5) / 31.0; + float b = (float)((color & 0x7C00) >> 10) / 31.0; + + tempRgbaPalette[i][0] = r * 255.0; + tempRgbaPalette[i][1] = g * 255.0; + tempRgbaPalette[i][2] = b * 255.0; + tempRgbaPalette[i][3] = 1 * 255.0; + } +} + +static u8 *TempConvertPLTTEntryToRGBA8(u8 paletteId) +{ + // Convert PLTT from ABGR1555 -> RGBA8 + u16 *pal4BPP = &PLTT[(paletteId + 16) * 16]; + + for (int i = 0; i < 16; i++) { + u16 color = pal4BPP[i]; + + float r = (float)(color & 0x01F) / 31.0; + float g = (float)((color & 0x3E0) >> 5) / 31.0; + float b = (float)((color & 0x7C00) >> 10) / 31.0; + + tempRgbaPalette[paletteId * 16 + i][0] = r * 255.0; + tempRgbaPalette[paletteId * 16 + i][1] = g * 255.0; + tempRgbaPalette[paletteId * 16 + i][2] = b * 255.0; + tempRgbaPalette[paletteId * 16 + i][3] = 1 * 255.0; + } + + return tempRgbaPalette[paletteId * 16]; +} + +// TODO: This should be done offline. +// Just load all assets in RGB8 or RGBA8 on boot. +static void TempConvert4bppToRGBA8_DynTextureBuffer(const u8 *bitmap4bpp, int width, int height, u8 paletteId) +{ + if (sDynTextureBuffer.width * sDynTextureBuffer.height < width * height) { + sDynTextureBuffer.data = realloc(sDynTextureBuffer.data, width * height * sizeof(u32)); + + if (!sDynTextureBuffer.data) { + printf("WARNING: realloc in %s failed!\n", __FUNCTION__); + return; + } else { + printf("realloc: w 0x%X, h 0x%X, full: 0x%X\n", width, height, (u32)(width * height * sizeof(u32))); + } + } + + u8 *texturePalette = TempConvertPLTTEntryToRGBA8(paletteId); + + sDynTextureBuffer.width = width; + sDynTextureBuffer.height = height; + + u16 widthInTiles = width >> 3; + + int numSourcePixels = width * height; + for (int frameY = 0; frameY < height; frameY++) { + for (int frameX = 0; frameX < width; frameX++) { + u8 colorIndex = ((frameY & 0x7) * 8 + (frameX & 0x7)); + + bool8 doShift = (colorIndex & 1); + u8 textureColorId = bitmap4bpp[colorIndex >> 1] & (0xF << (doShift * 4)); + textureColorId >>= doShift * 4; + + sDynTextureBuffer.data[colorIndex * 4 + 0] = tempRgbaPalette[textureColorId][0]; + sDynTextureBuffer.data[colorIndex * 4 + 1] = tempRgbaPalette[textureColorId][1]; + sDynTextureBuffer.data[colorIndex * 4 + 2] = tempRgbaPalette[textureColorId][2]; + sDynTextureBuffer.data[colorIndex * 4 + 3] = 0xFF; + } + } +} + +void OpenGL_OnInit() +{ + // Enable texturing + glEnable(GL_TEXTURE_2D); + + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + + // NOTE: Modelview matrix is a legacy feature + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glGenTextures(2, &sTempTextureHandles[0]); +} + +void OpenGL_DisplaySprite(Sprite *sprite, u8 oamPaletteNum) +{ + const SpriteOffset *dims = sprite->dimensions; + + if (dims != (void *)-1) { + // Convert vertices screenspace -> unit space + glMatrixMode(GL_PROJECTION); +#if 0 + glLoadIdentity(); +#else + float a = 2.0f / DISPLAY_WIDTH; + float b = 2.0f / DISPLAY_HEIGHT; + float projMtx[] = { a, 0, 0, 0, 0, b, 0, 0, 0, 0, 1, 0, -1, -1, 0, 1 }; + glLoadMatrixf(projMtx); +#endif + + TempConvert4bppToRGBA8_DynTextureBuffer(sprite->graphics.src, dims->width, dims->height, sprite->palId + oamPaletteNum); + + // glGenTextures(1, &sTempTextureHandles[2]); + glBindTexture(GL_TEXTURE_2D, sTempTextureHandles[2]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dims->width, dims->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, sDynTextureBuffer.data); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // downscale filtering + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // upscale filtering + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + // glClearColor((float)tempRgbaPalette[1][0] / 255., + // (float)tempRgbaPalette[1][1] / 255., + // (float)tempRgbaPalette[1][2] / 255., + // 1.0); + // glClear(GL_COLOR_BUFFER_BIT); + + float minX = sprite->x - (dims->width >> 1); + float maxX = minX + dims->width; + + float minY = sprite->y - (dims->height >> 1); + float maxY = minY + dims->height; + + glBegin(GL_TRIANGLES); + { + glTexCoord2f(0.0, 0.0); + glVertex2f(minX, maxY); + glTexCoord2f(1.0, 1.0); + glVertex2f(maxX, minY); + glTexCoord2f(0.0, 1.0); + glVertex2f(minX, minY); + + glTexCoord2f(0.0, 0.0); + glVertex2f(minX, maxY); + glTexCoord2f(1.0, 0.0); + glVertex2f(maxX, maxY); + glTexCoord2f(1.0, 1.0); + glVertex2f(maxX, minY); + } + glEnd(); + } +} + +void OpenGL_Render(void *tempBufferPixels, int viewportWidth, int viewportHeight) +{ + glViewport(0, 0, viewportWidth, viewportHeight); + +#if 0 + // Don't convert input-vertices + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); +#else + // Convert vertices screenspace -> unit space + glMatrixMode(GL_PROJECTION); + float a = 2.0f / DISPLAY_WIDTH; + float b = 2.0f / DISPLAY_HEIGHT; + float projMtx[] = { + a, 0, 0, 0, // + 0, b, 0, 0, // + 0, 0, 1, 0, // + -1, -1, 0, 1 // + }; + glLoadMatrixf(projMtx); +#endif + + // TempConvertPLTTToRGBA8(); + + // Convert the "software-rendered" image from ABGR1555 -> RGBA8 + for (int i = 0; i < ARRAY_COUNT(tempRgbaFrame); i++) { + u16 color = ((u16 *)tempBufferPixels)[i]; + float r = (float)(color & 0x01F) / 31.0; + float g = (float)((color & 0x3E0) >> 5) / 31.0; + float b = (float)((color & 0x7C00) >> 10) / 31.0; + + tempRgbaFrame[i][0] = b * 255.0; + tempRgbaFrame[i][1] = g * 255.0; + tempRgbaFrame[i][2] = r * 255.0; + tempRgbaFrame[i][3] = 1 * 255.0; + } + + glBindTexture(GL_TEXTURE_2D, sTempTextureHandles[0]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, tempRgbaPalette); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // downscale filtering + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // upscale filtering + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + glBindTexture(GL_TEXTURE_2D, sTempTextureHandles[1]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, DISPLAY_WIDTH, DISPLAY_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, tempRgbaFrame); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // downscale filtering + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // upscale filtering + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + glClearColor(1.0, 1.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + glBindTexture(GL_TEXTURE_2D, sTempTextureHandles[1]); + glBegin(GL_TRIANGLES); + { + glTexCoord2f(0.0, 0.0); + glVertex2f(0.0, +DISPLAY_HEIGHT); + glTexCoord2f(1.0, 1.0); + glVertex2f(+DISPLAY_WIDTH, 0); + glTexCoord2f(0.0, 1.0); + glVertex2f(0, 0); + + glTexCoord2f(0.0, 0.0); + glVertex2f(0, DISPLAY_HEIGHT); + glTexCoord2f(1.0, 0.0); + glVertex2f(DISPLAY_WIDTH, DISPLAY_HEIGHT); + glTexCoord2f(1.0, 1.0); + glVertex2f(DISPLAY_WIDTH, 0); + } + glEnd(); +} \ No newline at end of file diff --git a/src/platform/win32/win32.c b/src/platform/win32/win32.c index 896ef06a5..89ab44870 100644 --- a/src/platform/win32/win32.c +++ b/src/platform/win32/win32.c @@ -3,6 +3,14 @@ #include "global.h" #include "core.h" +#include "gba/io_reg.h" + +#if (RENDERER == RENDERER_OPENGL) +#include +#include "platform/shared/opengl.h" +#endif + +#include "platform/shared/input.h" extern void GameInit(void); @@ -11,6 +19,10 @@ LRESULT CALLBACK Win32_WindowCallback(HWND window, UINT message, WPARAM wParam, static void Win32_ProcessPendingMessages(HWND window); static RECT Win32_GetWindowDimension(HWND Window); +#if (RENDERER == RENDERER_OPENGL) +static void Win32_InitOpenGL(HWND window); +#endif + static u16 ALIGNED(8) sImageBuffer[DISPLAY_WIDTH * DISPLAY_HEIGHT] = { RGB_GREEN, RGB_GREEN, RGB_GREEN, RGB_GREEN, RGB_GREEN, RGB_GREEN, RGB_GREEN, RGB_GREEN, RGB_GREEN, RGB_GREEN, RGB_GREEN, RGB_GREEN, RGB_GREEN, RGB_GREEN, RGB_GREEN, RGB_GREEN, RGB_GREEN, RGB_GREEN, @@ -19,6 +31,7 @@ static BITMAPINFO sBMInfo = { 0 }; static bool32 sRunning = TRUE; static HWND sWindowHandle = 0; static HDC sDeviceContext = 0; +static u16 sInputKeys = 0; #define ENABLE_RESIZE TRUE @@ -79,6 +92,10 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR lpCmdLine, if (sWindowHandle) { sDeviceContext = GetDC(sWindowHandle); +#if (RENDERER == RENDERER_OPENGL) + Win32_InitOpenGL(sWindowHandle); +#endif + sBMInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); sBMInfo.bmiHeader.biWidth = DISPLAY_WIDTH; sBMInfo.bmiHeader.biHeight = -DISPLAY_HEIGHT; // negative biHeight: bottom->down image @@ -91,6 +108,8 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR lpCmdLine, sBMInfo.bmiHeader.biClrUsed = 0; sBMInfo.bmiHeader.biClrImportant = 0; + timeBeginPeriod(1); + Win32_ProcessPendingMessages(sWindowHandle); // If this isn't set, gFlags gets set to FLAGS_200, leading to the MP menu being @@ -105,12 +124,18 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR lpCmdLine, #if 01 REG_KEYINPUT &= ~START_BUTTON; - // while (sRunning) - { + while (sRunning) { + memset(sImageBuffer, 0, sizeof(sImageBuffer)); + gFlags |= 0x4000; EngineMainLoop(); - REG_KEYINPUT ^= (A_BUTTON | START_BUTTON); - REG_KEYINPUT |= (DPAD_RIGHT); + // REG_KEYINPUT ^= (A_BUTTON | START_BUTTON); + + // NOTE: This is an OR because sInputKeys can get set + // through keyboard events. + sInputKeys |= GetXInputKeys(); + + REG_KEYINPUT = ~sInputKeys; } #else HANDLE GameThreadHandle = CreateThread(NULL, 0, GameThread, NULL, 0, &threadId); @@ -134,10 +159,50 @@ DWORD WINAPI GameThread(void *pThreadParam) } } +#if (RENDERER == RENDERER_OPENGL) +// From "Handmade Hero 235 - Initializing OpenGL on Windows" +// https://www.youtube.com/watch?v=5Klc9RZPG7M +static void Win32_InitOpenGL(HWND window) +{ + HDC deviceContext = GetDC(window); + + PIXELFORMATDESCRIPTOR desiredPixelFormat = {}; + PIXELFORMATDESCRIPTOR suggestedPixelFormat; + + // TODO: Find out if double-buffering is necessary for us! + desiredPixelFormat.nSize = sizeof(PIXELFORMATDESCRIPTOR); + desiredPixelFormat.nVersion = 1; + desiredPixelFormat.dwFlags = (PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER); + desiredPixelFormat.cColorBits = 24; + desiredPixelFormat.cAlphaBits = 8; + desiredPixelFormat.iLayerType = PFD_MAIN_PLANE; + + int suggestedPixelFormatIndex = ChoosePixelFormat(deviceContext, &desiredPixelFormat); + DescribePixelFormat(deviceContext, suggestedPixelFormatIndex, sizeof(PIXELFORMATDESCRIPTOR), &suggestedPixelFormat); + SetPixelFormat(deviceContext, suggestedPixelFormatIndex, &suggestedPixelFormat); + + // RC = "Rendering Context" + HGLRC openGLRC = wglCreateContext(deviceContext); + + if (wglMakeCurrent(deviceContext, openGLRC)) { + OpenGL_OnInit(); + } else { + // LOG fail + } + + ReleaseDC(window, deviceContext); +} +#endif + static void Win32_DisplayBufferInWindow(HDC deviceContext, int windowWidth, int windowHeight) { +#if (RENDERER == RENDERER_OPENGL) + OpenGL_Render(sImageBuffer, windowWidth, windowHeight); + SwapBuffers(deviceContext); +#else StretchDIBits(deviceContext, 0, 0, windowWidth, windowHeight, 0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, sImageBuffer, &sBMInfo, DIB_RGB_COLORS, SRCCOPY); +#endif } LRESULT CALLBACK Win32_WindowCallback(HWND window, UINT message, WPARAM wParam, LPARAM lParam) @@ -179,11 +244,66 @@ LRESULT CALLBACK Win32_WindowCallback(HWND window, UINT message, WPARAM wParam, return result; } +static u16 Win32_KeyboardKeyToGameKey(char key) +{ + switch (key) { + case 'C': { + return A_BUTTON; + } break; + + case 'X': { + return B_BUTTON; + } break; + + case VK_RETURN: { + return START_BUTTON; + } break; + + case VK_BACK: { + return SELECT_BUTTON; + } break; + + case VK_LEFT: { + return DPAD_LEFT; + } break; + + case VK_UP: { + return DPAD_UP; + } break; + + case VK_RIGHT: { + return DPAD_RIGHT; + } break; + + case VK_DOWN: { + return DPAD_DOWN; + } break; + + case 'S': { + return L_BUTTON; + } break; + + case 'D': { + return R_BUTTON; + } break; + } + + return 0; +} + static void Win32_ProcessPendingMessages(HWND window) { MSG message; while (PeekMessage(&message, 0, 0, 0, PM_REMOVE)) { switch (message.message) { + case WM_KEYUP: { + sInputKeys &= ~Win32_KeyboardKeyToGameKey(message.wParam); + } break; + + case WM_KEYDOWN: { + sInputKeys |= Win32_KeyboardKeyToGameKey(message.wParam); + } break; + case WM_QUIT: { printf("Closing"); sRunning = FALSE; @@ -197,19 +317,131 @@ static void Win32_ProcessPendingMessages(HWND window) } } +// Converts GBA -> Win32 RGB value +#define RGB_SHIFT(value) (((value >> 10) & 0x1F) | (value & 0x3E0) | (((value & 0x1F) << 10))) + +void Platform_DisplaySprite(Sprite *sprite, u8 oamPaletteNum) +{ + if (sprite->graphics.src == NULL) + return; + +#if (RENDERER == RENDERER_OPENGL) + // TEMP - Currently the display buffer gets drawn in software, but we should load the assets as a textures and let OpenGL render + // everything + // OpenGL_DisplaySprite(sprite, oamPaletteNum); + // return; +#endif + + const SpriteOffset *dims = sprite->dimensions; + + bool32 xFlip = SPRITE_FLAG_GET(sprite, X_FLIP); + bool32 yFlip = SPRITE_FLAG_GET(sprite, Y_FLIP); + + // printf("Sprite: %d\n", sprite->graphics.anim); + + s32 x, y, sprWidth, sprHeight; + + x = sprite->x; + y = sprite->y; + + { + // TEMP - from sprite.c + sprWidth = dims->width; + sprHeight = dims->height; + if (sprite->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE_ENABLE) { + if (sprite->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE_DOUBLE_SIZE) { + x -= dims->width / 2; + y -= dims->height / 2; + sprWidth *= 2; + sprHeight *= 2; + } + } else { + if (sprite->frameFlags & SPRITE_FLAG_MASK_Y_FLIP) { + y -= sprHeight - dims->offsetY; + } else { + y -= dims->offsetY; + } + + if (sprite->frameFlags & SPRITE_FLAG_MASK_X_FLIP) { + x -= sprWidth - dims->offsetX; + } else { + x -= dims->offsetX; + } + } + } + + s32 tempX = x; + s32 tempY = y; + + u16 widthInTiles = dims->width >> 3; + + for (int frameY = 0; frameY < dims->height; frameY++) { + s32 finalY = (tempY + frameY); + + if (finalY < 0) + continue; + + if (finalY >= DISPLAY_HEIGHT) + break; + + for (int frameX = 0; frameX < dims->width; frameX++) { + + s32 finalX = (tempX + frameX); + + if (finalX < 0) + continue; + + if (finalX >= DISPLAY_WIDTH) + break; + + int bufferPixelIndex = finalY * DISPLAY_WIDTH + finalX; + int imagePixelIndex = frameY * dims->width + frameX; + + if (bufferPixelIndex >= 0 && bufferPixelIndex < DISPLAY_WIDTH * DISPLAY_HEIGHT) { + u16 *pal = &PLTT[oamPaletteNum * 16 + (BG_PLTT_SIZE / 2)]; + u16 tileNumX = (frameX >> 3); + u16 tileNumY = (frameY >> 3); + u16 tileNum = tileNumY * widthInTiles + tileNumX; + u32 offset = tileNum * TILE_SIZE_4BPP; + + u8 *tile = &((u8 *)sprite->graphics.src)[offset]; + + u8 colorIndex = ((frameY & 0x7) * 8 + (frameX & 0x7)); + + bool8 doShift = (colorIndex & 1); + u8 colorId = tile[colorIndex >> 1] & (0xF << (doShift * 4)); + colorId >>= doShift * 4; + if (colorId != 0) + sImageBuffer[bufferPixelIndex] = RGB_SHIFT(pal[colorId]); + } + } + } +} + void VBlankIntrWait() { - while (sRunning) { + // while (sRunning) + { // NOTE: This wouldn't work here with multiple threads, because PeekMessage() // only gets messages in the thread the specified window was created in. Win32_ProcessPendingMessages(sWindowHandle); RECT clientRect; GetClientRect(sWindowHandle, &clientRect); - Win32_DisplayBufferInWindow(sDeviceContext, clientRect.right - clientRect.left, clientRect.bottom - clientRect.top); - Sleep(16); static u8 test = 0; + sImageBuffer[test++] = RGB_BLACK; sImageBuffer[test] = RGB_GREEN; + Win32_DisplayBufferInWindow(sDeviceContext, clientRect.right - clientRect.left, clientRect.bottom - clientRect.top); + + // TODO: Remove Sleep, use high-resolution timer instead! + Sleep(10); + +#if (RENDERER == RENDERER_OPENGL) + // TODO: Don't do this here!!! + // This should be called in src/platform/shared/opengl.c + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT); +#endif } } diff --git a/src/sprite.c b/src/sprite.c index 0f49ddff6..555286db1 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -7,6 +7,11 @@ #include "lib/m4a/m4a.h" #include "data/sprite_data.h" #include "animation_commands.h" +#include "platform/platform.h" + +#if !PLATFORM_GBA && !PLATFORM_SDL +extern void Platform_DisplaySprite(Sprite *sprite, u8 oamPaletteNum); +#endif extern const AnimationCommandFunc animCmdTable[]; @@ -533,6 +538,7 @@ void DisplaySprite(Sprite *sprite) const u16 *oamData; if (sprite->dimensions != (void *)-1) { + const SpriteOffset *sprDims = sprite->dimensions; sprite->numSubFrames = sprDims->numSubframes; @@ -592,6 +598,15 @@ void DisplaySprite(Sprite *sprite) oam->all.attr0 &= 0xFE00; oam->all.attr2 += sprite->palId << 12; + +#if !PLATFORM_GBA && !PLATFORM_SDL + // TEMP + // Quick hack for getting output in OpenGL test + // The whole function call should be replaced by this! + Platform_DisplaySprite(sprite, oam->split.paletteNum); + return; +#endif + if (sprite->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE_ENABLE) { oam->all.attr0 |= 0x100; if (sprite->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE_DOUBLE_SIZE) { @@ -799,7 +814,7 @@ void CopyOamBufferToOam(void) u8 i = 0; s32 r3; - for (r3 = 0; r3 < 32; r3++) { + for (r3 = 0; r3 < (s32)ARRAY_COUNT(gUnknown_03001850); r3++) { s8 index = gUnknown_03001850[r3]; while (index != -1) { diff --git a/tools/_shared/c_header_parser/tilemaps.h b/tools/_shared/c_header_parser/tilemaps.h deleted file mode 100644 index 83f2fbe4a..000000000 --- a/tools/_shared/c_header_parser/tilemaps.h +++ /dev/null @@ -1,308 +0,0 @@ -#ifndef GUARD_TILEMAPS -#define GUARD_TILEMAPS - -// NOTE: * 0-92 are MapHeaders -// * 93 == NULL -#define TM_LEVEL_METATILES_0(level) (((level)*3) + 0) -#define TM_LEVEL_METATILES_1(level) (((level)*3) + 1) -#define TM_LEVEL_BG(level) (((level)*3) + 2) - -#define TM_SA1_TITLE_LOGO 94 -#define TM_SA1_TITLE_BG 95 -#define TM_INTRO_PRESENTED_BY_SEGA 96 -#define TM_INTRO_CREATED_BY_SONIC_TEAM 97 -#define TM_CHAR_SELECT_BACKGROUND 98 -#define TM_CHAR_SELECT_WHEEL 99 -#define TM_STAGE_SELECT_BG_SONIC 100 -#define TM_STAGE_SELECT_BG_CREAM 101 -#define TM_STAGE_SELECT_BG_TAILS 102 -#define TM_STAGE_SELECT_BG_KNUCKLES 103 -#define TM_STAGE_SELECT_BG_AMY 104 -#define TM_STAGE_SELECT_MAP 105 -#define TM_EGG_SAUCER_WHEEL_COPY 106 -#define TM_UNKNOWN_OPTIONS_BG 107 -#define TM_108 108 -#define TM_SA2_TITLE_LOGO_JP 109 -#define TM_TA_AND_MP_WHITE_BG 110 -#define TM_MP_ORANGE_BG 111 -#define TM_TA_ORANGE_BG 112 -#define TM_STAGE_1_BG_0_COPY 113 -#define TM_MP_WAIT_CONNECTION 114 -#define TM_MP_MESSAGE_BOX_UNKNOWN 115 -#define TM_MP_CHARACTERS_SELECTED_JP 116 -#define TM_MP_CHARACTERS_SELECTED_EN 117 -#define TM_MP_CHARACTERS_SELECTED_DE 118 -#define TM_MP_CHARACTERS_SELECTED_FR 119 -#define TM_MP_CHARACTERS_SELECTED_ES 120 -#define TM_MP_CHARACTERS_SELECTED_IT 121 -#define TM_MP_UNKNOWN_ORANGE_ZIGZAG 122 -#define TM_MP_UNKNOWN_GREEN 123 -#define TM_UNKNOWN_MESSAGE_BOX_WHITE 124 -#define TM_UNKNOWN_MESSAGE_BOX_WHITE_SMALL 125 -#define TM_MP_VS_BACKGROUND_TEXT 126 -#define TM_MP_CHEESE_PLEASE_WAIT_JP 127 -#define TM_MP_CHEESE_PLEASE_WAIT_EN 128 -#define TM_MP_CHEESE_PLEASE_WAIT_DE 129 -#define TM_MP_CHEESE_PLEASE_WAIT_FR 130 -#define TM_MP_CHEESE_PLEASE_WAIT_ES 131 -#define TM_MP_CHEESE_PLEASE_WAIT_IT 132 -#define TM_OPTIONS_BG0 133 -#define TM_OPTIONS_LANGUAGE_SELECT 134 -#define TM_OPTIONS_ENTER_NAME 135 -#define TM_OPTIONS_ENTER_NAME_CHARACTERS 136 -#define TM_OPTIONS_TIME_RECORD_BG0 137 -#define TM_OPTIONS_TIME_RECORD_BG1 138 -#define TM_139 139 -#define TM_MP_CHARACTER_SELECTED_SONIC_BG 140 -#define TM_MP_CHARACTER_SELECTED_SONIC 141 -#define TM_MP_CHARACTER_SELECTED_TAILS_BG 142 -#define TM_MP_CHARACTER_SELECTED_TAILS 143 -#define TM_MP_CHARACTER_SELECTED_KNUCKLES_BG 144 -#define TM_MP_CHARACTER_SELECTED_KNUCKLES 145 -#define TM_MP_CHARACTER_SELECTED_AMY_BG 146 -#define TM_MP_CHARACTER_SELECTED_AMY 147 -#define TM_MP_CHARACTER_SELECTED_CREAM_BG 148 -#define TM_MP_CHARACTER_SELECTED_CREAM 149 -#define TM_150_MESSAGE_BOX_BLACK 150 -#define TM_151_GREEN_CARET 151 -#define TM_OPTIONS_VS_RECORD_BG1 152 -#define TM_SPECIAL_STAGE_1 153 -#define TM_SPECIAL_STAGE_1_BG 154 -#define TM_SPECIAL_STAGE_2 155 -#define TM_SPECIAL_STAGE_2_BG 156 -#define TM_SPECIAL_STAGE_3 157 -#define TM_SPECIAL_STAGE_3_BG 158 -#define TM_SPECIAL_STAGE_4 159 -#define TM_SPECIAL_STAGE_4_BG 160 -#define TM_SPECIAL_STAGE_5 161 -#define TM_SPECIAL_STAGE_5_BG 162 -#define TM_SPECIAL_STAGE_6 163 -#define TM_SPECIAL_STAGE_6_BG 164 -#define TM_SPECIAL_STAGE_7 165 -#define TM_SPECIAL_STAGE_7_BG 166 -#define TM_TECHNO_BASE_BG_PURPLE_GRID 167 -#define TM_TECHNO_BASE_BG_CIRCUIT_MASK 168 -#define TM_SOUND_TEST_BG 169 -#define TM_CUTSCENE_POST_EXTRA_BOSS_BG 170 -#define TM_CUTSCENE_FINAL_ENDING_FALL_BG 171 -#define TM_CUTSCENE_FINAL_ENDING_FALL_CLOUDS 172 -#define TM_CUTSCENE_FINAL_ENDING_FALL_BG_DARK 173 -#define TM_CUTSCENE_FINAL_ENDING_FALL_BG_DARK_2 174 -// JP has an image of Eggman, other languages are only the textbox -#define TM_COLLECT_ALL_CHAOS_EMERALDS_JP 175 -#define TM_COLLECT_ALL_CHAOS_EMERALDS_EN 176 -#define TM_COLLECT_ALL_CHAOS_EMERALDS_FR 177 -#define TM_COLLECT_ALL_CHAOS_EMERALDS_DE 178 -#define TM_COLLECT_ALL_CHAOS_EMERALDS_IT 179 -#define TM_COLLECT_ALL_CHAOS_EMERALDS_ES 180 - -// (Also used as BG for SoundTest unlock) -// JP fills the entire screen, other languages are only the textbox -#define TM_UNLOCKED_TINY_CHAO_GARDEN_JP 181 -#define TM_UNLOCKED_TINY_CHAO_GARDEN_EN 182 -#define TM_UNLOCKED_TINY_CHAO_GARDEN_FR 183 -#define TM_UNLOCKED_TINY_CHAO_GARDEN_DE 184 -#define TM_UNLOCKED_TINY_CHAO_GARDEN_IT 185 -#define TM_UNLOCKED_TINY_CHAO_GARDEN_ES 186 - -// Uses TM_UNLOCKED_TINY_CHAO_GARDEN_JP as BG -#define TM_UNLOCKED_SOUND_TEST_JP 187 -#define TM_UNLOCKED_SOUND_TEST_EN 188 -#define TM_UNLOCKED_SOUND_TEST_FR 189 -#define TM_UNLOCKED_SOUND_TEST_DE 190 -#define TM_UNLOCKED_SOUND_TEST_IT 191 -#define TM_UNLOCKED_SOUND_TEST_ES 192 - -// Uses TM_UNLOCKED_TINY_CHAO_GARDEN_JP as BG -#define TM_UNLOCKED_BOSSES_TIME_ATTACK_JP 193 -#define TM_UNLOCKED_BOSSES_TIME_ATTACK_EN 194 -#define TM_UNLOCKED_BOSSES_TIME_ATTACK_FR 195 -#define TM_UNLOCKED_BOSSES_TIME_ATTACK_DE 196 -#define TM_UNLOCKED_BOSSES_TIME_ATTACK_IT 197 -#define TM_UNLOCKED_BOSSES_TIME_ATTACK_ES 198 -#define TM_UNLOCKED_AMY_JP 199 -#define TM_UNLOCKED_AMY_EN 200 -#define TM_UNLOCKED_AMY_FR 201 -#define TM_UNLOCKED_AMY_DE 202 -#define TM_UNLOCKED_AMY_IT 203 -#define TM_UNLOCKED_AMY_ES 204 -#define TM_CUTSCENE_FINAL_ENDING_LAND_FG 205 -#define TM_CUTSCENE_FINAL_ENDING_LAND_BG 206 -#define TM_CUTSCENE_FINAL_ENDING_LAND_FLOWER_FIELD 207 -#define TM_CUTSCENE_FINAL_ENDING_LAND_BG_ALT 208 -#define TM_UNK_SPACE_BG 209 -#define TM_STORYFRAME_SONIC_CATCHES_VANILLA 210 -#define TM_STORYFRAME_SONIC_FINDS_FRIENDS 211 -#define TM_STORYFRAME_SONIC_PATS_TAILS 212 -#define TM_STORYFRAME_CREAM_HUGS_VANILLA 213 -#define TM_STORYFRAME_CREAM_TAILS_VANILLA_LOOK_AROUND 214 -#define TM_STORYFRAME_CREAM_CHEESE_VANILLA_HAPPY 215 -#define TM_STORYFRAME_SONIC_LEAVES_0 216 -#define TM_STORYFRAME_SONIC_LEAVES_1 217 -#define TM_STORYFRAME_SONIC_LEAVES_2 218 -#define TM_STORYFRAME_SONIC_LEAVES_3 219 -#define TM_STORYFRAME_SONIC_LEAVES_4 220 -#define TM_STORYFRAME_SONIC_LEAVES_5 221 -#define TM_STORYFRAME_SONIC_LEAVES_6 222 -#define TM_STORYFRAME_SONIC_LEAVES_7 223 -#define TM_STORYFRAME_SONIC_LEAVES_8 224 -#define TM_STORYFRAME_SONIC_LEAVES_9 225 -#define TM_STORYFRAME_SONIC_LEAVES_10 226 -#define TM_STORYFRAME_CREAM_UNLOCK_0_SEPIA 227 -#define TM_STORYFRAME_CREAM_UNLOCK_1_SEPIA 228 -#define TM_STORYFRAME_TAILS_UNLOCK_1_SEPIA 229 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_1_SEPIA 230 -#define TM_STORYFRAME_CREAM_UNLOCK_3_SEPIA 231 -#define TM_CREDITS_SA2_LOGO_JP 232 -#define TM_CREDITS_SA2_LOGO_EN 233 -#define TM_CREDITS_0 234 -#define TM_CREDITS_1 235 -#define TM_CREDITS_2 236 -#define TM_CREDITS_3 237 -#define TM_CREDITS_4 238 -#define TM_CREDITS_5 239 -#define TM_CREDITS_6 240 -#define TM_CREDITS_7 241 -#define TM_CREDITS_8 242 -#define TM_CREDITS_9 243 -#define TM_CREDITS_10 244 -#define TM_CREDITS_11 245 -#define TM_CREDITS_12 246 -#define TM_CREDITS_13 247 -#define TM_CREDITS_14 248 -#define TM_CREDITS_15 249 -#define TM_CREDITS_16 250 -#define TM_CREDITS_17 251 -#define TM_CREDITS_18 252 -#define TM_CREDITS_19 253 -#define TM_CREDITS_20 254 -#define TM_CREDITS_21 255 -#define TM_CREDITS_22 256 -#define TM_CREDITS_23 257 -#define TM_CREDITS_24 258 -#define TM_CREDITS_COPYRIGHT 259 -#define TM_CREDITS_PRESENTED_BY_SEGA 260 -#define TM_TITLE_SCREEN_BG 261 -#define TM_INTRO_WATER 262 -#define TM_LENS_FLARE_BG 263 -#define TM_SA2_LOGO_JP 264 -#define TM_SA2_LOGO_EN 265 -#define TM_STORYFRAME_CREAM_UNLOCK_0 266 -#define TM_STORYFRAME_CREAM_UNLOCK_1 267 -#define TM_STORYFRAME_CREAM_UNLOCK_2 268 -#define TM_STORYFRAME_CREAM_UNLOCK_3 269 -#define TM_STORYFRAME_CREAM_UNLOCK_0_DLG_JP 270 -#define TM_STORYFRAME_CREAM_UNLOCK_1_DLG_JP 271 -#define TM_STORYFRAME_CREAM_UNLOCK_2_DLG_JP 272 -#define TM_STORYFRAME_CREAM_UNLOCK_3_DLG_JP 273 -#define TM_STORYFRAME_CREAM_UNLOCKED_JP 274 -#define TM_STORYFRAME_CREAM_UNLOCK_0_DLG_EN 275 -#define TM_STORYFRAME_CREAM_UNLOCK_1_DLG_EN 276 -#define TM_STORYFRAME_CREAM_UNLOCK_2_DLG_EN 277 -#define TM_STORYFRAME_CREAM_UNLOCK_3_DLG_EN 278 -#define TM_STORYFRAME_CREAM_UNLOCKED_EN 279 -#define TM_STORYFRAME_CREAM_UNLOCK_0_DLG_FR 280 -#define TM_STORYFRAME_CREAM_UNLOCK_1_DLG_FR 281 -#define TM_STORYFRAME_CREAM_UNLOCK_2_DLG_FR 282 -#define TM_STORYFRAME_CREAM_UNLOCK_3_DLG_FR 283 -#define TM_STORYFRAME_CREAM_UNLOCKED_FR 284 -#define TM_STORYFRAME_CREAM_UNLOCK_0_DLG_DE 285 -#define TM_STORYFRAME_CREAM_UNLOCK_1_DLG_DE 286 -#define TM_STORYFRAME_CREAM_UNLOCK_2_DLG_DE 287 -#define TM_STORYFRAME_CREAM_UNLOCK_3_DLG_DE 288 -#define TM_STORYFRAME_CREAM_UNLOCKED_DE 289 -#define TM_STORYFRAME_CREAM_UNLOCK_0_DLG_IT 290 -#define TM_STORYFRAME_CREAM_UNLOCK_1_DLG_IT 291 -#define TM_STORYFRAME_CREAM_UNLOCK_2_DLG_IT 292 -#define TM_STORYFRAME_CREAM_UNLOCK_3_DLG_IT 293 -#define TM_STORYFRAME_CREAM_UNLOCKED_IT 294 -#define TM_STORYFRAME_CREAM_UNLOCK_0_DLG_ES 295 -#define TM_STORYFRAME_CREAM_UNLOCK_1_DLG_ES 296 -#define TM_STORYFRAME_CREAM_UNLOCK_2_DLG_ES 297 -#define TM_STORYFRAME_CREAM_UNLOCK_3_DLG_ES 298 -#define TM_STORYFRAME_CREAM_UNLOCKED_ES 299 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_0 300 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_1 301 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_2 302 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_3 303 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_0_DLG_JP 304 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_1_DLG_JP 305 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_2_DLG_JP 306 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_3_DLG_JP 307 -#define TM_STORYFRAME_KNUCKLES_UNLOCKED_JP 308 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_0_DLG_EN 309 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_1_DLG_EN 310 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_2_DLG_EN 311 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_3_DLG_EN 312 -#define TM_STORYFRAME_KNUCKLES_UNLOCKED_EN 313 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_0_DLG_FR 314 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_1_DLG_FR 315 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_2_DLG_FR 316 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_3_DLG_FR 317 -#define TM_STORYFRAME_KNUCKLES_UNLOCKED_FR 318 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_0_DLG_DE 319 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_1_DLG_DE 320 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_2_DLG_DE 321 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_3_DLG_DE 322 -#define TM_STORYFRAME_KNUCKLES_UNLOCKED_DE 323 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_0_DLG_IT 324 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_1_DLG_IT 325 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_2_DLG_IT 326 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_3_DLG_IT 327 -#define TM_STORYFRAME_KNUCKLES_UNLOCKED_IT 328 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_0_DLG_ES 329 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_1_DLG_ES 330 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_2_DLG_ES 331 -#define TM_STORYFRAME_KNUCKLES_UNLOCK_3_DLG_ES 332 -#define TM_STORYFRAME_KNUCKLES_UNLOCKED_ES 333 -#define TM_STORYFRAME_TAILS_UNLOCK_0 334 -#define TM_STORYFRAME_TAILS_UNLOCK_1 335 -#define TM_STORYFRAME_TAILS_UNLOCK_2 336 -#define TM_STORYFRAME_TAILS_UNLOCK_3 337 -#define TM_STORYFRAME_TAILS_UNLOCK_0_DLG_JP 338 -#define TM_STORYFRAME_TAILS_UNLOCK_1_DLG_JP 339 -#define TM_STORYFRAME_TAILS_UNLOCK_2_DLG_JP 340 -#define TM_STORYFRAME_TAILS_UNLOCK_3_DLG_JP 341 -#define TM_STORYFRAME_TAILS_UNLOCKED_JP 342 -#define TM_STORYFRAME_TAILS_UNLOCK_0_DLG_EN 343 -#define TM_STORYFRAME_TAILS_UNLOCK_1_DLG_EN 344 -#define TM_STORYFRAME_TAILS_UNLOCK_2_DLG_EN 345 -#define TM_STORYFRAME_TAILS_UNLOCK_3_DLG_EN 346 -#define TM_STORYFRAME_TAILS_UNLOCKED_EN 347 -#define TM_STORYFRAME_TAILS_UNLOCK_0_DLG_FR 348 -#define TM_STORYFRAME_TAILS_UNLOCK_1_DLG_FR 349 -#define TM_STORYFRAME_TAILS_UNLOCK_2_DLG_FR 350 -#define TM_STORYFRAME_TAILS_UNLOCK_3_DLG_FR 351 -#define TM_STORYFRAME_TAILS_UNLOCKED_FR 352 -#define TM_STORYFRAME_TAILS_UNLOCK_0_DLG_DE 353 -#define TM_STORYFRAME_TAILS_UNLOCK_1_DLG_DE 354 -#define TM_STORYFRAME_TAILS_UNLOCK_2_DLG_DE 355 -#define TM_STORYFRAME_TAILS_UNLOCK_3_DLG_DE 356 -#define TM_STORYFRAME_TAILS_UNLOCKED_DE 357 -#define TM_STORYFRAME_TAILS_UNLOCK_0_DLG_IT 358 -#define TM_STORYFRAME_TAILS_UNLOCK_1_DLG_IT 359 -#define TM_STORYFRAME_TAILS_UNLOCK_2_DLG_IT 360 -#define TM_STORYFRAME_TAILS_UNLOCK_3_DLG_IT 361 -#define TM_STORYFRAME_TAILS_UNLOCKED_IT 362 -#define TM_STORYFRAME_TAILS_UNLOCK_0_DLG_ES 363 -#define TM_STORYFRAME_TAILS_UNLOCK_1_DLG_ES 364 -#define TM_STORYFRAME_TAILS_UNLOCK_2_DLG_ES 365 -#define TM_STORYFRAME_TAILS_UNLOCK_3_DLG_ES 366 -#define TM_STORYFRAME_TAILS_UNLOCKED_ES 367 -#define TM_REGULAR_FINAL_BOSS 368 -#define TM_UNKNOWN_STARS 369 -#define TM_SKY_CANYON_CLOUDS_FOREGROUND 370 -#define TM_371 371 -#define TM_EXTRA_BOSS_BACKGROUND 372 -#define TM_CHARACTER_SELECT_BACKGROUND_0 373 -#define TM_CHARACTER_SELECT_BACKGROUND_1 374 -#define TM_EXTRA_BOSS_COCKPIT 375 -#define TM_EXTRA_BOSS_BACKGROUND_COPY 376 -#define TM_EXTRA_BOSS_BACKGROUND_COPY 376 -#define TM_CUTSCENE_VANILLA_KIDNAPPED_FULL_MAP 377 -#define TM_CUTSCENE_VANILLA_KIDNAPPED_FULL_MAP_COPY 378 -#define TM_CUTSCENE_VANILLA_KIDNAPPED_SUPER_SONIC_ART 379 -#define TM_REGULAR_FINAL_BOSS_BUILDING_BG 380 -#define TM_COUNT 381 - -#endif // GUARD_TILEMAPS