From 218cde7ff9f23dbab51b2b952dbdf632666c0011 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Fri, 29 Nov 2024 18:16:27 +0000 Subject: [PATCH 01/11] first test --- .devcontainer/Dockerfile | 20 +++++++++++++++++--- Makefile | 8 ++++++-- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 8e03ecf80..580bfd77a 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -2,10 +2,24 @@ # [Choice] Ubuntu version (use ubuntu-22.04 or ubuntu-18.04 on local arm64/Apple Silicon): ubuntu-22.04, ubuntu-20.04, ubuntu-18.04 ARG VARIANT -FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT} +FROM mcr.microsoft.com/vscode/devcontainers/base:0-ubuntu-22.04 RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ - && apt-get -y install --no-install-recommends binutils-arm-none-eabi gcc-arm-none-eabi libpng-dev build-essential clang-format-13 xorg-dev libsdl2-dev gcc-mingw-w64 + && apt-get -y install --no-install-recommends binutils-arm-none-eabi \ + gcc-arm-none-eabi libpng-dev build-essential clang-format-13 xorg-dev \ + libsdl2-dev gcc-mingw-w64 texinfo flex bison gettext libgsl-dev libgmp3-dev \ + libmpfr-dev libmpc-dev zlib1g-dev autopoint cmake autoconf patch WORKDIR /deps -RUN git clone https://github.com/pret/agbcc.git && cd agbcc && ./build.sh +RUN git clone https://github.com/SAT-R/agbcc.git && cd agbcc && ./build.sh + +ENV PS2DEV=/usr/local/ps2dev + +RUN mkdir -p $PS2DEV && chown -R $USER: $PS2DEV + +ENV PS2DEV=/usr/local/ps2dev +ENV PS2SDK=$PS2DEV/ps2sdk +ENV GSKIT=$PS2DEV/gsKit +ENV PATH=$PATH:$PS2DEV/bin:$PS2DEV/ee/bin:$PS2DEV/iop/bin:$PS2DEV/dvp/bin:$PS2SDK/bin + +RUN git clone https://github.com/ps2dev/ps2dev && cd ps2dev && ./build-all.sh diff --git a/Makefile b/Makefile index 632d08a97..e18971c0a 100644 --- a/Makefile +++ b/Makefile @@ -30,12 +30,16 @@ ifeq ($(PLATFORM),gba) PREFIX := arm-none-eabi- else ifeq ($(CPU_ARCH),i386) ifeq ($(PLATFORM),sdl_win32) - TOOLCHAIN := /usr/i686-w64-mingw32/ PREFIX := i686-w64-mingw32- else ifeq ($(PLATFORM),win32) - TOOLCHAIN := /usr/i686-w64-mingw32/ PREFIX := i686-w64-mingw32- endif +else ifeq ($(CPU_ARCH),EE) + ifeq ($(PLATFORM),sdl_ps2) + PREFIX := mips64r5900el-ps2-elf- + else + $(error Unsupported CPU arch for platform '$(CPU_ARCH)', '$(PLATFORM)') + endif else ifneq ($(PLATFORM),sdl) $(error Unsupported CPU arch for platform '$(CPU_ARCH)', '$(PLATFORM)') From 136e4b6a0e26c6724c7ffcc0ddfc654065ac62ee Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Sat, 30 Nov 2024 01:10:32 +0000 Subject: [PATCH 02/11] running without sdl --- Makefile | 12 +- config.mk | 3 + include/game/stage/player.h | 2 +- src/game/stage/player.c | 16 +- src/platform/ps2/ps2.c | 2143 +++++++++++++++++++++++++ src/platform/shared/audio/cgb_audio.c | 1 + 6 files changed, 2167 insertions(+), 10 deletions(-) create mode 100644 src/platform/ps2/ps2.c diff --git a/Makefile b/Makefile index e18971c0a..4e12c7873 100644 --- a/Makefile +++ b/Makefile @@ -112,6 +112,10 @@ else ifeq ($(PLATFORM),sdl) CC1FLAGS += -Wno-parentheses-equality -Wno-unused-value CPPFLAGS += -D TITLE_BAR=$(BUILD_NAME).$(PLATFORM) -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 $(shell sdl2-config --cflags) + else ifeq ($(PLATFORM),sdl_ps2) + CC1FLAGS += -Wno-parentheses-equality -Wno-unused-value + CPPFLAGS += -I$(PS2SDK)/common/include -I$(PS2SDK)/ee/include -I$(PS2SDK)/ports/include $(shell sdl2-config --cflags) + CPPFLAGS += -D TITLE_BAR=$(BUILD_NAME).$(PLATFORM) -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 -D_EE -DPS2 -D__PS2__ else ifeq ($(PLATFORM),sdl_win32) CPPFLAGS += -D TITLE_BAR=$(BUILD_NAME).$(PLATFORM) -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 $(SDL_MINGW_FLAGS) else ifeq ($(PLATFORM),win32) @@ -266,6 +270,8 @@ ifeq ($(PLATFORM),gba) C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/*") else ifeq ($(PLATFORM),sdl) C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*") +else ifeq ($(PLATFORM),sdl_ps2) +C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/pret_sdl/*") else ifeq ($(PLATFORM),sdl_win32) C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*") else ifeq ($(PLATFORM),win32) @@ -427,7 +433,7 @@ PROCESSED_LDSCRIPT := $(OBJ_DIR)/$(LDSCRIPT) $(PROCESSED_LDSCRIPT): $(LDSCRIPT) $(CPP) -P $(CPPFLAGS) $(LDSCRIPT) > $(PROCESSED_LDSCRIPT) -$(ELF): $(OBJS) $(PROCESSED_LDSCRIPT) libagbsyscall +$(ELF): $(OBJS) $(PROCESSED_LDSCRIPT) ifeq ($(PLATFORM),gba) @echo "$(LD) -T $(LDSCRIPT) -Map $(MAP) " @cd $(OBJ_DIR) && $(LD) -A CPU_ARCH -T $(LDSCRIPT) -Map "$(ROOT_DIR)/$(MAP)" $(OBJS_REL) "$(ROOT_DIR)/tools/agbcc/lib/libgcc.a" "$(ROOT_DIR)/tools/agbcc/lib/libc.a" -L$(ROOT_DIR)/libagbsyscall -lagbsyscall -o $(ROOT_DIR)/$@ @@ -438,6 +444,8 @@ ifeq ($(PLATFORM),sdl) @cd $(OBJ_DIR) && $(CC1) $(OBJS_REL) $(shell sdl2-config --cflags --libs) $(LINKER_MAP_FLAGS) -o $(ROOT_DIR)/$@ 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 ifeq ($(PLATFORM),sdl_ps2) + @cd $(OBJ_DIR) && $(CC1) $(OBJS_REL) $(LINKER_MAP_FLAGS) -T$(PS2SDK)/ee/startup/linkfile -L$(PS2SDK)/common/lib -L$(PS2SDK)/ee/lib -L$(PS2DEV)/gsKit/lib -L$(PS2SDK)/ports/lib -Wl,-zmax-page-size=128 -o $(ROOT_DIR)/$@ else @cd $(OBJ_DIR) && $(CC1) -mwin32 $(OBJS_REL) -L$(ROOT_DIR)/libagbsyscall -lagbsyscall -lkernel32 -o $(ROOT_DIR)/$@ -Xlinker -Map "$(ROOT_DIR)/$(MAP)" endif @@ -515,6 +523,8 @@ europe: ; @$(MAKE) GAME_REGION=EUROPE sdl: ; @$(MAKE) PLATFORM=sdl +sdl_ps2: ; @$(MAKE) CPU_ARCH=EE PLATFORM=sdl_ps2 + sdl_win32: SDL2.dll $(SDL_MINGW_LIB) @$(MAKE) PLATFORM=sdl_win32 CPU_ARCH=i386 diff --git a/config.mk b/config.mk index 30782695f..80f86a8b8 100644 --- a/config.mk +++ b/config.mk @@ -18,6 +18,9 @@ ifeq ($(CPU_ARCH),arm) else ifeq ($(CPU_ARCH),i386) THUMB_SUPPORT ?= 0 MIDI_COMMENTS := "x86" +else ifeq ($(CPU_ARCH),EE) + THUMB_SUPPORT ?= 0 + MIDI_COMMENTS := "x86" else $(error unknown arch: $(CPU_ARCH)) endif diff --git a/include/game/stage/player.h b/include/game/stage/player.h index 29ecea13f..1bbd7e16f 100644 --- a/include/game/stage/player.h +++ b/include/game/stage/player.h @@ -39,7 +39,7 @@ void Player_DisableInputAndBossTimer_FinalBoss(void); void SetStageSpawnPos(u32 character, u32 level, u32 p2, Player *player); void CallSetStageSpawnPos(u32 character, u32 level, u32 p2, Player *p); -s32 sub_8029B88(Player *player, u8 *p1, int *out); +s32 sub_8029B88(Player *player, u8 *p1, s32 *out); s32 sub_8029AC0(Player *player, u8 *p1, s32 *out); s32 sub_8029B0C(Player *player, u8 *p1, s32 *out); diff --git a/src/game/stage/player.c b/src/game/stage/player.c index f52301cd4..7e61cc537 100644 --- a/src/game/stage/player.c +++ b/src/game/stage/player.c @@ -6314,8 +6314,8 @@ s32 sub_8029A28(Player *p, u8 *p1, s32 *out) u8 dummy; // TODO: Why is dummyInt unused? - int dummyInt; - int p1Value; + s32 dummyInt; + s32 p1Value; if (p1 == NULL) p1 = &dummy; @@ -6377,8 +6377,8 @@ s32 sub_8029AC0(Player *p, u8 *p1, s32 *out) u8 dummy; // TODO: Why is dummyInt unused? - int dummyInt; - int p1Value; + s32 dummyInt; + s32 p1Value; if (p1 == NULL) p1 = &dummy; @@ -6409,8 +6409,8 @@ s32 sub_8029B0C(Player *p, u8 *p1, s32 *out) u8 dummy; // TODO: Why is dummyInt unused? - int dummyInt; - int p1Value; + s32 dummyInt; + s32 p1Value; if (p1 == NULL) p1 = &dummy; @@ -6434,7 +6434,7 @@ s32 sub_8029B0C(Player *p, u8 *p1, s32 *out) return result; } -s32 sub_8029B58(Player *p, u8 *p1, int *out) +s32 sub_8029B58(Player *p, u8 *p1, s32 *out) { s32 result; @@ -6447,7 +6447,7 @@ s32 sub_8029B58(Player *p, u8 *p1, int *out) return result; } -s32 sub_8029B88(Player *p, u8 *p1, int *out) +s32 sub_8029B88(Player *p, u8 *p1, s32 *out) { s32 result; diff --git a/src/platform/ps2/ps2.c b/src/platform/ps2/ps2.c new file mode 100644 index 000000000..22f4de80c --- /dev/null +++ b/src/platform/ps2/ps2.c @@ -0,0 +1,2143 @@ +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#include +#endif + +// #include + +#include "global.h" +#include "core.h" +#include "gba/defines.h" +#include "gba/io_reg.h" +#include "gba/types.h" +#include "lib/agb_flash/flash_internal.h" +#define DMA_DEST_MASK 0x0060 +#define DMA_SRC_MASK 0x0180 + +#if ENABLE_AUDIO +#include "platform/shared/audio/cgb_audio.h" +#endif + +#ifndef TILE_WIDTH +#define TILE_WIDTH 8 +#endif + +extern IntrFunc gIntrTable[16]; + +#if 0 +extern u16 INTR_CHECK; +extern void *INTR_VECTOR; +extern unsigned char REG_BASE[0x400]; +extern unsigned char PLTT[PLTT_SIZE]; +extern unsigned char VRAM_[VRAM_SIZE]; +extern unsigned char OAM[OAM_SIZE]; +extern unsigned char FLASH_BASE[131072]; +#endif +extern uint8_t EWRAM_START[EWRAM_SIZE]; +extern uint8_t IWRAM_START[IWRAM_SIZE]; +// TODO: REG_BASE needs to be u8, because of the address macro definitions +extern uint8_t REG_BASE[IO_SIZE]; +extern uint16_t PLTT[PLTT_SIZE / sizeof(uint16_t)]; +extern uint8_t VRAM[VRAM_SIZE]; +extern uint8_t OAM[OAM_SIZE]; +extern uint8_t FLASH_BASE[FLASH_ROM_SIZE_1M * SECTORS_PER_BANK]; +ALIGNED(256) uint16_t gameImage[DISPLAY_WIDTH * DISPLAY_HEIGHT]; +#if ENABLE_VRAM_VIEW +#define VRAM_VIEW_WIDTH (32 * TILE_WIDTH) +#define VRAM_VIEW_HEIGHT (((VRAM_SIZE / TILE_SIZE_4BPP) / 32) * TILE_WIDTH) +uint16_t vramBuffer[VRAM_VIEW_WIDTH * VRAM_VIEW_HEIGHT]; +uint8_t vramPalIdBuffer[(VRAM_VIEW_WIDTH / TILE_WIDTH) * (VRAM_VIEW_HEIGHT / TILE_WIDTH)]; +#endif + +#define DMA_COUNT 4 + +struct DMATransfer { + union { + const void *src; + const u16 *src16; + const u32 *src32; + }; + union { + void *dst; + vu16 *dst16; + vu32 *dst32; + }; + u32 size; + u16 control; +} DMAList[DMA_COUNT]; + +enum { DMA_NOW, DMA_VBLANK, DMA_HBLANK, DMA_SPECIAL }; + +struct scanlineData { + uint16_t layers[4][DISPLAY_WIDTH]; + uint16_t spriteLayers[4][DISPLAY_WIDTH]; + uint16_t bgcnts[4]; + uint16_t winMask[DISPLAY_WIDTH]; + // priority bookkeeping + char bgtoprio[4]; // background to priority + char prioritySortedBgs[4][4]; + char prioritySortedBgsCount[4]; +}; + +struct bgPriority { + char priority; + char subPriority; +}; + +// SDL_Thread *mainLoopThread; +// SDL_Window *sdlWindow; +// SDL_Renderer *sdlRenderer; +// SDL_Texture *sdlTexture; +#if ENABLE_VRAM_VIEW +SDL_Window *vramWindow; +SDL_Renderer *vramRenderer; +SDL_Texture *vramTexture; +#endif +#define INITIAL_VIDEO_SCALE 1 +unsigned int videoScale = INITIAL_VIDEO_SCALE; +unsigned int preFullscreenVideoScale = INITIAL_VIDEO_SCALE; +// SDL_sem *vBlankSemaphore; +// SDL_atomic_t isFrameAvailable; +bool speedUp = false; +bool videoScaleChanged = false; +bool isRunning = true; +bool paused = false; +bool stepOneFrame = false; +double simTime = 0; +double lastGameTime = 0; +double curGameTime = 0; +double fixedTimestep = 1.0 / 60.0; // 16.666667ms +double timeScale = 1.0; +// struct SiiRtcInfo internalClock; + +static FILE *sSaveFile = NULL; + +extern void AgbMain(void); +void DoSoftReset(void) {}; + +int DoMain(void *param); +void ProcessSDLEvents(void); +// void VDraw(SDL_Texture *texture); +// void VramDraw(SDL_Texture *texture); + +static void ReadSaveFile(char *path); +static void StoreSaveFile(void); +static void CloseSaveFile(void); + +static void UpdateInternalClock(void); +static void RunDMAs(u32 type); + +u16 Platform_GetKeyInput(void); + +#ifdef _WIN32 +void *Platform_malloc(int numBytes) { return HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY, numBytes); } +void Platform_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); } +#endif + +int main(int argc, char **argv) +{ + // // Open an output console on Windows + // #ifdef _WIN32 + // AllocConsole(); + // AttachConsole(GetCurrentProcessId()); + // freopen("CON", "w", stdout); + // #endif + + // ReadSaveFile("sa2.sav"); + + // if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) { + // fprintf(stderr, "SDL could not initialize! SDL_Error: %s\n", SDL_GetError()); + // return 1; + // } + + // #ifdef TITLE_BAR + // const char *title = STR(TITLE_BAR); + // #else + // const char *title = "SAT-R sa2"; + // #endif + + // sdlWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, DISPLAY_WIDTH * videoScale, + // DISPLAY_HEIGHT * videoScale, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); + // if (sdlWindow == NULL) { + // fprintf(stderr, "Window could not be created! SDL_Error: %s\n", SDL_GetError()); + // return 1; + // } + + // #if ENABLE_VRAM_VIEW + // int mainWindowX; + // int mainWindowWidth; + // SDL_GetWindowPosition(sdlWindow, &mainWindowX, NULL); + // SDL_GetWindowSize(sdlWindow, &mainWindowWidth, NULL); + // int vramWindowX = mainWindowX + mainWindowWidth; + // u16 vramWindowWidth = VRAM_VIEW_WIDTH; + // u16 vramWindowHeight = VRAM_VIEW_HEIGHT; + // vramWindow = SDL_CreateWindow("VRAM View", vramWindowX, SDL_WINDOWPOS_CENTERED, vramWindowWidth, vramWindowHeight, + // SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); + // if (vramWindow == NULL) { + // fprintf(stderr, "VRAM Window could not be created! SDL_Error: %s\n", SDL_GetError()); + // return 1; + // } + // #endif + + // sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_PRESENTVSYNC); + // if (sdlRenderer == NULL) { + // fprintf(stderr, "Renderer could not be created! SDL_Error: %s\n", SDL_GetError()); + // return 1; + // } + + // #if ENABLE_VRAM_VIEW + // vramRenderer = SDL_CreateRenderer(vramWindow, -1, SDL_RENDERER_PRESENTVSYNC); + // if (vramRenderer == NULL) { + // fprintf(stderr, "VRAM Renderer could not be created! SDL_Error: %s\n", SDL_GetError()); + // return 1; + // } + // #endif + + // SDL_SetRenderDrawColor(sdlRenderer, 255, 255, 255, 255); + // SDL_RenderClear(sdlRenderer); + // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); + // SDL_RenderSetLogicalSize(sdlRenderer, DISPLAY_WIDTH, DISPLAY_HEIGHT); + // #if ENABLE_VRAM_VIEW + // SDL_SetRenderDrawColor(vramRenderer, 0, 0, 0, 255); + // SDL_RenderClear(vramRenderer); + // SDL_RenderSetLogicalSize(vramRenderer, vramWindowWidth, vramWindowHeight); + // #endif + + // sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ABGR1555, SDL_TEXTUREACCESS_STREAMING, DISPLAY_WIDTH, + // DISPLAY_HEIGHT); if (sdlTexture == NULL) { + // fprintf(stderr, "Texture could not be created! SDL_Error: %s\n", SDL_GetError()); + // return 1; + // } + + // #if ENABLE_VRAM_VIEW + // vramTexture = SDL_CreateTexture(vramRenderer, SDL_PIXELFORMAT_ABGR1555, SDL_TEXTUREACCESS_STREAMING, vramWindowWidth, + // vramWindowHeight); if (vramTexture == NULL) { + // fprintf(stderr, "Texture could not be created! SDL_Error: %s\n", SDL_GetError()); + // return 1; + // } + // #endif + + // simTime = curGameTime = lastGameTime = SDL_GetPerformanceCounter(); + + // isFrameAvailable.value = 0; + // vBlankSemaphore = SDL_CreateSemaphore(0); + // if (vBlankSemaphore == NULL) { + // SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to create Semaphore:\n %s", SDL_GetError()); + // } + + // #if ENABLE_AUDIO + // SDL_AudioSpec want; + + // SDL_memset(&want, 0, sizeof(want)); /* or SDL_zero(want) */ + // want.freq = 48000; + // want.format = AUDIO_F32; + // want.channels = 2; + // want.samples = (want.freq / 60); + cgb_audio_init(48000); + + // if (SDL_OpenAudio(&want, 0) < 0) + // SDL_Log("Failed to open audio: %s", SDL_GetError()); + // else { + // if (want.format != AUDIO_F32) /* we let this one thing change. */ + // SDL_Log("We didn't get Float32 audio format."); + // SDL_PauseAudio(0); + // } + // #endif + + // VDraw(sdlTexture); + // #if ENABLE_VRAM_VIEW + // VramDraw(vramTexture); + // #endif + // // Prevent the multiplayer screen from being drawn ( see core.c:GameInit() ) + // REG_RCNT = 0x8000; + + // mainLoopThread = SDL_CreateThread(DoMain, "AgbMain", NULL); + + // double accumulator = 0.0; + + // #if 0 + // memset(&internalClock, 0, sizeof(internalClock)); + // internalClock.status = SIIRTCINFO_24HOUR; + // UpdateInternalClock(); + // #endif + + // REG_KEYINPUT = 0x3FF; + + // while (isRunning) { + // ProcessSDLEvents(); + + // if (!paused || stepOneFrame) { + // double dt = fixedTimestep / timeScale; // TODO: Fix speedup + // double deltaTime = 0; + + // curGameTime = SDL_GetPerformanceCounter(); + // if (stepOneFrame) { + // deltaTime = dt; + // } else { + // deltaTime = (double)((curGameTime - lastGameTime) / (double)SDL_GetPerformanceFrequency()); + // if (deltaTime > (dt * 5)) + // deltaTime = dt * 5; + // } + // lastGameTime = curGameTime; + + // accumulator += deltaTime; + + // while (accumulator >= dt) { + // REG_KEYINPUT = KEYS_MASK ^ Platform_GetKeyInput(); + // if (SDL_AtomicGet(&isFrameAvailable)) { + // VDraw(sdlTexture); + // SDL_AtomicSet(&isFrameAvailable, 0); + + // REG_DISPSTAT |= INTR_FLAG_VBLANK; + + // // TODO(Jace): I think this should be DMA_VBLANK. + // // If not, and it is HBLANK instead, add a note here, why it is! + // RunDMAs(DMA_VBLANK); + + // if (REG_DISPSTAT & DISPSTAT_VBLANK_INTR) + // gIntrTable[INTR_INDEX_VBLANK](); + // REG_DISPSTAT &= ~INTR_FLAG_VBLANK; + + // SDL_SemPost(vBlankSemaphore); + + // accumulator -= dt; + // } + // } + + // if (paused && stepOneFrame) { + // stepOneFrame = false; + // } + // } + + // SDL_RenderClear(sdlRenderer); + // SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); + + // #if ENABLE_VRAM_VIEW + // VramDraw(vramTexture); + // SDL_RenderClear(vramRenderer); + // SDL_RenderCopy(vramRenderer, vramTexture, NULL, NULL); + // #endif + // if (videoScaleChanged) { + // SDL_SetWindowSize(sdlWindow, DISPLAY_WIDTH * videoScale, DISPLAY_HEIGHT * videoScale); + // videoScaleChanged = false; + // } + // SDL_RenderPresent(sdlRenderer); + // #if ENABLE_VRAM_VIEW + // SDL_RenderPresent(vramRenderer); + // #endif + // } + + // // StoreSaveFile(); + // CloseSaveFile(); + + // SDL_DestroyWindow(sdlWindow); + // SDL_Quit(); + // return 0; + + REG_RCNT = 0x8000; + AgbMain(); + + return 0; +} + +static void ReadSaveFile(char *path) +{ + // Check whether the saveFile exists, and create it if not + sSaveFile = fopen(path, "r+b"); + if (sSaveFile == NULL) { + sSaveFile = fopen(path, "w+b"); + } + + fseek(sSaveFile, 0, SEEK_END); + int fileSize = ftell(sSaveFile); + fseek(sSaveFile, 0, SEEK_SET); + + // Only read as many bytes as fit inside the buffer + // or as many bytes as are in the file + int bytesToRead = (fileSize < sizeof(FLASH_BASE)) ? fileSize : sizeof(FLASH_BASE); + + int bytesRead = fread(FLASH_BASE, 1, bytesToRead, sSaveFile); + + // Fill the buffer if the savefile was just created or smaller than the buffer itself + for (int i = bytesRead; i < sizeof(FLASH_BASE); i++) { + FLASH_BASE[i] = 0xFF; + } +} + +static void StoreSaveFile() +{ + if (sSaveFile != NULL) { + fseek(sSaveFile, 0, SEEK_SET); + fwrite(FLASH_BASE, 1, sizeof(FLASH_BASE), sSaveFile); + } +} + +void Platform_StoreSaveFile(void) { StoreSaveFile(); } + +static void CloseSaveFile() +{ + if (sSaveFile != NULL) { + fclose(sSaveFile); + } +} + +// Key mappings +#define KEY_A_BUTTON SDLK_c +#define KEY_B_BUTTON SDLK_x +#define KEY_START_BUTTON SDLK_RETURN +#define KEY_SELECT_BUTTON SDLK_BACKSLASH +#define KEY_L_BUTTON SDLK_s +#define KEY_R_BUTTON SDLK_d +#define KEY_DPAD_UP SDLK_UP +#define KEY_DPAD_DOWN SDLK_DOWN +#define KEY_DPAD_LEFT SDLK_LEFT +#define KEY_DPAD_RIGHT SDLK_RIGHT + +#define HANDLE_KEYUP(key) \ + case KEY_##key: \ + keys &= ~key; \ + break; + +#define HANDLE_KEYDOWN(key) \ + case KEY_##key: \ + keys |= key; \ + break; + +static u16 keys; + +u32 fullScreenFlags = 0; +// static SDL_DisplayMode sdlDispMode = { 0 }; + +void Platform_QueueAudio(const void *data, uint32_t bytesCount) +{ + // Reset the audio buffer if we are 10 frames out of sync + // If this happens it suggests there was some OS level lag + // in playing audio. The queue length should remain stable at < 10 otherwise + // if (SDL_GetQueuedAudioSize(1) > (bytesCount * 10)) { + // SDL_ClearQueuedAudio(1); + // } + + // SDL_QueueAudio(1, data, bytesCount); + // printf("Queueing %d\n, QueueSize %d\n", bytesCount, SDL_GetQueuedAudioSize(1)); +} + +void ProcessSDLEvents(void) +{ + // SDL_Event event; + + // while (SDL_PollEvent(&event)) { + // SDL_Keycode keyCode = event.key.keysym.sym; + // Uint16 keyMod = event.key.keysym.mod; + + // switch (event.type) { + // case SDL_QUIT: + // isRunning = false; + // break; + // case SDL_KEYUP: + // switch (event.key.keysym.sym) { + // HANDLE_KEYUP(A_BUTTON) + // HANDLE_KEYUP(B_BUTTON) + // HANDLE_KEYUP(START_BUTTON) + // HANDLE_KEYUP(SELECT_BUTTON) + // HANDLE_KEYUP(L_BUTTON) + // HANDLE_KEYUP(R_BUTTON) + // HANDLE_KEYUP(DPAD_UP) + // HANDLE_KEYUP(DPAD_DOWN) + // HANDLE_KEYUP(DPAD_LEFT) + // HANDLE_KEYUP(DPAD_RIGHT) + // case SDLK_SPACE: + // if (speedUp) { + // speedUp = false; + // timeScale = 1.0; + // SDL_ClearQueuedAudio(1); + // SDL_PauseAudio(0); + // } + // break; + // } + // break; + // case SDL_KEYDOWN: + // if (keyCode == SDLK_RETURN && (keyMod & KMOD_ALT)) { + // fullScreenFlags ^= SDL_WINDOW_FULLSCREEN_DESKTOP; + // if (fullScreenFlags & SDL_WINDOW_FULLSCREEN_DESKTOP) { + // SDL_GetWindowDisplayMode(sdlWindow, &sdlDispMode); + // preFullscreenVideoScale = videoScale; + // } else { + // SDL_SetWindowDisplayMode(sdlWindow, &sdlDispMode); + // videoScale = preFullscreenVideoScale; + // } + // SDL_SetWindowFullscreen(sdlWindow, fullScreenFlags); + + // SDL_SetWindowSize(sdlWindow, DISPLAY_WIDTH * videoScale, DISPLAY_HEIGHT * videoScale); + // videoScaleChanged = FALSE; + // } else + // switch (event.key.keysym.sym) { + // HANDLE_KEYDOWN(A_BUTTON) + // HANDLE_KEYDOWN(B_BUTTON) + // HANDLE_KEYDOWN(START_BUTTON) + // HANDLE_KEYDOWN(SELECT_BUTTON) + // HANDLE_KEYDOWN(L_BUTTON) + // HANDLE_KEYDOWN(R_BUTTON) + // HANDLE_KEYDOWN(DPAD_UP) + // HANDLE_KEYDOWN(DPAD_DOWN) + // HANDLE_KEYDOWN(DPAD_LEFT) + // HANDLE_KEYDOWN(DPAD_RIGHT) + // case SDLK_r: + // if (event.key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) { + // DoSoftReset(); + // } + // break; + // case SDLK_p: + // if (event.key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) { + // paused = !paused; + // } + // break; + // case SDLK_SPACE: + // if (!speedUp) { + // speedUp = true; + // timeScale = 5.0; + // SDL_PauseAudio(1); + // } + // break; + // case SDLK_F10: + // paused = true; + // stepOneFrame = true; + // break; + // } + // break; + // case SDL_WINDOWEVENT: + // if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { + // unsigned int w = event.window.data1; + // unsigned int h = event.window.data2; + + // videoScale = 0; + // if (w / DISPLAY_WIDTH > videoScale) + // videoScale = w / DISPLAY_WIDTH; + // if (h / DISPLAY_HEIGHT > videoScale) + // videoScale = h / DISPLAY_HEIGHT; + // if (videoScale < 1) + // videoScale = 1; + + // videoScaleChanged = true; + // } + // break; + // } + // } +} + +#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 + u16 gamepadKeys = GetXInputKeys(); + return (gamepadKeys != 0) ? gamepadKeys : keys; +#endif + + return keys; +} + +// BIOS function implementations are based on the VBA-M source code. + +static uint32_t CPUReadMemory(const void *src) { return *(uint32_t *)src; } + +static void CPUWriteMemory(void *dest, uint32_t val) { *(uint32_t *)dest = val; } + +static uint16_t CPUReadHalfWord(const void *src) { return *(uint16_t *)src; } + +static void CPUWriteHalfWord(void *dest, uint16_t val) { *(uint16_t *)dest = val; } + +static uint8_t CPUReadByte(const void *src) { return *(uint8_t *)src; } + +static void CPUWriteByte(void *dest, uint8_t val) { *(uint8_t *)dest = val; } + +static void RunDMAs(u32 type) +{ + for (int dmaNum = 0; dmaNum < DMA_COUNT; dmaNum++) { + struct DMATransfer *dma = &DMAList[dmaNum]; +#if !USE_NEW_DMA + // Regular GBA order + u32 dmaCntReg = (®_DMA0CNT)[dmaNum * 3]; +#else + // "64 bit" order + u32 dmaCntReg = (®_DMA0CNT)[dmaNum]; +#endif + if (!((dmaCntReg >> 16) & DMA_ENABLE)) { + dma->control &= ~DMA_ENABLE; + } + + if ((dma->control & DMA_ENABLE) && (((dma->control & DMA_START_MASK) >> 12) == type)) { + // printf("DMA%d src=%p, dest=%p, control=%d\n", dmaNum, dma->src, dma->dst, dma->control); + for (int i = 0; i < dma->size; i++) { + if ((dma->control) & DMA_32BIT) + *dma->dst32 = *dma->src32; + else + *dma->dst16 = *dma->src16; + + // process destination pointer changes + if (((dma->control) & DMA_DEST_MASK) == DMA_DEST_INC) { + if ((dma->control) & DMA_32BIT) + dma->dst32++; + else + dma->dst16++; + } else if (((dma->control) & DMA_DEST_MASK) == DMA_DEST_DEC) { + if ((dma->control) & DMA_32BIT) + dma->dst32--; + else + dma->dst16--; + } else if (((dma->control) & DMA_DEST_MASK) == DMA_DEST_RELOAD) // TODO + { + if ((dma->control) & DMA_32BIT) + dma->dst32++; + else + dma->dst16++; + } + + // process source pointer changes + if (((dma->control) & DMA_SRC_MASK) == DMA_SRC_INC) { + if ((dma->control) & DMA_32BIT) + dma->src32++; + else + dma->src16++; + } else if (((dma->control) & DMA_SRC_MASK) == DMA_SRC_DEC) { + if ((dma->control) & DMA_32BIT) + dma->src32--; + else + dma->src16--; + } + } + + if (dma->control & DMA_REPEAT) { + // NOTE: If we change dma->size anywhere above, we need to reset its value here. + + if (((dma->control) & DMA_DEST_MASK) == DMA_DEST_RELOAD) { +#if !USE_NEW_DMA + dma->dst = (void *)(uintptr_t)(®_DMA0DAD)[dmaNum * 3]; +#else + dma->dst = (void *)(uintptr_t)(®_DMA0DAD)[dmaNum]; +#endif + } + } else { + dma->control &= ~DMA_ENABLE; + } + } + } +} + +#if 0 +s32 Div(s32 num, s32 denom) +{ + if (denom != 0) { + return num / denom; + } else { + return 0; + } +} + +s32 Mod(s32 num, s32 denom) +{ + if (denom != 0) { + return num % denom; + } else { + return 0; + } +} +#endif + +int MultiBoot(struct MultiBootParam *mp) { return 0; } + +#ifdef DmaSet +#undef DmaSet +#endif +void DmaSet(int dmaNum, const void *src, void *dest, u32 control) +{ + if (dmaNum >= DMA_COUNT) { + fprintf(stderr, "DmaSet with invalid DMA number: dmaNum=%d, src=%p, dest=%p, control=%d\n", dmaNum, src, dest, control); + return; + } + +#if !USE_NEW_DMA + // Regular GBA order + (®_DMA0SAD)[dmaNum * 3] = (uintptr_t)src; + (®_DMA0DAD)[dmaNum * 3] = (uintptr_t)dest; + (®_DMA0CNT)[dmaNum * 3] = (size_t)control; +#else + // "64 bit" order + (®_DMA0SAD)[dmaNum] = (uintptr_t)src; + (®_DMA0DAD)[dmaNum] = (uintptr_t)dest; + (®_DMA0CNT)[dmaNum] = (size_t)control; +#endif + + struct DMATransfer *dma = &DMAList[dmaNum]; + dma->src = src; + dma->dst = dest; + dma->size = control & 0x1ffff; + dma->control = control >> 16; + + // printf("\nDMA%d: S:%p %p -> %p\n", dmaNum, src, dest, dest + dma->size); + + RunDMAs(DMA_NOW); +} + +void DmaStop(int dmaNum) +{ +#if !USE_NEW_DMA + (®_DMA0CNT)[dmaNum * 3] &= ~((DMA_ENABLE | DMA_START_MASK | DMA_DREQ_ON | DMA_REPEAT) << 16); +#else + (®_DMA0CNT)[dmaNum] &= ~((DMA_ENABLE | DMA_START_MASK | DMA_DREQ_ON | DMA_REPEAT) << 16); +#endif + + struct DMATransfer *dma = &DMAList[dmaNum]; + dma->control &= ~(DMA_ENABLE | DMA_START_MASK | DMA_DREQ_ON | DMA_REPEAT); +} + +void DmaWait(int dmaNum) { printf("DmaWait: %d\n", dmaNum); } + +// void DmaWait(int dmaNum) +// { +// vu32 *ctrlRegs = ®_DMA0CNT; +// #if !USE_NEW_DMA +// while (ctrlRegs[dmaNum * 3] & (DMA_ENABLE << 16)) +// ; +// #else +// while (ctrlRegs[dmaNum] & (DMA_ENABLE << 16)) +// ; +// #endif +// } + +void TestFunc(void) { } + +void CpuSet(const void *src, void *dst, u32 cnt) +{ + if (dst == NULL) { + TestFunc(); + printf("Attempted to CpuSet from %p to NULL\n", src); + return; + } + + int count = cnt & 0x1FFFFF; + + const u8 *source = src; + u8 *dest = dst; + + // 32-bit ? + if ((cnt >> 26) & 1) { + // assert(((uintptr_t)src & ~3) == (uintptr_t)src); + // assert(((uintptr_t)dst & ~3) == (uintptr_t)dst); + + // needed for 32-bit mode! + // source = (u8 *)((uint32_t )source & ~3); + // dest = (u8 *)((uint32_t )dest & ~3); + + // fill ? + if ((cnt >> 24) & 1) { + uint32_t value = CPUReadMemory(source); + while (count) { + CPUWriteMemory(dest, value); + dest += 4; + count--; + } + } else { + // copy + while (count) { + CPUWriteMemory(dest, CPUReadMemory(source)); + source += 4; + dest += 4; + count--; + } + } + } else { + // No align on 16-bit fill? + // assert(((uintptr_t)src & ~1) == (uintptr_t)src); + // assert(((uintptr_t)dst & ~1) == (uintptr_t)dst); + + // 16-bit fill? + if ((cnt >> 24) & 1) { + uint16_t value = CPUReadHalfWord(source); + while (count) { + CPUWriteHalfWord(dest, value); + dest += 2; + count--; + } + } else { + // copy + while (count) { + CPUWriteHalfWord(dest, CPUReadHalfWord(source)); + source += 2; + dest += 2; + count--; + } + } + } +} + +void CpuFastSet(const void *src, void *dst, u32 cnt) +{ + if (dst == NULL) { + puts("Attempted to CpuFastSet to NULL\n"); + return; + } + + int count = cnt & 0x1FFFFF; + + const u8 *source = src; + u8 *dest = dst; + + // source = (u8 *)((uint32_t )source & ~3); + // dest = (u8 *)((uint32_t )dest & ~3); + + // fill? + if ((cnt >> 24) & 1) { + uint32_t value = CPUReadMemory(source); + while (count > 0) { + // BIOS always transfers 32 bytes at a time + for (int i = 0; i < 8; i++) { + CPUWriteMemory(dest, value); + dest += 4; + } + count -= 8; + } + } else { + // copy + while (count > 0) { + // BIOS always transfers 32 bytes at a time + for (int i = 0; i < 8; i++) { + uint32_t value = CPUReadMemory(source); + CPUWriteMemory(dest, value); + source += 4; + dest += 4; + } + count -= 8; + } + } +} + +void LZ77UnCompVram(const void *src_, void *dest_) +{ + const u8 *src = (const u8 *)src_; + u8 *dest = dest_; + int destSize = (src[3] << 16) | (src[2] << 8) | src[1]; + int srcPos = 4; + int destPos = 0; + + for (;;) { + unsigned char flags = src[srcPos++]; + + for (int i = 0; i < 8; i++) { + if (flags & 0x80) { + int blockSize = (src[srcPos] >> 4) + 3; + int blockDistance = (((src[srcPos] & 0xF) << 8) | src[srcPos + 1]) + 1; + + srcPos += 2; + + int blockPos = destPos - blockDistance; + + // Some Ruby/Sapphire tilesets overflow. + if (destPos + blockSize > destSize) { + blockSize = destSize - destPos; + // fprintf(stderr, "Destination buffer overflow.\n"); + puts("Destination buffer overflow.\n"); + } + + if (blockPos < 0) + goto fail; + + for (int j = 0; j < blockSize; j++) + dest[destPos++] = dest[blockPos + j]; + } else { + if (destPos >= destSize) + goto fail; + + dest[destPos++] = src[srcPos++]; + } + + if (destPos == destSize) { + return; + } + + flags <<= 1; + } + } + +fail: + puts("Fatal error while decompressing LZ file.\n"); +} + +void LZ77UnCompWram(const void *src, void *dst) +{ + const uint8_t *source = src; + uint8_t *dest = dst; + + uint32_t header = CPUReadMemory(source); + source += 4; + + int len = header >> 8; + + while (len > 0) { + uint8_t d = CPUReadByte(source++); + + if (d) { + for (int i = 0; i < 8; i++) { + if (d & 0x80) { + uint16_t data = CPUReadByte(source++) << 8; + data |= CPUReadByte(source++); + int length = (data >> 12) + 3; + int offset = (data & 0x0FFF); + uint8_t *windowOffset = dest - offset - 1; + for (int i2 = 0; i2 < length; i2++) { + CPUWriteByte(dest++, CPUReadByte(windowOffset++)); + len--; + if (len == 0) + return; + } + } else { + CPUWriteByte(dest++, CPUReadByte(source++)); + len--; + if (len == 0) + return; + } + d <<= 1; + } + } else { + for (int i = 0; i < 8; i++) { + CPUWriteByte(dest++, CPUReadByte(source++)); + len--; + if (len == 0) + return; + } + } + } +} + +void RLUnCompWram(const void *src, void *dest) +{ + int remaining = CPUReadMemory(src) >> 8; + int blockHeader; + int block; + src += 4; + while (remaining > 0) { + blockHeader = CPUReadByte(src); + src++; + if (blockHeader & 0x80) // Compressed? + { + blockHeader &= 0x7F; + blockHeader += 3; + block = CPUReadByte(src); + src++; + while (blockHeader-- && remaining) { + remaining--; + CPUWriteByte(dest, block); + dest++; + } + } else // Uncompressed + { + blockHeader++; + while (blockHeader-- && remaining) { + remaining--; + u8 byte = CPUReadByte(src); + src++; + CPUWriteByte(dest, byte); + dest++; + } + } + } +} + +void RLUnCompVram(const void *src, void *dest) +{ + int remaining = CPUReadMemory(src) >> 8; + int padding = (4 - remaining) & 0x3; + int blockHeader; + int block; + int halfWord = 0; + src += 4; + while (remaining > 0) { + blockHeader = CPUReadByte(src); + src++; + if (blockHeader & 0x80) // Compressed? + { + blockHeader &= 0x7F; + blockHeader += 3; + block = CPUReadByte(src); + src++; + while (blockHeader-- && remaining) { + remaining--; + if ((uintptr_t)dest & 1) { + halfWord |= block << 8; + CPUWriteHalfWord((void *)((uintptr_t)dest ^ 1), halfWord); + } else + halfWord = block; + dest++; + } + } else // Uncompressed + { + blockHeader++; + while (blockHeader-- && remaining) { + remaining--; + u8 byte = CPUReadByte(src); + src++; + if ((uintptr_t)dest & 1) { + halfWord |= byte << 8; + CPUWriteHalfWord((void *)((uintptr_t)dest ^ 1), halfWord); + } else + halfWord = byte; + dest++; + } + } + } + if ((uintptr_t)dest & 1) { + padding--; + dest++; + } + for (; padding > 0; padding -= 2, dest += 2) + CPUWriteHalfWord(dest, 0); +} + +const s16 sineTable[256] + = { (s16)0x0000, (s16)0x0192, (s16)0x0323, (s16)0x04B5, (s16)0x0645, (s16)0x07D5, (s16)0x0964, (s16)0x0AF1, (s16)0x0C7C, (s16)0x0E05, + (s16)0x0F8C, (s16)0x1111, (s16)0x1294, (s16)0x1413, (s16)0x158F, (s16)0x1708, (s16)0x187D, (s16)0x19EF, (s16)0x1B5D, (s16)0x1CC6, + (s16)0x1E2B, (s16)0x1F8B, (s16)0x20E7, (s16)0x223D, (s16)0x238E, (s16)0x24DA, (s16)0x261F, (s16)0x275F, (s16)0x2899, (s16)0x29CD, + (s16)0x2AFA, (s16)0x2C21, (s16)0x2D41, (s16)0x2E5A, (s16)0x2F6B, (s16)0x3076, (s16)0x3179, (s16)0x3274, (s16)0x3367, (s16)0x3453, + (s16)0x3536, (s16)0x3612, (s16)0x36E5, (s16)0x37AF, (s16)0x3871, (s16)0x392A, (s16)0x39DA, (s16)0x3A82, (s16)0x3B20, (s16)0x3BB6, + (s16)0x3C42, (s16)0x3CC5, (s16)0x3D3E, (s16)0x3DAE, (s16)0x3E14, (s16)0x3E71, (s16)0x3EC5, (s16)0x3F0E, (s16)0x3F4E, (s16)0x3F84, + (s16)0x3FB1, (s16)0x3FD3, (s16)0x3FEC, (s16)0x3FFB, (s16)0x4000, (s16)0x3FFB, (s16)0x3FEC, (s16)0x3FD3, (s16)0x3FB1, (s16)0x3F84, + (s16)0x3F4E, (s16)0x3F0E, (s16)0x3EC5, (s16)0x3E71, (s16)0x3E14, (s16)0x3DAE, (s16)0x3D3E, (s16)0x3CC5, (s16)0x3C42, (s16)0x3BB6, + (s16)0x3B20, (s16)0x3A82, (s16)0x39DA, (s16)0x392A, (s16)0x3871, (s16)0x37AF, (s16)0x36E5, (s16)0x3612, (s16)0x3536, (s16)0x3453, + (s16)0x3367, (s16)0x3274, (s16)0x3179, (s16)0x3076, (s16)0x2F6B, (s16)0x2E5A, (s16)0x2D41, (s16)0x2C21, (s16)0x2AFA, (s16)0x29CD, + (s16)0x2899, (s16)0x275F, (s16)0x261F, (s16)0x24DA, (s16)0x238E, (s16)0x223D, (s16)0x20E7, (s16)0x1F8B, (s16)0x1E2B, (s16)0x1CC6, + (s16)0x1B5D, (s16)0x19EF, (s16)0x187D, (s16)0x1708, (s16)0x158F, (s16)0x1413, (s16)0x1294, (s16)0x1111, (s16)0x0F8C, (s16)0x0E05, + (s16)0x0C7C, (s16)0x0AF1, (s16)0x0964, (s16)0x07D5, (s16)0x0645, (s16)0x04B5, (s16)0x0323, (s16)0x0192, (s16)0x0000, (s16)0xFE6E, + (s16)0xFCDD, (s16)0xFB4B, (s16)0xF9BB, (s16)0xF82B, (s16)0xF69C, (s16)0xF50F, (s16)0xF384, (s16)0xF1FB, (s16)0xF074, (s16)0xEEEF, + (s16)0xED6C, (s16)0xEBED, (s16)0xEA71, (s16)0xE8F8, (s16)0xE783, (s16)0xE611, (s16)0xE4A3, (s16)0xE33A, (s16)0xE1D5, (s16)0xE075, + (s16)0xDF19, (s16)0xDDC3, (s16)0xDC72, (s16)0xDB26, (s16)0xD9E1, (s16)0xD8A1, (s16)0xD767, (s16)0xD633, (s16)0xD506, (s16)0xD3DF, + (s16)0xD2BF, (s16)0xD1A6, (s16)0xD095, (s16)0xCF8A, (s16)0xCE87, (s16)0xCD8C, (s16)0xCC99, (s16)0xCBAD, (s16)0xCACA, (s16)0xC9EE, + (s16)0xC91B, (s16)0xC851, (s16)0xC78F, (s16)0xC6D6, (s16)0xC626, (s16)0xC57E, (s16)0xC4E0, (s16)0xC44A, (s16)0xC3BE, (s16)0xC33B, + (s16)0xC2C2, (s16)0xC252, (s16)0xC1EC, (s16)0xC18F, (s16)0xC13B, (s16)0xC0F2, (s16)0xC0B2, (s16)0xC07C, (s16)0xC04F, (s16)0xC02D, + (s16)0xC014, (s16)0xC005, (s16)0xC000, (s16)0xC005, (s16)0xC014, (s16)0xC02D, (s16)0xC04F, (s16)0xC07C, (s16)0xC0B2, (s16)0xC0F2, + (s16)0xC13B, (s16)0xC18F, (s16)0xC1EC, (s16)0xC252, (s16)0xC2C2, (s16)0xC33B, (s16)0xC3BE, (s16)0xC44A, (s16)0xC4E0, (s16)0xC57E, + (s16)0xC626, (s16)0xC6D6, (s16)0xC78F, (s16)0xC851, (s16)0xC91B, (s16)0xC9EE, (s16)0xCACA, (s16)0xCBAD, (s16)0xCC99, (s16)0xCD8C, + (s16)0xCE87, (s16)0xCF8A, (s16)0xD095, (s16)0xD1A6, (s16)0xD2BF, (s16)0xD3DF, (s16)0xD506, (s16)0xD633, (s16)0xD767, (s16)0xD8A1, + (s16)0xD9E1, (s16)0xDB26, (s16)0xDC72, (s16)0xDDC3, (s16)0xDF19, (s16)0xE075, (s16)0xE1D5, (s16)0xE33A, (s16)0xE4A3, (s16)0xE611, + (s16)0xE783, (s16)0xE8F8, (s16)0xEA71, (s16)0xEBED, (s16)0xED6C, (s16)0xEEEF, (s16)0xF074, (s16)0xF1FB, (s16)0xF384, (s16)0xF50F, + (s16)0xF69C, (s16)0xF82B, (s16)0xF9BB, (s16)0xFB4B, (s16)0xFCDD, (s16)0xFE6E }; + +void BgAffineSet(struct BgAffineSrcData *src, struct BgAffineDstData *dest, s32 count) +{ + for (s32 i = 0; i < count; i++) { + s32 cx = src[i].texX; + s32 cy = src[i].texY; + s16 dispx = src[i].scrX; + s16 dispy = src[i].scrY; + s16 rx = src[i].sx; + s16 ry = src[i].sy; + u16 theta = src[i].alpha >> 8; + s32 a = sineTable[(theta + 0x40) & 255]; + s32 b = sineTable[theta]; + + s16 dx = (rx * a) >> 14; + s16 dmx = (rx * b) >> 14; + s16 dy = (ry * b) >> 14; + s16 dmy = (ry * a) >> 14; + + dest[i].pa = dx; + dest[i].pb = -dmx; + dest[i].pc = dy; + dest[i].pd = dmy; + + s32 startx = cx - dx * dispx + dmx * dispy; + s32 starty = cy - dy * dispx - dmy * dispy; + + dest[i].dx = startx; + dest[i].dy = starty; + } +} + +void ObjAffineSet(struct ObjAffineSrcData *src, void *dest, s32 count, s32 offset) +{ + for (s32 i = 0; i < count; i++) { + s16 rx = src[i].xScale; + s16 ry = src[i].yScale; + u16 theta = src[i].rotation >> 8; + + s32 a = (s32)sineTable[(theta + 64) & 255]; + s32 b = (s32)sineTable[theta]; + + s16 dx = ((s32)rx * a) >> 14; + s16 dmx = ((s32)rx * b) >> 14; + s16 dy = ((s32)ry * b) >> 14; + s16 dmy = ((s32)ry * a) >> 14; + + CPUWriteHalfWord(dest, dx); + dest += offset; + CPUWriteHalfWord(dest, -dmx); + dest += offset; + CPUWriteHalfWord(dest, dy); + dest += offset; + CPUWriteHalfWord(dest, dmy); + dest += offset; + } +} + +void SoftReset(u32 resetFlags) { } + +void SoftResetExram(u32 resetFlags) { } + +static const uint16_t bgMapSizes[][2] = { + { 32, 32 }, + { 64, 32 }, + { 32, 64 }, + { 64, 64 }, +}; + +#define mosaicBGEffectX (REG_MOSAIC & 0xF) +#define mosaicBGEffectY ((REG_MOSAIC >> 4) & 0xF) +#define mosaicSpriteEffectX ((REG_MOSAIC >> 8) & 0xF) +#define mosaicSpriteEffectY ((REG_MOSAIC >> 12) & 0xF) +#define applyBGHorizontalMosaicEffect(x) (x - (x % (mosaicBGEffectX + 1))) +#define applyBGVerticalMosaicEffect(y) (y - (y % (mosaicBGEffectY + 1))) +#define applySpriteHorizontalMosaicEffect(x) (x - (x % (mosaicSpriteEffectX + 1))) +#define applySpriteVerticalMosaicEffect(y) (y - (y % (mosaicSpriteEffectY + 1))) + +static void RenderBGScanline(int bgNum, uint16_t control, uint16_t hoffs, uint16_t voffs, int lineNum, uint16_t *line) +{ + unsigned int charBaseBlock = (control >> 2) & 3; + unsigned int screenBaseBlock = (control & BGCNT_SCREENBASE_MASK) >> 8; + + unsigned int bitsPerPixel = ((control >> 7) & 1) ? 8 : 4; + unsigned int mapWidth = bgMapSizes[control >> 14][0]; + unsigned int mapHeight = bgMapSizes[control >> 14][1]; + unsigned int mapWidthInPixels = mapWidth * 8; + unsigned int mapHeightInPixels = mapHeight * 8; + + uint8_t *bgtiles = (uint8_t *)BG_CHAR_ADDR(charBaseBlock); + uint16_t *pal = (uint16_t *)PLTT; + + if (control & BGCNT_MOSAIC) + lineNum = applyBGVerticalMosaicEffect(lineNum); + + hoffs &= 0x1FF; + voffs &= 0x1FF; + + for (unsigned int x = 0; x < DISPLAY_WIDTH; x++) { + uint16_t *bgmap = (uint16_t *)BG_SCREEN_ADDR(screenBaseBlock); + // adjust for scroll + unsigned int xx; + if (control & BGCNT_MOSAIC) + xx = (applyBGHorizontalMosaicEffect(x) + hoffs) & 0x1FF; + else { + if (!(control & BGCNT_TXT512x256)) { + xx = (x + hoffs) & 0xFF; + } else { + xx = (x + hoffs) & 0x1FF; + } + } + + unsigned int yy = (lineNum + voffs); + + if (!(control & BGCNT_TXT256x512)) { + yy &= 0xFF; + } else { + yy &= 0x1FF; + } + + unsigned int mapX = xx / 8; + unsigned int mapY = yy / 8; + + // TODO: The mult. with 64 doesn't break stage maps, but most regular tilemaps are broken. +#if !WIDESCREEN_HACK + unsigned int mapIndex = mapY * 32 + mapX; +#else + unsigned int mapIndex = mapY * ((control & BGCNT_TXT512x256) ? 64 : 32) + mapX; +#endif + uint16_t entry = bgmap[mapIndex]; + + unsigned int tileNum = entry & 0x3FF; + unsigned int paletteNum = (entry >> 12) & 0xF; +#if ENABLE_VRAM_VIEW + vramPalIdBuffer[tileNum] = paletteNum; +#endif + + unsigned int tileX = xx % 8; + unsigned int tileY = yy % 8; + + // Flip if necessary + if (entry & (1 << 10)) + tileX = 7 - tileX; + if (entry & (1 << 11)) + tileY = 7 - tileY; + + uint16_t tileLoc = tileNum * (bitsPerPixel * 8); + uint16_t tileLocY = tileY * bitsPerPixel; + uint16_t tileLocX = tileX; + if (bitsPerPixel == 4) + tileLocX /= 2; + + uint8_t pixel = bgtiles[tileLoc + tileLocY + tileLocX]; + + if (bitsPerPixel == 4) { + if (tileX & 1) + pixel >>= 4; + else + pixel &= 0xF; + + if (pixel != 0) + line[x] = pal[16 * paletteNum + pixel] | 0x8000; + } else { + line[x] = pal[pixel] | 0x8000; + } + } +} + +static inline uint32_t getBgX(int bgNumber) +{ + if (bgNumber == 2) { + return REG_BG2X; + } else if (bgNumber == 3) { + return REG_BG3X; + } + + return 0; +} + +static inline uint32_t getBgY(int bgNumber) +{ + if (bgNumber == 2) { + return REG_BG2Y; + } else if (bgNumber == 3) { + return REG_BG3Y; + } + + return 0; +} + +static inline uint16_t getBgPA(int bgNumber) +{ + if (bgNumber == 2) { + return REG_BG2PA; + } else if (bgNumber == 3) { + return REG_BG3PA; + } + return 0; +} + +static inline uint16_t getBgPB(int bgNumber) +{ + if (bgNumber == 2) { + return REG_BG2PB; + } else if (bgNumber == 3) { + return REG_BG3PB; + } + + return 0; +} + +static inline uint16_t getBgPC(int bgNumber) +{ + if (bgNumber == 2) { + return REG_BG2PC; + } else if (bgNumber == 3) { + return REG_BG3PC; + } + + return 0; +} + +static inline uint16_t getBgPD(int bgNumber) +{ + if (bgNumber == 2) { + return REG_BG2PD; + } else if (bgNumber == 3) { + return REG_BG3PD; + } + + return 0; +} + +static void RenderRotScaleBGScanline(int bgNum, uint16_t control, uint16_t x, uint16_t y, int lineNum, uint16_t *line) +{ + vBgCnt *bgcnt = (vBgCnt *)&control; + unsigned int charBaseBlock = bgcnt->charBaseBlock; + unsigned int screenBaseBlock = bgcnt->screenBaseBlock; + unsigned int mapWidth = 1 << (4 + (bgcnt->screenSize)); // number of tiles + + uint8_t *bgtiles = (uint8_t *)(VRAM + charBaseBlock * 0x4000); + uint8_t *bgmap = (uint8_t *)(VRAM + screenBaseBlock * 0x800); + uint16_t *pal = (uint16_t *)PLTT; + + if (control & BGCNT_MOSAIC) + lineNum = applyBGVerticalMosaicEffect(lineNum); + + s16 pa = getBgPA(bgNum); + s16 pb = getBgPB(bgNum); + s16 pc = getBgPC(bgNum); + s16 pd = getBgPD(bgNum); + + int sizeX = 128; + int sizeY = 128; + + switch (bgcnt->screenSize) { + case 0: + break; + case 1: + sizeX = sizeY = 256; + break; + case 2: + sizeX = sizeY = 512; + break; + case 3: + sizeX = sizeY = 1024; + break; + } + + int maskX = sizeX - 1; + int maskY = sizeY - 1; + + int yshift = ((control >> 14) & 3) + 4; + + /*int dx = pa & 0x7FFF; + if (pa & 0x8000) + dx |= 0xFFFF8000; + int dmx = pb & 0x7FFF; + if (pb & 0x8000) + dmx |= 0xFFFF8000; + int dy = pc & 0x7FFF; + if (pc & 0x8000) + dy |= 0xFFFF8000; + int dmy = pd & 0x7FFF; + if (pd & 0x8000) + dmy |= 0xFFFF8000;*/ + + s32 currentX = getBgX(bgNum); + s32 currentY = getBgY(bgNum); + // sign extend 28 bit number + currentX = ((currentX & (1 << 27)) ? currentX | 0xF0000000 : currentX); + currentY = ((currentY & (1 << 27)) ? currentY | 0xF0000000 : currentY); + + currentX += lineNum * pb; + currentY += lineNum * pd; + + int realX = currentX; + int realY = currentY; + + if (bgcnt->areaOverflowMode) { + for (int x = 0; x < DISPLAY_WIDTH; x++) { + int xxx = (realX >> 8) & maskX; + int yyy = (realY >> 8) & maskY; + + int tile = bgmap[(xxx >> 3) + ((yyy >> 3) << yshift)]; + + int tileX = xxx & 7; + int tileY = yyy & 7; + + uint8_t pixel = bgtiles[(tile << 6) + (tileY << 3) + tileX]; + + if (pixel != 0) { + line[x] = pal[pixel] | 0x8000; + } + + realX += pa; + realY += pc; + } + } else { + for (int x = 0; x < DISPLAY_WIDTH; x++) { + int xxx = (realX >> 8); + int yyy = (realY >> 8); + + if (xxx < 0 || yyy < 0 || xxx >= sizeX || yyy >= sizeY) { + // line[x] = 0x80000000; + } else { + int tile = bgmap[(xxx >> 3) + ((yyy >> 3) << yshift)]; + + int tileX = xxx & 7; + int tileY = yyy & 7; + + uint8_t pixel = bgtiles[(tile << 6) + (tileY << 3) + tileX]; + + if (pixel != 0) { + line[x] = pal[pixel] | 0x8000; + } + } + realX += pa; + realY += pc; + } + } + // the only way i could figure out how to get accurate mosaic on affine bgs + // luckily i dont think pokemon emerald uses mosaic on affine bgs + if (control & BGCNT_MOSAIC && mosaicBGEffectX > 0) { + for (int x = 0; x < DISPLAY_WIDTH; x++) { + uint16_t color = line[applyBGHorizontalMosaicEffect(x)]; + line[x] = color; + } + } +} + +const u8 spriteSizes[][2] = { + { 8, 16 }, + { 8, 32 }, + { 16, 32 }, + { 32, 64 }, +}; + +#define getAlphaBit(x) ((x >> 15) & 1) +#define getRedChannel(x) ((x >> 0) & 0x1F) +#define getGreenChannel(x) ((x >> 5) & 0x1F) +#define getBlueChannel(x) ((x >> 10) & 0x1F) +#define isbgEnabled(x) ((REG_DISPCNT >> 8) & 0xF) & (1 << x) + +static uint16_t alphaBlendColor(uint16_t targetA, uint16_t targetB) +{ + unsigned int eva = REG_BLDALPHA & 0x1F; + unsigned int evb = (REG_BLDALPHA >> 8) & 0x1F; + // shift right by 4 = division by 16 + unsigned int r = ((getRedChannel(targetA) * eva) + (getRedChannel(targetB) * evb)) >> 4; + unsigned int g = ((getGreenChannel(targetA) * eva) + (getGreenChannel(targetB) * evb)) >> 4; + unsigned int b = ((getBlueChannel(targetA) * eva) + (getBlueChannel(targetB) * evb)) >> 4; + + if (r > 31) + r = 31; + if (g > 31) + g = 31; + if (b > 31) + b = 31; + + return r | (g << 5) | (b << 10) | (1 << 15); +} + +static uint16_t alphaBrightnessIncrease(uint16_t targetA) +{ + unsigned int evy = (REG_BLDY & 0x1F); + unsigned int r = getRedChannel(targetA) + (31 - getRedChannel(targetA)) * evy / 16; + unsigned int g = getGreenChannel(targetA) + (31 - getGreenChannel(targetA)) * evy / 16; + unsigned int b = getBlueChannel(targetA) + (31 - getBlueChannel(targetA)) * evy / 16; + + if (r > 31) + r = 31; + if (g > 31) + g = 31; + if (b > 31) + b = 31; + + return r | (g << 5) | (b << 10) | (1 << 15); +} + +static uint16_t alphaBrightnessDecrease(uint16_t targetA) +{ + unsigned int evy = (REG_BLDY & 0x1F); + unsigned int r = getRedChannel(targetA) - getRedChannel(targetA) * evy / 16; + unsigned int g = getGreenChannel(targetA) - getGreenChannel(targetA) * evy / 16; + unsigned int b = getBlueChannel(targetA) - getBlueChannel(targetA) * evy / 16; + + if (r > 31) + r = 31; + if (g > 31) + g = 31; + if (b > 31) + b = 31; + + return r | (g << 5) | (b << 10) | (1 << 15); +} + +// outputs the blended pixel in colorOutput, the prxxx are the bg priority and +// subpriority, pixelpos is pixel offset in scanline +static bool alphaBlendSelectTargetB(struct scanlineData *scanline, uint16_t *colorOutput, char prnum, char prsub, int pixelpos, + bool spriteBlendEnabled) +{ + // iterate trough every possible bg to blend with, starting from specified priorities + // from arguments + for (unsigned int blndprnum = prnum; blndprnum <= 3; blndprnum++) { + // check if sprite is available to blend with, if sprite blending is enabled + if (spriteBlendEnabled == true && getAlphaBit(scanline->spriteLayers[blndprnum][pixelpos]) == 1) { + *colorOutput = scanline->spriteLayers[blndprnum][pixelpos]; + return true; + } + + for (unsigned int blndprsub = prsub; blndprsub < scanline->prioritySortedBgsCount[blndprnum]; blndprsub++) { + char currLayer = scanline->prioritySortedBgs[blndprnum][blndprsub]; + if (getAlphaBit(scanline->layers[currLayer][pixelpos]) == 1 && REG_BLDCNT & (1 << (8 + currLayer)) && isbgEnabled(currLayer)) { + *colorOutput = scanline->layers[currLayer][pixelpos]; + return true; + } + // if we hit a non target layer we should bail + if (getAlphaBit(scanline->layers[currLayer][pixelpos]) == 1 && isbgEnabled(currLayer) && prnum != blndprnum) { + return false; + } + } + prsub = 0; // start from zero in the next iteration + } + // no background got hit, check if backdrop is enabled and return it if enabled + // otherwise fail + if (REG_BLDCNT & BLDCNT_TGT2_BD) { + *colorOutput = *(uint16_t *)PLTT; + return true; + } else { + return false; + } +} + +#define WINMASK_BG0 (1 << 0) +#define WINMASK_BG1 (1 << 1) +#define WINMASK_BG2 (1 << 2) +#define WINMASK_BG3 (1 << 3) +#define WINMASK_OBJ (1 << 4) +#define WINMASK_CLR (1 << 5) +#define WINMASK_WINOUT (1 << 6) + +// checks if window horizontal is in bounds and takes account WIN wraparound +static bool winCheckHorizontalBounds(u16 left, u16 right, u16 xpos) +{ + if (left > right) + return (xpos >= left || xpos < right); + else + return (xpos >= left && xpos < right); +} + +// Parts of this code heavily borrowed from NanoboyAdvance. +static void DrawSprites(struct scanlineData *scanline, uint16_t vcount, bool windowsEnabled) +{ + int i; + unsigned int x; + unsigned int y; + void *objtiles = OBJ_VRAM0; + unsigned int blendMode = (REG_BLDCNT >> 6) & 3; + bool winShouldBlendPixel = true; + + int16_t matrix[2][2] = {}; + + if (!(REG_DISPCNT & (1 << 6))) { + puts("2-D OBJ Character mapping not supported."); + } + + for (i = OAM_ENTRY_COUNT - 1; i >= 0; i--) { + OamData *oam = &((OamData *)OAM)[i]; + unsigned int width; + unsigned int height; + uint16_t *pixels; + + bool isAffine = oam->split.affineMode & 1; + bool doubleSizeOrDisabled = (oam->split.affineMode >> 1) & 1; + bool isSemiTransparent = (oam->split.objMode == 1); + bool isObjWin = (oam->split.objMode == 2); + + if (!(isAffine) && doubleSizeOrDisabled) // disable for non-affine + { + continue; + } + + if (oam->split.shape == 0) { + width = (1 << oam->split.size) * 8; + height = (1 << oam->split.size) * 8; + } else if (oam->split.shape == 1) // wide + { + width = spriteSizes[oam->split.size][1]; + height = spriteSizes[oam->split.size][0]; + } else if (oam->split.shape == 2) // tall + { + width = spriteSizes[oam->split.size][0]; + height = spriteSizes[oam->split.size][1]; + } else { + continue; // prohibited, do not draw + } + + int rect_width = width; + int rect_height = height; + + int half_width = width / 2; + int half_height = height / 2; + + pixels = scanline->spriteLayers[oam->split.priority]; + + int32_t x = oam->split.x; + int32_t y = oam->split.y; + + if (x >= DISPLAY_WIDTH) + x -= 512; + if (y >= DISPLAY_HEIGHT) + y -= 256; + + if (isAffine) { + // TODO: there is probably a better way to do this + u8 matrixNum = oam->split.matrixNum * 4; + + OamData *oam1 = &((OamData *)OAM)[matrixNum]; + OamData *oam2 = &((OamData *)OAM)[matrixNum + 1]; + OamData *oam3 = &((OamData *)OAM)[matrixNum + 2]; + OamData *oam4 = &((OamData *)OAM)[matrixNum + 3]; + + matrix[0][0] = oam1->all.affineParam; + matrix[0][1] = oam2->all.affineParam; + matrix[1][0] = oam3->all.affineParam; + matrix[1][1] = oam4->all.affineParam; + + if (doubleSizeOrDisabled) // double size for affine + { + rect_width *= 2; + rect_height *= 2; + half_width *= 2; + half_height *= 2; + } + } else { + // Identity + matrix[0][0] = 0x100; + matrix[0][1] = 0; + matrix[1][0] = 0; + matrix[1][1] = 0x100; + } + + x += half_width; + y += half_height; + + // Does this sprite actually draw on this scanline? + if (vcount >= (y - half_height) && vcount < (y + half_height)) { + int local_y = (oam->split.mosaic == 1) ? applySpriteVerticalMosaicEffect(vcount) - y : vcount - y; + int number = oam->split.tileNum; + int palette = oam->split.paletteNum; + bool flipX = !isAffine && ((oam->split.matrixNum >> 3) & 1); + bool flipY = !isAffine && ((oam->split.matrixNum >> 4) & 1); + bool is8BPP = oam->split.bpp & 1; + + for (int local_x = -half_width; local_x <= half_width; local_x++) { + uint8_t *tiledata = (uint8_t *)objtiles; + uint16_t *palette = (uint16_t *)(PLTT + (0x200 / 2)); + int local_mosaicX; + int tex_x; + int tex_y; + + unsigned int global_x = local_x + x; + + if (global_x < 0 || global_x >= DISPLAY_WIDTH) + continue; + + if (oam->split.mosaic == 1) { + // mosaic effect has to be applied to global coordinates otherwise + // the mosaic will scroll + local_mosaicX = applySpriteHorizontalMosaicEffect(global_x) - x; + tex_x = ((matrix[0][0] * local_mosaicX + matrix[0][1] * local_y) >> 8) + (width / 2); + tex_y = ((matrix[1][0] * local_mosaicX + matrix[1][1] * local_y) >> 8) + (height / 2); + } else { + tex_x = ((matrix[0][0] * local_x + matrix[0][1] * local_y) >> 8) + (width / 2); + tex_y = ((matrix[1][0] * local_x + matrix[1][1] * local_y) >> 8) + (height / 2); + } + + /* Check if transformed coordinates are inside bounds. */ + + if (tex_x >= width || tex_y >= height || tex_x < 0 || tex_y < 0) + continue; + + if (flipX) + tex_x = width - tex_x - 1; + if (flipY) + tex_y = height - tex_y - 1; + + int tile_x = tex_x % 8; + int tile_y = tex_y % 8; + int block_x = tex_x / 8; + int block_y = tex_y / 8; + int block_offset = ((block_y * (REG_DISPCNT & 0x40 ? (width / 8) : 16)) + block_x); + uint16_t pixel = 0; + + if (!is8BPP) { + int tileDataIndex = (block_offset + oam->split.tileNum) * 32 + (tile_y * 4) + (tile_x / 2); + pixel = tiledata[tileDataIndex]; + if (tile_x & 1) + pixel >>= 4; + else + pixel &= 0xF; + palette += oam->split.paletteNum * 16; +#if ENABLE_VRAM_VIEW + vramPalIdBuffer[0x800 + (tileDataIndex / 32)] = 16 + oam->split.paletteNum; +#endif + } else { + pixel = tiledata[(block_offset * 2 + oam->split.tileNum) * 32 + (tile_y * 8) + tile_x]; + } + + if (pixel != 0) { + uint16_t color = palette[pixel]; + + // if sprite mode is 2 then write to the window mask instead + if (isObjWin) { + if (scanline->winMask[global_x] & WINMASK_WINOUT) + scanline->winMask[global_x] = (REG_WINOUT >> 8) & 0x3F; + continue; + } + // this code runs if pixel is to be drawn + if (global_x < DISPLAY_WIDTH && global_x >= 0) { + // check if its enabled in the window (if window is enabled) + winShouldBlendPixel = (windowsEnabled == false || scanline->winMask[global_x] & WINMASK_CLR); + + // has to be separated from the blend mode switch statement + // because of OBJ semi transparancy feature + if ((blendMode == 1 && REG_BLDCNT & BLDCNT_TGT1_OBJ && winShouldBlendPixel) || isSemiTransparent) { + uint16_t targetA = color; + uint16_t targetB = 0; + if (alphaBlendSelectTargetB(scanline, &targetB, oam->split.priority, 0, global_x, false)) { + color = alphaBlendColor(targetA, targetB); + } + } else if (REG_BLDCNT & BLDCNT_TGT1_OBJ && winShouldBlendPixel) { + switch (blendMode) { + case 2: + color = alphaBrightnessIncrease(color); + break; + case 3: + color = alphaBrightnessDecrease(color); + break; + } + } + + // write pixel to pixel framebuffer + pixels[global_x] = color | (1 << 15); + } + } + } + } + } +} + +static void DrawScanline(uint16_t *pixels, uint16_t vcount) +{ + unsigned int mode = REG_DISPCNT & 3; + unsigned char numOfBgs = (mode == 0 ? 4 : 3); + int bgnum, prnum; + struct scanlineData scanline; + unsigned int blendMode = (REG_BLDCNT >> 6) & 3; + unsigned int xpos; + + // initialize all priority bookkeeping data + memset(scanline.layers, 0, sizeof(scanline.layers)); + memset(scanline.winMask, 0, sizeof(scanline.winMask)); + memset(scanline.spriteLayers, 0, sizeof(scanline.spriteLayers)); + memset(scanline.prioritySortedBgsCount, 0, sizeof(scanline.prioritySortedBgsCount)); + + for (bgnum = 0; bgnum < numOfBgs; bgnum++) { + uint16_t bgcnt = *(uint16_t *)(REG_ADDR_BG0CNT + bgnum * 2); + uint16_t priority; + scanline.bgcnts[bgnum] = bgcnt; + scanline.bgtoprio[bgnum] = priority = (bgcnt & 3); + + char priorityCount = scanline.prioritySortedBgsCount[priority]; + scanline.prioritySortedBgs[priority][priorityCount] = bgnum; + scanline.prioritySortedBgsCount[priority]++; + } + + switch (mode) { + case 0: + // All backgrounds are text mode + for (bgnum = 3; bgnum >= 0; bgnum--) { + if (isbgEnabled(bgnum)) { + uint16_t bghoffs = *(uint16_t *)(REG_ADDR_BG0HOFS + bgnum * 4); + uint16_t bgvoffs = *(uint16_t *)(REG_ADDR_BG0VOFS + bgnum * 4); + + RenderBGScanline(bgnum, scanline.bgcnts[bgnum], bghoffs, bgvoffs, vcount, scanline.layers[bgnum]); + } + } + + break; + case 1: + // BG2 is affine + bgnum = 2; + if (isbgEnabled(bgnum)) { + RenderRotScaleBGScanline(bgnum, scanline.bgcnts[bgnum], REG_BG2X, REG_BG2Y, vcount, scanline.layers[bgnum]); + } + // BG0 and BG1 are text mode + for (bgnum = 1; bgnum >= 0; bgnum--) { + if (isbgEnabled(bgnum)) { + uint16_t bghoffs = *(uint16_t *)(REG_ADDR_BG0HOFS + bgnum * 4); + uint16_t bgvoffs = *(uint16_t *)(REG_ADDR_BG0VOFS + bgnum * 4); + + RenderBGScanline(bgnum, scanline.bgcnts[bgnum], bghoffs, bgvoffs, vcount, scanline.layers[bgnum]); + } + } + break; + default: + printf("Video mode %u is unsupported.\n", mode); + break; + } + + bool windowsEnabled = false; + u16 WIN0bottom, WIN0top, WIN0right, WIN0left; + u16 WIN1bottom, WIN1top, WIN1right, WIN1left; + bool WIN0enable, WIN1enable; + WIN0enable = false; + WIN1enable = false; + + // figure out if WIN0 masks on this scanline + if (REG_DISPCNT & DISPCNT_WIN0_ON) { + // acquire the window coordinates + + WIN0bottom = WIN_GET_HIGHER(REG_WIN0V); // y2; + WIN0top = WIN_GET_LOWER(REG_WIN0V); // y1; + WIN0right = WIN_GET_HIGHER(REG_WIN0H); // x2 + WIN0left = WIN_GET_LOWER(REG_WIN0H); // x1 + + // printf("%d, %d, %d, %d\n", WIN0bottom, WIN0top, WIN0right, WIN0left); + // figure out WIN Y wraparound and check bounds accordingly + if (WIN0top > WIN0bottom) { + if (vcount >= WIN0top || vcount < WIN0bottom) + WIN0enable = true; + } else { + if (vcount >= WIN0top && vcount < WIN0bottom) + WIN0enable = true; + } + + windowsEnabled = true; + } + // figure out if WIN1 masks on this scanline + if (REG_DISPCNT & DISPCNT_WIN1_ON) { + WIN1bottom = WIN_GET_HIGHER(REG_WIN1V); // y2; + WIN1top = WIN_GET_LOWER(REG_WIN1V); // y1; + WIN1right = WIN_GET_HIGHER(REG_WIN1H); // x2 + WIN1left = WIN_GET_LOWER(REG_WIN1H); // x1 + + if (WIN1top > WIN1bottom) { + if (vcount >= WIN1top || vcount < WIN1bottom) + WIN1enable = true; + } else { + if (vcount >= WIN1top && vcount < WIN1bottom) + WIN1enable = true; + } + + windowsEnabled = true; + } + // enable windows if OBJwin is enabled + if (REG_DISPCNT & DISPCNT_OBJWIN_ON && REG_DISPCNT & DISPCNT_OBJ_ON) { + windowsEnabled = true; + } + + // draw to pixel mask + if (windowsEnabled) { + for (xpos = 0; xpos < DISPLAY_WIDTH; xpos++) { + // win0 checks + if (WIN0enable && winCheckHorizontalBounds(WIN0left, WIN0right, xpos)) + scanline.winMask[xpos] = REG_WININ & 0x3F; + // win1 checks + else if (WIN1enable && winCheckHorizontalBounds(WIN1left, WIN1right, xpos)) + scanline.winMask[xpos] = (REG_WININ >> 8) & 0x3F; + else + scanline.winMask[xpos] = (REG_WINOUT & 0x3F) | WINMASK_WINOUT; + } + } + + if (REG_DISPCNT & DISPCNT_OBJ_ON) + DrawSprites(&scanline, vcount, windowsEnabled); + + // iterate trough every priority in order + for (prnum = 3; prnum >= 0; prnum--) { + for (char prsub = scanline.prioritySortedBgsCount[prnum] - 1; prsub >= 0; prsub--) { + char bgnum = scanline.prioritySortedBgs[prnum][prsub]; + // if background is enabled then draw it + if (isbgEnabled(bgnum)) { + uint16_t *src = scanline.layers[bgnum]; + // copy all pixels to framebuffer + for (xpos = 0; xpos < DISPLAY_WIDTH; xpos++) { + uint16_t color = src[xpos]; + bool winEffectEnable = true; + + if (!getAlphaBit(color)) + continue; // do nothing if alpha bit is not set + + if (windowsEnabled) { + winEffectEnable = ((scanline.winMask[xpos] & WINMASK_CLR) >> 5); + // if bg is disabled inside the window then do not draw the pixel + if (!(scanline.winMask[xpos] & 1 << bgnum)) + continue; + } + + // blending code + if (blendMode != 0 && REG_BLDCNT & (1 << bgnum) && winEffectEnable) { + uint16_t targetA = color; + uint16_t targetB = 0; + + switch (blendMode) { + case 1: { + char isSpriteBlendingEnabled = REG_BLDCNT & BLDCNT_TGT2_OBJ ? 1 : 0; + // find targetB and blend it + if (alphaBlendSelectTargetB(&scanline, &targetB, prnum, prsub + 1, xpos, isSpriteBlendingEnabled)) { + color = alphaBlendColor(targetA, targetB); + } + } break; + case 2: + color = alphaBrightnessIncrease(targetA); + break; + case 3: + color = alphaBrightnessDecrease(targetA); + break; + } + } + // write the pixel to scanline buffer output + pixels[xpos] = color; + } + } + } + // draw sprites on current priority + uint16_t *src = scanline.spriteLayers[prnum]; + for (xpos = 0; xpos < DISPLAY_WIDTH; xpos++) { + if (getAlphaBit(src[xpos])) { + // check if sprite pixel draws inside window + if (windowsEnabled && !(scanline.winMask[xpos] & WINMASK_OBJ)) + continue; + // draw the pixel + pixels[xpos] = src[xpos]; + } + } + } +} + +uint16_t *memsetu16(uint16_t *dst, uint16_t fill, size_t count) +{ + for (int i = 0; i < count; i++) { + *dst++ = fill; + } + + return 0; +} + +static void DrawFrame(uint16_t *pixels) +{ + int i; + int j; + static uint16_t scanlines[DISPLAY_HEIGHT][DISPLAY_WIDTH]; + unsigned int blendMode = (REG_BLDCNT >> 6) & 3; + + for (i = 0; i < DISPLAY_HEIGHT; i++) { + REG_VCOUNT = i; + if (((REG_DISPSTAT >> 8) & 0xFF) == REG_VCOUNT) { + REG_DISPSTAT |= INTR_FLAG_VCOUNT; + if (REG_DISPSTAT & DISPSTAT_VCOUNT_INTR) + gIntrTable[INTR_INDEX_VCOUNT](); + } + + // Render the backdrop color before the each individual scanline. + // HBlank interrupt code could have changed it inbetween lines. + memsetu16(scanlines[i], *(uint16_t *)PLTT, DISPLAY_WIDTH); + DrawScanline(scanlines[i], i); + + REG_DISPSTAT |= INTR_FLAG_HBLANK; + + RunDMAs(DMA_HBLANK); + + if (REG_DISPSTAT & DISPSTAT_HBLANK_INTR) + gIntrTable[INTR_INDEX_HBLANK](); + + REG_DISPSTAT &= ~INTR_FLAG_HBLANK; + REG_DISPSTAT &= ~INTR_FLAG_VCOUNT; + } + + // Copy to screen + for (i = 0; i < DISPLAY_HEIGHT; i++) { + uint16_t *src = scanlines[i]; + for (j = 0; j < DISPLAY_WIDTH; j++) { + pixels[i * DISPLAY_WIDTH + j] = src[j]; + } + } +} + +#if ENABLE_VRAM_VIEW +void DrawVramView(Uint16 *buffer) +{ + for (int y = 0; y < VRAM_VIEW_HEIGHT / TILE_WIDTH; y++) { + for (int x = 0; x < VRAM_VIEW_WIDTH / TILE_WIDTH; x++) { + u16 tileId = y * (VRAM_VIEW_WIDTH / TILE_WIDTH) + x; + u16 *tileBase = &buffer[(y * VRAM_VIEW_WIDTH + x) * 8]; + + for (int ty = 0; ty < TILE_WIDTH; ty++) { + for (int tx = 0; tx < TILE_WIDTH; tx += 2) { + s32 tileIndex = ty * VRAM_VIEW_WIDTH + tx; + u16 *dest = &tileBase[tileIndex]; + + int i = (ty * TILE_WIDTH + tx) / 2; + u8 *colorPtr = &((u8 *)VRAM)[tileId * 0x20 + i]; + u8 colorId = colorPtr[0]; + u8 colA = (colorId & 0xF0) >> 4; + u8 colB = (colorId & 0x0F) >> 0; + + u8 paletteId = vramPalIdBuffer[tileId]; + dest[0] = PLTT[paletteId * 16 + colB]; + dest[1] = PLTT[paletteId * 16 + colA]; + } + } + } + } +} + +void VramDraw(SDL_Texture *texture) +{ + memset(vramBuffer, 0, sizeof(vramBuffer)); + DrawVramView(vramBuffer); + SDL_UpdateTexture(texture, NULL, vramBuffer, VRAM_VIEW_WIDTH * sizeof(Uint16)); +} +#endif + +// void VDraw(SDL_Texture *texture) +// { +// memset(gameImage, 0, sizeof(gameImage)); +// DrawFrame(gameImage); +// SDL_UpdateTexture(texture, NULL, gameImage, DISPLAY_WIDTH * sizeof(Uint16)); +// REG_VCOUNT = 161; // prep for being in VBlank period +// } + +int DoMain(void *data) +{ + AgbMain(); + return 0; +} + +void VBlankIntrWait(void) +{ + // SDL_AtomicSet(&isFrameAvailable, 1); + // SDL_SemWait(vBlankSemaphore); +} + +u8 BinToBcd(u8 bin) +{ + int placeCounter = 1; + u8 out = 0; + do { + out |= (bin % 10) * placeCounter; + placeCounter *= 16; + } while ((bin /= 10) > 0); + + return out; +} + +// Following functions taken from mGBA's source +u16 ArcTan(s16 i) +{ + s32 a = -((i * i) >> 14); + s32 b = ((0xA9 * a) >> 14) + 0x390; + b = ((b * a) >> 14) + 0x91C; + b = ((b * a) >> 14) + 0xFB6; + b = ((b * a) >> 14) + 0x16AA; + b = ((b * a) >> 14) + 0x2081; + b = ((b * a) >> 14) + 0x3651; + b = ((b * a) >> 14) + 0xA2F9; + + return (i * b) >> 16; +} + +u16 ArcTan2(s16 x, s16 y) +{ + if (!y) { + if (x >= 0) + return 0; + return 0x8000; + } + if (!x) { + if (y >= 0) + return 0x4000; + return 0xC000; + } + if (y >= 0) { + if (x >= 0) { + if (x >= y) + return ArcTan((y << 14) / x); + } else if (-x >= y) + return ArcTan((y << 14) / x) + 0x8000; + return 0x4000 - ArcTan((x << 14) / y); + } else { + if (x <= 0) { + if (-x > -y) + return ArcTan((y << 14) / x) + 0x8000; + } else if (x >= -y) + return ArcTan((y << 14) / x) + 0x10000; + return 0xC000 - ArcTan((x << 14) / y); + } +} + +u16 Sqrt(u32 num) +{ + if (!num) + return 0; + u32 lower; + u32 upper = num; + u32 bound = 1; + while (bound < upper) { + upper >>= 1; + bound <<= 1; + } + while (1) { + upper = num; + u32 accum = 0; + lower = bound; + while (1) { + u32 oldLower = lower; + if (lower <= upper >> 1) + lower <<= 1; + if (oldLower >= upper >> 1) + break; + } + while (1) { + accum <<= 1; + if (upper >= lower) { + ++accum; + upper -= lower; + } + if (lower == bound) + break; + lower >>= 1; + } + u32 oldBound = bound; + bound += accum; + bound >>= 1; + if (bound >= oldBound) { + bound = oldBound; + break; + } + } + return bound; +} diff --git a/src/platform/shared/audio/cgb_audio.c b/src/platform/shared/audio/cgb_audio.c index 787a65f43..51b6791d8 100644 --- a/src/platform/shared/audio/cgb_audio.c +++ b/src/platform/shared/audio/cgb_audio.c @@ -103,6 +103,7 @@ void cgb_trigger_note(u8 channel) void cgb_audio_generate(u16 samplesPerFrame) { + float *outBuffer = gb.outBuffer; switch (REG_NR11 & 0xC0) { case 0x00: From 4b0a46a2aad241cd15e483e8485a6d6e04a48ed2 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Sat, 30 Nov 2024 04:29:30 +0000 Subject: [PATCH 03/11] more progress --- Makefile | 12 +- include/gba/types.h | 5 +- src/core.c | 7 +- src/platform/pret_sdl/sdl2.c | 15 + src/platform/ps2/.gitignore | 0 src/platform/ps2/lib/.gitkeep | 0 src/platform/ps2/ps2.c | 726 +++++++++++++++++++--------------- 7 files changed, 430 insertions(+), 335 deletions(-) create mode 100644 src/platform/ps2/.gitignore create mode 100644 src/platform/ps2/lib/.gitkeep diff --git a/Makefile b/Makefile index 4e12c7873..b97f61742 100644 --- a/Makefile +++ b/Makefile @@ -102,6 +102,8 @@ SDL_MINGW_LIB := $(SDL_MINGW_PKG)/lib SDL_MINGW_LINKER_FLAGS := -L$(SDL_MINGW_LIB) -lSDL2main -lSDL2.dll SDL_MINGW_FLAGS := -I$(SDL_MINGW_INCLUDE) -D_THREAD_SAFE +SDL2_PS2_PKG ?= ext/SDL2-PS2/ + # These have to(?) be defined this way, because # the C-preprocessor cannot resolve stuff like: # #if (PLATFORM == gba), where PLATFORM is defined via -D. @@ -114,7 +116,7 @@ else CPPFLAGS += -D TITLE_BAR=$(BUILD_NAME).$(PLATFORM) -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 $(shell sdl2-config --cflags) else ifeq ($(PLATFORM),sdl_ps2) CC1FLAGS += -Wno-parentheses-equality -Wno-unused-value - CPPFLAGS += -I$(PS2SDK)/common/include -I$(PS2SDK)/ee/include -I$(PS2SDK)/ports/include $(shell sdl2-config --cflags) + CPPFLAGS += -I$(PS2SDK)/common/include -I$(PS2SDK)/ee/include -I$(PS2SDK)/ports/include $(shell $(SDL2_PS2_PKG)/bin/sdl2-config --cflags) CPPFLAGS += -D TITLE_BAR=$(BUILD_NAME).$(PLATFORM) -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 -D_EE -DPS2 -D__PS2__ else ifeq ($(PLATFORM),sdl_win32) CPPFLAGS += -D TITLE_BAR=$(BUILD_NAME).$(PLATFORM) -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 $(SDL_MINGW_FLAGS) @@ -269,13 +271,13 @@ $(shell mkdir -p $(C_BUILDDIR) $(ASM_BUILDDIR) $(DATA_ASM_BUILDDIR) $(SOUND_ASM_ ifeq ($(PLATFORM),gba) C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/*") else ifeq ($(PLATFORM),sdl) -C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*") +C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/ps2/*") else ifeq ($(PLATFORM),sdl_ps2) C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/pret_sdl/*") else ifeq ($(PLATFORM),sdl_win32) -C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*") +C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/ps2/*") else ifeq ($(PLATFORM),win32) -C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/pret_sdl/*") +C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/pret_sdl/*" -not -path "*/platform/ps2/*") else C_SRCS := $(shell find $(C_SUBDIR) -name "*.c") endif @@ -445,7 +447,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 ifeq ($(PLATFORM),sdl_ps2) - @cd $(OBJ_DIR) && $(CC1) $(OBJS_REL) $(LINKER_MAP_FLAGS) -T$(PS2SDK)/ee/startup/linkfile -L$(PS2SDK)/common/lib -L$(PS2SDK)/ee/lib -L$(PS2DEV)/gsKit/lib -L$(PS2SDK)/ports/lib -Wl,-zmax-page-size=128 -o $(ROOT_DIR)/$@ + @cd $(OBJ_DIR) && $(CC1) $(OBJS_REL) $(shell $(SDL2_PS2_PKG)/bin/sdl2-config --cflags --libs) $(LINKER_MAP_FLAGS) -T$(PS2SDK)/ee/startup/linkfile -L$(PS2SDK)/common/lib -L$(PS2SDK)/ee/lib -L$(PS2DEV)/gsKit/lib -L$(PS2SDK)/ports/lib -Wl,-zmax-page-size=128 -o $(ROOT_DIR)/$@ else @cd $(OBJ_DIR) && $(CC1) -mwin32 $(OBJS_REL) -L$(ROOT_DIR)/libagbsyscall -lagbsyscall -lkernel32 -o $(ROOT_DIR)/$@ -Xlinker -Map "$(ROOT_DIR)/$(MAP)" endif diff --git a/include/gba/types.h b/include/gba/types.h index db818abdc..c7bb2b8e2 100644 --- a/include/gba/types.h +++ b/include/gba/types.h @@ -17,7 +17,9 @@ typedef struct __attribute__((packed)) name struct_body name; #endif - +#if _EE +#include +#else typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; @@ -26,6 +28,7 @@ typedef int8_t s8; typedef int16_t s16; typedef int32_t s32; typedef int64_t s64; +#endif // If the DISPLAY_HEIGHT was >255, scanline effects would break, // so we have to make this variable bigger. diff --git a/src/core.c b/src/core.c index dfe1ce94f..067fc6f3f 100644 --- a/src/core.c +++ b/src/core.c @@ -358,6 +358,8 @@ void GameInit(void) MultiSioInit(0); } +#include + void GameLoop(void) { while (TRUE) { @@ -399,8 +401,9 @@ void GameLoop(void) } // Wait for vblank to finish - while (REG_DISPSTAT & DISPSTAT_VBLANK) - ; + while (REG_DISPSTAT & DISPSTAT_VBLANK) { + SleepThread(); + } }; } diff --git a/src/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index 138bed81a..50420593a 100644 --- a/src/platform/pret_sdl/sdl2.c +++ b/src/platform/pret_sdl/sdl2.c @@ -2011,6 +2011,21 @@ void VDraw(SDL_Texture *texture) REG_VCOUNT = 161; // prep for being in VBlank period } +<<<<<<< HEAD +======= +int DoMain(void *data) +{ + AgbMain(); + return 0; +} + +void VBlankIntrWait(void) +{ + SDL_AtomicSet(&isFrameAvailable, 1); + SDL_SemWait(vBlankSemaphore); +} + +>>>>>>> b1b34f15 (more progress) u8 BinToBcd(u8 bin) { int placeCounter = 1; diff --git a/src/platform/ps2/.gitignore b/src/platform/ps2/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/src/platform/ps2/lib/.gitkeep b/src/platform/ps2/lib/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/src/platform/ps2/ps2.c b/src/platform/ps2/ps2.c index 22f4de80c..dc2cc9ed0 100644 --- a/src/platform/ps2/ps2.c +++ b/src/platform/ps2/ps2.c @@ -9,7 +9,9 @@ #include #endif -// #include +#define SDL_MAIN_HANDLED + +#include #include "global.h" #include "core.h" @@ -90,10 +92,11 @@ struct bgPriority { char subPriority; }; -// SDL_Thread *mainLoopThread; -// SDL_Window *sdlWindow; -// SDL_Renderer *sdlRenderer; -// SDL_Texture *sdlTexture; +SDL_Thread *mainLoopThread; +SDL_Thread *controlThread; +SDL_Window *sdlWindow; +SDL_Renderer *sdlRenderer; +SDL_Texture *sdlTexture; #if ENABLE_VRAM_VIEW SDL_Window *vramWindow; SDL_Renderer *vramRenderer; @@ -102,8 +105,8 @@ SDL_Texture *vramTexture; #define INITIAL_VIDEO_SCALE 1 unsigned int videoScale = INITIAL_VIDEO_SCALE; unsigned int preFullscreenVideoScale = INITIAL_VIDEO_SCALE; -// SDL_sem *vBlankSemaphore; -// SDL_atomic_t isFrameAvailable; +SDL_sem *vBlankSemaphore; +SDL_atomic_t isFrameAvailable; bool speedUp = false; bool videoScaleChanged = false; bool isRunning = true; @@ -122,9 +125,10 @@ extern void AgbMain(void); void DoSoftReset(void) {}; int DoMain(void *param); +int DoControl(void *data); void ProcessSDLEvents(void); -// void VDraw(SDL_Texture *texture); -// void VramDraw(SDL_Texture *texture); +void VDraw(SDL_Texture *texture); +void VramDraw(SDL_Texture *texture); static void ReadSaveFile(char *path); static void StoreSaveFile(void); @@ -140,209 +144,275 @@ void *Platform_malloc(int numBytes) { return HeapAlloc(GetProcessHeap(), HEAP_GE void Platform_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); } #endif +#include + +void RotateThreads(s32 id, u16 time, void *arg) +{ + printf("rorate\n"); + iRotateThreadReadyQueue(0x1e); +} + int main(int argc, char **argv) { - // // Open an output console on Windows - // #ifdef _WIN32 - // AllocConsole(); - // AttachConsole(GetCurrentProcessId()); - // freopen("CON", "w", stdout); - // #endif - - // ReadSaveFile("sa2.sav"); - - // if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) { - // fprintf(stderr, "SDL could not initialize! SDL_Error: %s\n", SDL_GetError()); - // return 1; - // } - - // #ifdef TITLE_BAR - // const char *title = STR(TITLE_BAR); - // #else - // const char *title = "SAT-R sa2"; - // #endif - - // sdlWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, DISPLAY_WIDTH * videoScale, - // DISPLAY_HEIGHT * videoScale, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); - // if (sdlWindow == NULL) { - // fprintf(stderr, "Window could not be created! SDL_Error: %s\n", SDL_GetError()); - // return 1; - // } - - // #if ENABLE_VRAM_VIEW - // int mainWindowX; - // int mainWindowWidth; - // SDL_GetWindowPosition(sdlWindow, &mainWindowX, NULL); - // SDL_GetWindowSize(sdlWindow, &mainWindowWidth, NULL); - // int vramWindowX = mainWindowX + mainWindowWidth; - // u16 vramWindowWidth = VRAM_VIEW_WIDTH; - // u16 vramWindowHeight = VRAM_VIEW_HEIGHT; - // vramWindow = SDL_CreateWindow("VRAM View", vramWindowX, SDL_WINDOWPOS_CENTERED, vramWindowWidth, vramWindowHeight, - // SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); - // if (vramWindow == NULL) { - // fprintf(stderr, "VRAM Window could not be created! SDL_Error: %s\n", SDL_GetError()); - // return 1; - // } - // #endif - - // sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_PRESENTVSYNC); - // if (sdlRenderer == NULL) { - // fprintf(stderr, "Renderer could not be created! SDL_Error: %s\n", SDL_GetError()); - // return 1; - // } - - // #if ENABLE_VRAM_VIEW - // vramRenderer = SDL_CreateRenderer(vramWindow, -1, SDL_RENDERER_PRESENTVSYNC); - // if (vramRenderer == NULL) { - // fprintf(stderr, "VRAM Renderer could not be created! SDL_Error: %s\n", SDL_GetError()); - // return 1; - // } - // #endif - - // SDL_SetRenderDrawColor(sdlRenderer, 255, 255, 255, 255); - // SDL_RenderClear(sdlRenderer); - // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); - // SDL_RenderSetLogicalSize(sdlRenderer, DISPLAY_WIDTH, DISPLAY_HEIGHT); - // #if ENABLE_VRAM_VIEW - // SDL_SetRenderDrawColor(vramRenderer, 0, 0, 0, 255); - // SDL_RenderClear(vramRenderer); - // SDL_RenderSetLogicalSize(vramRenderer, vramWindowWidth, vramWindowHeight); - // #endif - - // sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ABGR1555, SDL_TEXTUREACCESS_STREAMING, DISPLAY_WIDTH, - // DISPLAY_HEIGHT); if (sdlTexture == NULL) { - // fprintf(stderr, "Texture could not be created! SDL_Error: %s\n", SDL_GetError()); - // return 1; - // } - - // #if ENABLE_VRAM_VIEW - // vramTexture = SDL_CreateTexture(vramRenderer, SDL_PIXELFORMAT_ABGR1555, SDL_TEXTUREACCESS_STREAMING, vramWindowWidth, - // vramWindowHeight); if (vramTexture == NULL) { - // fprintf(stderr, "Texture could not be created! SDL_Error: %s\n", SDL_GetError()); - // return 1; - // } - // #endif - - // simTime = curGameTime = lastGameTime = SDL_GetPerformanceCounter(); - - // isFrameAvailable.value = 0; - // vBlankSemaphore = SDL_CreateSemaphore(0); - // if (vBlankSemaphore == NULL) { - // SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to create Semaphore:\n %s", SDL_GetError()); - // } - - // #if ENABLE_AUDIO - // SDL_AudioSpec want; - - // SDL_memset(&want, 0, sizeof(want)); /* or SDL_zero(want) */ - // want.freq = 48000; - // want.format = AUDIO_F32; - // want.channels = 2; - // want.samples = (want.freq / 60); + // REG_RCNT = 0x8000; + // cgb_audio_init(48000); + // AgbMain(); + // return 0; + // Open an output console on Windows +#ifdef _WIN32 + AllocConsole(); + AttachConsole(GetCurrentProcessId()); + freopen("CON", "w", stdout); +#endif + + // ReadSaveFile("sa2.sav"); + + printf("Starting\n"); + SDL_SetMainReady(); + printf("Ready \n"); + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + fprintf(stderr, "SDL could not initialize! SDL_Error: %s\n", SDL_GetError()); + return 1; + } + printf("INITIALISED\n"); + +#ifdef TITLE_BAR + const char *title = STR(TITLE_BAR); +#else + const char *title = "SAT-R sa2"; +#endif + + sdlWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, DISPLAY_WIDTH * videoScale, + DISPLAY_HEIGHT * videoScale, SDL_WINDOW_SHOWN); + if (sdlWindow == NULL) { + fprintf(stderr, "Window could not be created! SDL_Error: %s\n", SDL_GetError()); + return 1; + } + + printf("WINDOW CREATED\n"); + +#if ENABLE_VRAM_VIEW + int mainWindowX; + int mainWindowWidth; + SDL_GetWindowPosition(sdlWindow, &mainWindowX, NULL); + SDL_GetWindowSize(sdlWindow, &mainWindowWidth, NULL); + int vramWindowX = mainWindowX + mainWindowWidth; + u16 vramWindowWidth = VRAM_VIEW_WIDTH; + u16 vramWindowHeight = VRAM_VIEW_HEIGHT; + vramWindow = SDL_CreateWindow("VRAM View", vramWindowX, SDL_WINDOWPOS_CENTERED, vramWindowWidth, vramWindowHeight, + SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); + if (vramWindow == NULL) { + fprintf(stderr, "VRAM Window could not be created! SDL_Error: %s\n", SDL_GetError()); + return 1; + } +#endif + + sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_PRESENTVSYNC); + if (sdlRenderer == NULL) { + fprintf(stderr, "Renderer could not be created! SDL_Error: %s\n", SDL_GetError()); + return 1; + } + printf("RENDERER CREATED\n"); + +#if ENABLE_VRAM_VIEW + vramRenderer = SDL_CreateRenderer(vramWindow, -1, SDL_RENDERER_PRESENTVSYNC); + if (vramRenderer == NULL) { + fprintf(stderr, "VRAM Renderer could not be created! SDL_Error: %s\n", SDL_GetError()); + return 1; + } +#endif + + SDL_SetRenderDrawColor(sdlRenderer, 255, 255, 255, 255); + SDL_RenderClear(sdlRenderer); + // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); + SDL_RenderSetLogicalSize(sdlRenderer, DISPLAY_WIDTH, DISPLAY_HEIGHT); + +#if ENABLE_VRAM_VIEW + SDL_SetRenderDrawColor(vramRenderer, 0, 0, 0, 255); + SDL_RenderClear(vramRenderer); + SDL_RenderSetLogicalSize(vramRenderer, vramWindowWidth, vramWindowHeight); +#endif + + sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ABGR1555, SDL_TEXTUREACCESS_STREAMING, DISPLAY_WIDTH, DISPLAY_HEIGHT); + if (sdlTexture == NULL) { + fprintf(stderr, "Texture could not be created! SDL_Error: %s\n", SDL_GetError()); + return 1; + } + +#if ENABLE_VRAM_VIEW + vramTexture = SDL_CreateTexture(vramRenderer, SDL_PIXELFORMAT_ABGR1555, SDL_TEXTUREACCESS_STREAMING, vramWindowWidth, vramWindowHeight); + if (vramTexture == NULL) { + fprintf(stderr, "Texture could not be created! SDL_Error: %s\n", SDL_GetError()); + return 1; + } +#endif + + simTime = curGameTime = lastGameTime = SDL_GetPerformanceCounter(); + + isFrameAvailable.value = 0; + vBlankSemaphore = SDL_CreateSemaphore(0); + if (vBlankSemaphore == NULL) { + SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to create Semaphore:\n %s", SDL_GetError()); + } + +#if ENABLE_AUDIO + SDL_AudioSpec want; + + SDL_memset(&want, 0, sizeof(want)); /* or SDL_zero(want) */ + want.freq = 48000; + want.format = AUDIO_F32; + want.channels = 2; + want.samples = (want.freq / 60); cgb_audio_init(48000); - // if (SDL_OpenAudio(&want, 0) < 0) - // SDL_Log("Failed to open audio: %s", SDL_GetError()); - // else { - // if (want.format != AUDIO_F32) /* we let this one thing change. */ - // SDL_Log("We didn't get Float32 audio format."); - // SDL_PauseAudio(0); - // } - // #endif - - // VDraw(sdlTexture); - // #if ENABLE_VRAM_VIEW - // VramDraw(vramTexture); - // #endif - // // Prevent the multiplayer screen from being drawn ( see core.c:GameInit() ) - // REG_RCNT = 0x8000; - - // mainLoopThread = SDL_CreateThread(DoMain, "AgbMain", NULL); - - // double accumulator = 0.0; - - // #if 0 - // memset(&internalClock, 0, sizeof(internalClock)); - // internalClock.status = SIIRTCINFO_24HOUR; - // UpdateInternalClock(); - // #endif - - // REG_KEYINPUT = 0x3FF; - - // while (isRunning) { - // ProcessSDLEvents(); - - // if (!paused || stepOneFrame) { - // double dt = fixedTimestep / timeScale; // TODO: Fix speedup - // double deltaTime = 0; - - // curGameTime = SDL_GetPerformanceCounter(); - // if (stepOneFrame) { - // deltaTime = dt; - // } else { - // deltaTime = (double)((curGameTime - lastGameTime) / (double)SDL_GetPerformanceFrequency()); - // if (deltaTime > (dt * 5)) - // deltaTime = dt * 5; - // } - // lastGameTime = curGameTime; - - // accumulator += deltaTime; - - // while (accumulator >= dt) { - // REG_KEYINPUT = KEYS_MASK ^ Platform_GetKeyInput(); - // if (SDL_AtomicGet(&isFrameAvailable)) { - // VDraw(sdlTexture); - // SDL_AtomicSet(&isFrameAvailable, 0); - - // REG_DISPSTAT |= INTR_FLAG_VBLANK; - - // // TODO(Jace): I think this should be DMA_VBLANK. - // // If not, and it is HBLANK instead, add a note here, why it is! - // RunDMAs(DMA_VBLANK); - - // if (REG_DISPSTAT & DISPSTAT_VBLANK_INTR) - // gIntrTable[INTR_INDEX_VBLANK](); - // REG_DISPSTAT &= ~INTR_FLAG_VBLANK; - - // SDL_SemPost(vBlankSemaphore); - - // accumulator -= dt; - // } - // } - - // if (paused && stepOneFrame) { - // stepOneFrame = false; - // } - // } - - // SDL_RenderClear(sdlRenderer); - // SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); - - // #if ENABLE_VRAM_VIEW - // VramDraw(vramTexture); - // SDL_RenderClear(vramRenderer); - // SDL_RenderCopy(vramRenderer, vramTexture, NULL, NULL); - // #endif - // if (videoScaleChanged) { - // SDL_SetWindowSize(sdlWindow, DISPLAY_WIDTH * videoScale, DISPLAY_HEIGHT * videoScale); - // videoScaleChanged = false; - // } - // SDL_RenderPresent(sdlRenderer); - // #if ENABLE_VRAM_VIEW - // SDL_RenderPresent(vramRenderer); - // #endif - // } - - // // StoreSaveFile(); - // CloseSaveFile(); - - // SDL_DestroyWindow(sdlWindow); - // SDL_Quit(); - // return 0; + // if (SDL_OpenAudio(&want, 0) < 0) + // SDL_Log("Failed to open audio: %s", SDL_GetError()); + // else { + // if (want.format != AUDIO_F32) /* we let this one thing change. */ + // SDL_Log("We didn't get Float32 audio format."); + // SDL_PauseAudio(0); + // } +#endif + VDraw(sdlTexture); +#if ENABLE_VRAM_VIEW + VramDraw(vramTexture); +#endif + // Prevent the multiplayer screen from being drawn ( see core.c:GameInit() ) REG_RCNT = 0x8000; - AgbMain(); + mainLoopThread = SDL_CreateThread(DoMain, "AgbMain", NULL); + controlThread = SDL_CreateThread(DoControl, "DoControl", NULL); + // struct t_ee_thread agbThread, controlThread; + // int agbThreadId, controlThreadId; + + // printf("\nBeginning thread demo:\n"); + + // agbThread.status = 0; + // agbThread.func = (void *)DoMain; + // agbThread.stack = (void *)((int *)malloc(0x800) + 0x800 - 4); + // agbThread.initial_priority = 0x1e; + + // controlThread.status = 0; + // controlThread.func = (void *)DoControl; + // controlThread.stack = (void *)((int *)malloc(0x800) + 0x800 - 4); + // controlThread.initial_priority = 0x1e; + + // agbThreadId = CreateThread(&agbThread); + // controlThreadId = CreateThread(&controlThread); + + // if (agbThreadId <= 0) { + // printf("Server thread failed to start. %i\n", agbThreadId); + // return -1; + // } + + // if (controlThreadId <= 0) { + // printf("Server thread failed to start. %i\n", controlThreadId); + // return -1; + // } + // printf("Starting threads\n"); + + // StartThread(agbThreadId, NULL); + // StartThread(controlThreadId, NULL); + + // // Set the time in miliseconds to call the function RotateThreads + // SetAlarm(16, RotateThreads, 0); + + while (isRunning) { + SleepThread(); + } + + // TerminateThread(agbThreadId); + // printf("Terminated agb thread.\n"); + // TerminateThread(controlThreadId); + // printf("Terminated control thread.\n"); + + // StoreSaveFile(); + // CloseSaveFile(); + + SDL_DestroyWindow(sdlWindow); + SDL_Quit(); + return 0; +} + +int DoControl(void *d) +{ + printf("CONTROL??"); + double accumulator = 0.0; + +#if 0 + memset(&internalClock, 0, sizeof(internalClock)); + internalClock.status = SIIRTCINFO_24HOUR; + UpdateInternalClock(); +#endif + + REG_KEYINPUT = 0x3FF; + + while (TRUE) { + printf("PROCESS EVENT\n"); + ProcessSDLEvents(); + + if (!paused || stepOneFrame) { + double dt = fixedTimestep / timeScale; // TODO: Fix speedup + double deltaTime = 0; + + curGameTime = SDL_GetPerformanceCounter(); + if (stepOneFrame) { + deltaTime = dt; + } else { + deltaTime = (double)((curGameTime - lastGameTime) / (double)SDL_GetPerformanceFrequency()); + if (deltaTime > (dt * 5)) + deltaTime = dt * 5; + } + lastGameTime = curGameTime; + + accumulator += deltaTime; + + while (accumulator >= dt) { + printf("WAITING %d %d\n", accumulator, dt); + REG_KEYINPUT = KEYS_MASK ^ Platform_GetKeyInput(); + if (SDL_AtomicGet(&isFrameAvailable)) { + VDraw(sdlTexture); + SDL_AtomicSet(&isFrameAvailable, 0); + + REG_DISPSTAT |= INTR_FLAG_VBLANK; + + // TODO(Jace): I think this should be DMA_VBLANK. + // If not, and it is HBLANK instead, add a note here, why it is! + RunDMAs(DMA_VBLANK); + + if (REG_DISPSTAT & DISPSTAT_VBLANK_INTR) + gIntrTable[INTR_INDEX_VBLANK](); + REG_DISPSTAT &= ~INTR_FLAG_VBLANK; + + SDL_SemPost(vBlankSemaphore); + + accumulator -= dt; + } + } + + if (paused && stepOneFrame) { + stepOneFrame = false; + } + } + + SDL_RenderClear(sdlRenderer); + SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); + +#if ENABLE_VRAM_VIEW + VramDraw(vramTexture); + SDL_RenderClear(vramRenderer); + SDL_RenderCopy(vramRenderer, vramTexture, NULL, NULL); +#endif + if (videoScaleChanged) { + SDL_SetWindowSize(sdlWindow, DISPLAY_WIDTH * videoScale, DISPLAY_HEIGHT * videoScale); + videoScaleChanged = false; + } + SDL_RenderPresent(sdlRenderer); +#if ENABLE_VRAM_VIEW + SDL_RenderPresent(vramRenderer); +#endif + } return 0; } @@ -412,7 +482,7 @@ static void CloseSaveFile() static u16 keys; u32 fullScreenFlags = 0; -// static SDL_DisplayMode sdlDispMode = { 0 }; +static SDL_DisplayMode sdlDispMode = { 0 }; void Platform_QueueAudio(const void *data, uint32_t bytesCount) { @@ -429,105 +499,105 @@ void Platform_QueueAudio(const void *data, uint32_t bytesCount) void ProcessSDLEvents(void) { - // SDL_Event event; - - // while (SDL_PollEvent(&event)) { - // SDL_Keycode keyCode = event.key.keysym.sym; - // Uint16 keyMod = event.key.keysym.mod; - - // switch (event.type) { - // case SDL_QUIT: - // isRunning = false; - // break; - // case SDL_KEYUP: - // switch (event.key.keysym.sym) { - // HANDLE_KEYUP(A_BUTTON) - // HANDLE_KEYUP(B_BUTTON) - // HANDLE_KEYUP(START_BUTTON) - // HANDLE_KEYUP(SELECT_BUTTON) - // HANDLE_KEYUP(L_BUTTON) - // HANDLE_KEYUP(R_BUTTON) - // HANDLE_KEYUP(DPAD_UP) - // HANDLE_KEYUP(DPAD_DOWN) - // HANDLE_KEYUP(DPAD_LEFT) - // HANDLE_KEYUP(DPAD_RIGHT) - // case SDLK_SPACE: - // if (speedUp) { - // speedUp = false; - // timeScale = 1.0; - // SDL_ClearQueuedAudio(1); - // SDL_PauseAudio(0); - // } - // break; - // } - // break; - // case SDL_KEYDOWN: - // if (keyCode == SDLK_RETURN && (keyMod & KMOD_ALT)) { - // fullScreenFlags ^= SDL_WINDOW_FULLSCREEN_DESKTOP; - // if (fullScreenFlags & SDL_WINDOW_FULLSCREEN_DESKTOP) { - // SDL_GetWindowDisplayMode(sdlWindow, &sdlDispMode); - // preFullscreenVideoScale = videoScale; - // } else { - // SDL_SetWindowDisplayMode(sdlWindow, &sdlDispMode); - // videoScale = preFullscreenVideoScale; - // } - // SDL_SetWindowFullscreen(sdlWindow, fullScreenFlags); - - // SDL_SetWindowSize(sdlWindow, DISPLAY_WIDTH * videoScale, DISPLAY_HEIGHT * videoScale); - // videoScaleChanged = FALSE; - // } else - // switch (event.key.keysym.sym) { - // HANDLE_KEYDOWN(A_BUTTON) - // HANDLE_KEYDOWN(B_BUTTON) - // HANDLE_KEYDOWN(START_BUTTON) - // HANDLE_KEYDOWN(SELECT_BUTTON) - // HANDLE_KEYDOWN(L_BUTTON) - // HANDLE_KEYDOWN(R_BUTTON) - // HANDLE_KEYDOWN(DPAD_UP) - // HANDLE_KEYDOWN(DPAD_DOWN) - // HANDLE_KEYDOWN(DPAD_LEFT) - // HANDLE_KEYDOWN(DPAD_RIGHT) - // case SDLK_r: - // if (event.key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) { - // DoSoftReset(); - // } - // break; - // case SDLK_p: - // if (event.key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) { - // paused = !paused; - // } - // break; - // case SDLK_SPACE: - // if (!speedUp) { - // speedUp = true; - // timeScale = 5.0; - // SDL_PauseAudio(1); - // } - // break; - // case SDLK_F10: - // paused = true; - // stepOneFrame = true; - // break; - // } - // break; - // case SDL_WINDOWEVENT: - // if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { - // unsigned int w = event.window.data1; - // unsigned int h = event.window.data2; - - // videoScale = 0; - // if (w / DISPLAY_WIDTH > videoScale) - // videoScale = w / DISPLAY_WIDTH; - // if (h / DISPLAY_HEIGHT > videoScale) - // videoScale = h / DISPLAY_HEIGHT; - // if (videoScale < 1) - // videoScale = 1; - - // videoScaleChanged = true; - // } - // break; - // } - // } + SDL_Event event; + + while (SDL_PollEvent(&event)) { + SDL_Keycode keyCode = event.key.keysym.sym; + Uint16 keyMod = event.key.keysym.mod; + + switch (event.type) { + case SDL_QUIT: + isRunning = false; + break; + case SDL_KEYUP: + switch (event.key.keysym.sym) { + HANDLE_KEYUP(A_BUTTON) + HANDLE_KEYUP(B_BUTTON) + HANDLE_KEYUP(START_BUTTON) + HANDLE_KEYUP(SELECT_BUTTON) + HANDLE_KEYUP(L_BUTTON) + HANDLE_KEYUP(R_BUTTON) + HANDLE_KEYUP(DPAD_UP) + HANDLE_KEYUP(DPAD_DOWN) + HANDLE_KEYUP(DPAD_LEFT) + HANDLE_KEYUP(DPAD_RIGHT) + case SDLK_SPACE: + if (speedUp) { + speedUp = false; + timeScale = 1.0; + SDL_ClearQueuedAudio(1); + SDL_PauseAudio(0); + } + break; + } + break; + case SDL_KEYDOWN: + if (keyCode == SDLK_RETURN && (keyMod & KMOD_ALT)) { + fullScreenFlags ^= SDL_WINDOW_FULLSCREEN_DESKTOP; + if (fullScreenFlags & SDL_WINDOW_FULLSCREEN_DESKTOP) { + SDL_GetWindowDisplayMode(sdlWindow, &sdlDispMode); + preFullscreenVideoScale = videoScale; + } else { + SDL_SetWindowDisplayMode(sdlWindow, &sdlDispMode); + videoScale = preFullscreenVideoScale; + } + SDL_SetWindowFullscreen(sdlWindow, fullScreenFlags); + + SDL_SetWindowSize(sdlWindow, DISPLAY_WIDTH * videoScale, DISPLAY_HEIGHT * videoScale); + videoScaleChanged = FALSE; + } else + switch (event.key.keysym.sym) { + HANDLE_KEYDOWN(A_BUTTON) + HANDLE_KEYDOWN(B_BUTTON) + HANDLE_KEYDOWN(START_BUTTON) + HANDLE_KEYDOWN(SELECT_BUTTON) + HANDLE_KEYDOWN(L_BUTTON) + HANDLE_KEYDOWN(R_BUTTON) + HANDLE_KEYDOWN(DPAD_UP) + HANDLE_KEYDOWN(DPAD_DOWN) + HANDLE_KEYDOWN(DPAD_LEFT) + HANDLE_KEYDOWN(DPAD_RIGHT) + case SDLK_r: + if (event.key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) { + DoSoftReset(); + } + break; + case SDLK_p: + if (event.key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) { + paused = !paused; + } + break; + case SDLK_SPACE: + if (!speedUp) { + speedUp = true; + timeScale = 5.0; + SDL_PauseAudio(1); + } + break; + case SDLK_F10: + paused = true; + stepOneFrame = true; + break; + } + break; + case SDL_WINDOWEVENT: + if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { + unsigned int w = event.window.data1; + unsigned int h = event.window.data2; + + videoScale = 0; + if (w / DISPLAY_WIDTH > videoScale) + videoScale = w / DISPLAY_WIDTH; + if (h / DISPLAY_HEIGHT > videoScale) + videoScale = h / DISPLAY_HEIGHT; + if (videoScale < 1) + videoScale = 1; + + videoScaleChanged = true; + } + break; + } + } } #ifdef _WIN32 @@ -748,19 +818,17 @@ void DmaStop(int dmaNum) dma->control &= ~(DMA_ENABLE | DMA_START_MASK | DMA_DREQ_ON | DMA_REPEAT); } -void DmaWait(int dmaNum) { printf("DmaWait: %d\n", dmaNum); } - -// void DmaWait(int dmaNum) -// { -// vu32 *ctrlRegs = ®_DMA0CNT; -// #if !USE_NEW_DMA -// while (ctrlRegs[dmaNum * 3] & (DMA_ENABLE << 16)) -// ; -// #else -// while (ctrlRegs[dmaNum] & (DMA_ENABLE << 16)) -// ; -// #endif -// } +void DmaWait(int dmaNum) +{ + vu32 *ctrlRegs = ®_DMA0CNT; +#if !USE_NEW_DMA + while (ctrlRegs[dmaNum * 3] & (DMA_ENABLE << 16)) + ; +#else + while (ctrlRegs[dmaNum] & (DMA_ENABLE << 16)) + ; +#endif +} void TestFunc(void) { } @@ -2023,24 +2091,28 @@ void VramDraw(SDL_Texture *texture) } #endif -// void VDraw(SDL_Texture *texture) -// { -// memset(gameImage, 0, sizeof(gameImage)); -// DrawFrame(gameImage); -// SDL_UpdateTexture(texture, NULL, gameImage, DISPLAY_WIDTH * sizeof(Uint16)); -// REG_VCOUNT = 161; // prep for being in VBlank period -// } +void VDraw(SDL_Texture *texture) +{ + memset(gameImage, 0, sizeof(gameImage)); + DrawFrame(gameImage); + SDL_UpdateTexture(texture, NULL, gameImage, DISPLAY_WIDTH * sizeof(Uint16)); + REG_VCOUNT = 161; // prep for being in VBlank period +} int DoMain(void *data) { + printf("THREAD!\n"); AgbMain(); return 0; } void VBlankIntrWait(void) { - // SDL_AtomicSet(&isFrameAvailable, 1); - // SDL_SemWait(vBlankSemaphore); + printf("INTRWAIT\n"); + SDL_AtomicSet(&isFrameAvailable, 1); + printf("WAITING FOR SEM\n"); + while (vBlankSemaphore) + SDL_SemWait(vBlankSemaphore); } u8 BinToBcd(u8 bin) From 1a908bcbb67cf4c58dff09487772e6224718334c Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Sat, 30 Nov 2024 19:29:03 +0000 Subject: [PATCH 04/11] it boots! --- src/core.c | 2 +- src/platform/ps2/ps2.c | 258 ++++++++++++++++++++++++++++++++--------- 2 files changed, 205 insertions(+), 55 deletions(-) diff --git a/src/core.c b/src/core.c index 067fc6f3f..c7a9ef380 100644 --- a/src/core.c +++ b/src/core.c @@ -402,7 +402,7 @@ void GameLoop(void) // Wait for vblank to finish while (REG_DISPSTAT & DISPSTAT_VBLANK) { - SleepThread(); + // SleepThread(); } }; } diff --git a/src/platform/ps2/ps2.c b/src/platform/ps2/ps2.c index dc2cc9ed0..f0b19d0a2 100644 --- a/src/platform/ps2/ps2.c +++ b/src/platform/ps2/ps2.c @@ -106,6 +106,7 @@ SDL_Texture *vramTexture; unsigned int videoScale = INITIAL_VIDEO_SCALE; unsigned int preFullscreenVideoScale = INITIAL_VIDEO_SCALE; SDL_sem *vBlankSemaphore; +SDL_atomic_t isVblankReady; SDL_atomic_t isFrameAvailable; bool speedUp = false; bool videoScaleChanged = false; @@ -146,10 +147,141 @@ void Platform_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); } #include +static volatile int counter = 0; +static volatile int continueloop; + +#define THREAD_STACK_SIZE (128 * 1024) + +static u8 thread_stack[THREAD_STACK_SIZE] ALIGNED(16); +static ee_thread_t thread_thread; +static int thread_threadid; + +static u8 thread_stack2[THREAD_STACK_SIZE] ALIGNED(16); +static ee_thread_t thread_thread2; +static int thread_threadid2; + +static u8 disp_stack[THREAD_STACK_SIZE] ALIGNED(16); +static int disp_threadid; + +void TheThread(void *arg); +void TheThread2(void *arg); + +// void dispatcher(void *apParam) +// { + +// while (1) { +// printf("Dispatch\n"); + +// SleepThread(); + +// } /* end while */ + +// } /* end dispatcher */ + +// void alarmfunction(s32 id, u16 time, void *arg) +// { +// counter++; +// iWakeupThread(disp_threadid); +// iRotateThreadReadyQueue(30); +// iSetAlarm(625, alarmfunction, NULL); +// } + +// int main(int argc, char **argv) +// { +// extern void *_gp; + +// // EEUG : pay attention at the priority of your 'main' thread. +// // Make sure that it is higher than threads you create +// //(i.e. priority value is lower than 0x1E). I think ps2link sets it to 64 +// // - set the priority of your main thread to '0x1D': +// // - create/start your "vegetables counters", set alarm handlers etc.; +// // - lower priority of your 'main' thread +// ChangeThreadPriority(GetThreadId(), 29); // 29 is lower than 30 ;) + +// continueloop = 1; + +// SetAlarm(625, alarmfunction, NULL); + +// printf("\ncreating thread\n"); + +// thread_thread.func = dispatcher; +// thread_thread.stack = disp_stack; +// thread_thread.stack_size = THREAD_STACK_SIZE; +// thread_thread.gp_reg = &_gp; +// thread_thread.initial_priority = 0; +// StartThread(disp_threadid = CreateThread(&thread_thread), NULL); + +// thread_thread.func = TheThread; +// thread_thread.stack = thread_stack; +// thread_thread.stack_size = THREAD_STACK_SIZE; +// thread_thread.gp_reg = &_gp; +// thread_thread.initial_priority = 30; +// if ((thread_threadid = CreateThread(&thread_thread)) < 0) { +// printf("CREATE THREAD ERROR!!!\n"); +// return -1; +// } +// StartThread(thread_threadid, NULL); +// printf("thread started\n"); + +// thread_thread2.func = TheThread2; +// thread_thread2.stack = thread_stack2; +// thread_thread2.stack_size = THREAD_STACK_SIZE; +// thread_thread2.gp_reg = &_gp; +// thread_thread2.initial_priority = 31; +// if ((thread_threadid2 = CreateThread(&thread_thread2)) < 0) { +// printf("CREATE THREAD ERROR!!!\n"); +// return -1; +// } +// StartThread(thread_threadid2, NULL); +// printf("thread 2 started\n"); + +// ChangeThreadPriority(GetThreadId(), 30); + +// while (continueloop == 1) { } + +// printf("terminating\n"); +// TerminateThread(thread_threadid); +// DeleteThread(thread_threadid); + +// printf("\ndone\n"); +// return 0; +// } + +// void TheThread(void *arg) +// { +// while (1) { +// printf("Thread loop iter\n"); +// if (counter > 50) +// continueloop = 0; +// SleepThread(); +// } +// } +// void TheThread2(void *arg) +// { +// while (1) { +// printf("Thread 2 loop iter\n"); +// if (counter > 50) +// continueloop = 0; +// SleepThread(); +// } +// } + +void dispatcher(void *apParam) +{ + + while (1) { + + SleepThread(); + + } /* end while */ + +} /* end dispatcher */ + void RotateThreads(s32 id, u16 time, void *arg) { - printf("rorate\n"); - iRotateThreadReadyQueue(0x1e); + iWakeupThread(disp_threadid); + iRotateThreadReadyQueue(30); + iSetAlarm(1, RotateThreads, NULL); } int main(int argc, char **argv) @@ -250,6 +382,7 @@ int main(int argc, char **argv) simTime = curGameTime = lastGameTime = SDL_GetPerformanceCounter(); isFrameAvailable.value = 0; + isVblankReady.value = 0; vBlankSemaphore = SDL_CreateSemaphore(0); if (vBlankSemaphore == NULL) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to create Semaphore:\n %s", SDL_GetError()); @@ -281,63 +414,69 @@ int main(int argc, char **argv) // Prevent the multiplayer screen from being drawn ( see core.c:GameInit() ) REG_RCNT = 0x8000; - mainLoopThread = SDL_CreateThread(DoMain, "AgbMain", NULL); - controlThread = SDL_CreateThread(DoControl, "DoControl", NULL); - // struct t_ee_thread agbThread, controlThread; - // int agbThreadId, controlThreadId; - - // printf("\nBeginning thread demo:\n"); - - // agbThread.status = 0; - // agbThread.func = (void *)DoMain; - // agbThread.stack = (void *)((int *)malloc(0x800) + 0x800 - 4); - // agbThread.initial_priority = 0x1e; - - // controlThread.status = 0; - // controlThread.func = (void *)DoControl; - // controlThread.stack = (void *)((int *)malloc(0x800) + 0x800 - 4); - // controlThread.initial_priority = 0x1e; - - // agbThreadId = CreateThread(&agbThread); - // controlThreadId = CreateThread(&controlThread); - - // if (agbThreadId <= 0) { - // printf("Server thread failed to start. %i\n", agbThreadId); - // return -1; - // } + ChangeThreadPriority(GetThreadId(), 29); // 29 is lower than 30 ;) + + // Set the time in miliseconds to call the function RotateThreads + SetAlarm(1, RotateThreads, 0); + + // mainLoopThread = SDL_CreateThread(DoMain, "AgbMain", NULL); + // controlThread = SDL_CreateThread(DoControl, "DoControl", NULL); + struct t_ee_thread agbThread, controlThread, thread_thread; + int agbThreadId, controlThreadId; + + printf("\nBeginning thread demo:\n"); + + thread_thread.func = dispatcher; + thread_thread.stack = disp_stack; + thread_thread.stack_size = THREAD_STACK_SIZE; + thread_thread.gp_reg = &_gp; + thread_thread.initial_priority = 0; + StartThread(disp_threadid = CreateThread(&thread_thread), NULL); + + thread_thread.func = DoMain; + thread_thread.stack = thread_stack; + thread_thread.stack_size = THREAD_STACK_SIZE; + thread_thread.gp_reg = &_gp; + thread_thread.initial_priority = 30; + if ((agbThreadId = CreateThread(&thread_thread)) < 0) { + printf("CREATE THREAD ERROR!!!\n"); + return -1; + } - // if (controlThreadId <= 0) { - // printf("Server thread failed to start. %i\n", controlThreadId); - // return -1; - // } - // printf("Starting threads\n"); + printf("Starting threads\n"); + StartThread(agbThreadId, NULL); - // StartThread(agbThreadId, NULL); - // StartThread(controlThreadId, NULL); + ChangeThreadPriority(GetThreadId(), 30); - // // Set the time in miliseconds to call the function RotateThreads - // SetAlarm(16, RotateThreads, 0); - - while (isRunning) { - SleepThread(); - } + DoControl(NULL); + // printf("terminating\n"); // TerminateThread(agbThreadId); - // printf("Terminated agb thread.\n"); - // TerminateThread(controlThreadId); - // printf("Terminated control thread.\n"); + // DeleteThread(agbThreadId); // StoreSaveFile(); // CloseSaveFile(); + // while (1) { + // if (SDL_AtomicGet(&isFrameAvailable)) { + // SDL_AtomicSet(&isFrameAvailable, 0); + // REG_DISPSTAT |= INTR_FLAG_VBLANK; + // RunDMAs(DMA_VBLANK); + // if (REG_DISPSTAT & DISPSTAT_VBLANK_INTR) + // gIntrTable[INTR_INDEX_VBLANK](); + // REG_DISPSTAT &= ~INTR_FLAG_VBLANK; + + // SDL_SemPost(vBlankSemaphore); + // } + // } SDL_DestroyWindow(sdlWindow); SDL_Quit(); return 0; } -int DoControl(void *d) +int DoControl(void *data) { - printf("CONTROL??"); + printf("CONTROL??\n"); double accumulator = 0.0; #if 0 @@ -348,8 +487,8 @@ int DoControl(void *d) REG_KEYINPUT = 0x3FF; - while (TRUE) { - printf("PROCESS EVENT\n"); + while (isRunning) { + // printf("PROCESS EVENT\n"); ProcessSDLEvents(); if (!paused || stepOneFrame) { @@ -369,9 +508,10 @@ int DoControl(void *d) accumulator += deltaTime; while (accumulator >= dt) { - printf("WAITING %d %d\n", accumulator, dt); + // printf("WAITING %d %d\n", accumulator, dt); REG_KEYINPUT = KEYS_MASK ^ Platform_GetKeyInput(); if (SDL_AtomicGet(&isFrameAvailable)) { + // printf("Frame is ready\n"); VDraw(sdlTexture); SDL_AtomicSet(&isFrameAvailable, 0); @@ -386,8 +526,11 @@ int DoControl(void *d) REG_DISPSTAT &= ~INTR_FLAG_VBLANK; SDL_SemPost(vBlankSemaphore); + // SDL_AtomicSet(&isVblankReady, 1); accumulator -= dt; + } else { + // SleepThread(); } } @@ -412,6 +555,7 @@ int DoControl(void *d) #if ENABLE_VRAM_VIEW SDL_RenderPresent(vramRenderer); #endif + // SleepThread(); } return 0; } @@ -680,6 +824,7 @@ static void CPUWriteByte(void *dest, uint8_t val) { *(uint8_t *)dest = val; } static void RunDMAs(u32 type) { + // printf("Runing DMAs\n"); for (int dmaNum = 0; dmaNum < DMA_COUNT; dmaNum++) { struct DMATransfer *dma = &DMAList[dmaNum]; #if !USE_NEW_DMA @@ -823,11 +968,11 @@ void DmaWait(int dmaNum) vu32 *ctrlRegs = ®_DMA0CNT; #if !USE_NEW_DMA while (ctrlRegs[dmaNum * 3] & (DMA_ENABLE << 16)) - ; #else while (ctrlRegs[dmaNum] & (DMA_ENABLE << 16)) - ; #endif + // SleepThread(); + ; } void TestFunc(void) { } @@ -2101,18 +2246,23 @@ void VDraw(SDL_Texture *texture) int DoMain(void *data) { - printf("THREAD!\n"); + printf("DO MAIN THREAD!\n"); AgbMain(); return 0; } void VBlankIntrWait(void) { - printf("INTRWAIT\n"); + // printf("INTRWAIT\n"); SDL_AtomicSet(&isFrameAvailable, 1); - printf("WAITING FOR SEM\n"); - while (vBlankSemaphore) - SDL_SemWait(vBlankSemaphore); + // printf("WAITING FOR SEM\n"); + // while (!SDL_AtomicGet(&isVblankReady)) { + // printf("WAITING FOR SEM\n"); + // // SleepThread(); + // } + // printf("SEM DONE\n"); + // SDL_AtomicSet(&isVblankReady, 0); + SDL_SemWait(vBlankSemaphore); } u8 BinToBcd(u8 bin) From d187f5665a513a7bad7d10f9c4897bce64e8a681 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Sun, 1 Dec 2024 17:19:45 +0000 Subject: [PATCH 05/11] running --- include/config.h | 2 +- include/gba/defines.h | 4 +- src/platform/ps2/ps2.c | 151 ++++++++++++++++---------- src/platform/shared/audio/cgb_audio.c | 2 +- 4 files changed, 97 insertions(+), 62 deletions(-) diff --git a/include/config.h b/include/config.h index afadc0557..8824d101c 100644 --- a/include/config.h +++ b/include/config.h @@ -17,7 +17,7 @@ #define USE_NEW_DMA 1 #endif -#define TAS_TESTING 0 +#define TAS_TESTING 1 #define TAS_TESTING_WIDESCREEN_HACK 1 #endif // GUARD_SA2_CONFIG_H diff --git a/include/gba/defines.h b/include/gba/defines.h index 057138435..165ce41ed 100644 --- a/include/gba/defines.h +++ b/include/gba/defines.h @@ -37,8 +37,8 @@ #define OAM_ENTRY_COUNT 128 #if PORTABLE // NOTE: Used in gba/types.h, so they have to be defined before the #include -#define DISPLAY_WIDTH 426 -#define DISPLAY_HEIGHT 240 +#define DISPLAY_WIDTH 240 +#define DISPLAY_HEIGHT 160 //#include "gba/types.h" // TODO: Fix #define OAM_SIZE (OAM_ENTRY_COUNT*sizeof(OamData)) diff --git a/src/platform/ps2/ps2.c b/src/platform/ps2/ps2.c index f0b19d0a2..e5687452b 100644 --- a/src/platform/ps2/ps2.c +++ b/src/platform/ps2/ps2.c @@ -150,7 +150,7 @@ void Platform_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); } static volatile int counter = 0; static volatile int continueloop; -#define THREAD_STACK_SIZE (128 * 1024) +#define THREAD_STACK_SIZE (512 * 1024) static u8 thread_stack[THREAD_STACK_SIZE] ALIGNED(16); static ee_thread_t thread_thread; @@ -339,7 +339,7 @@ int main(int argc, char **argv) } #endif - sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_PRESENTVSYNC); + sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, 0); if (sdlRenderer == NULL) { fprintf(stderr, "Renderer could not be created! SDL_Error: %s\n", SDL_GetError()); return 1; @@ -414,41 +414,44 @@ int main(int argc, char **argv) // Prevent the multiplayer screen from being drawn ( see core.c:GameInit() ) REG_RCNT = 0x8000; - ChangeThreadPriority(GetThreadId(), 29); // 29 is lower than 30 ;) - - // Set the time in miliseconds to call the function RotateThreads - SetAlarm(1, RotateThreads, 0); - - // mainLoopThread = SDL_CreateThread(DoMain, "AgbMain", NULL); - // controlThread = SDL_CreateThread(DoControl, "DoControl", NULL); - struct t_ee_thread agbThread, controlThread, thread_thread; - int agbThreadId, controlThreadId; - - printf("\nBeginning thread demo:\n"); - - thread_thread.func = dispatcher; - thread_thread.stack = disp_stack; - thread_thread.stack_size = THREAD_STACK_SIZE; - thread_thread.gp_reg = &_gp; - thread_thread.initial_priority = 0; - StartThread(disp_threadid = CreateThread(&thread_thread), NULL); - - thread_thread.func = DoMain; - thread_thread.stack = thread_stack; - thread_thread.stack_size = THREAD_STACK_SIZE; - thread_thread.gp_reg = &_gp; - thread_thread.initial_priority = 30; - if ((agbThreadId = CreateThread(&thread_thread)) < 0) { - printf("CREATE THREAD ERROR!!!\n"); - return -1; - } + // ChangeThreadPriority(GetThreadId(), 29); // 29 is lower than 30 ;) + + // // Set the time in miliseconds to call the function RotateThreads + // SetAlarm(1, RotateThreads, 0); + + // // mainLoopThread = SDL_CreateThread(DoMain, "AgbMain", NULL); + // // controlThread = SDL_CreateThread(DoControl, "DoControl", NULL); + // struct t_ee_thread agbThread, controlThread, thread_thread; + // int agbThreadId, controlThreadId; + + // printf("\nBeginning thread demo:\n"); + + // thread_thread.func = dispatcher; + // thread_thread.stack = disp_stack; + // thread_thread.stack_size = THREAD_STACK_SIZE; + // thread_thread.gp_reg = &_gp; + // thread_thread.initial_priority = 0; + // StartThread(disp_threadid = CreateThread(&thread_thread), NULL); + + // thread_thread.func = DoMain; + // thread_thread.stack = thread_stack; + // thread_thread.stack_size = THREAD_STACK_SIZE; + // thread_thread.gp_reg = &_gp; + // thread_thread.initial_priority = 30; + // if ((agbThreadId = CreateThread(&thread_thread)) < 0) { + // printf("CREATE THREAD ERROR!!!\n"); + // return -1; + // } + + // printf("Starting threads\n"); + // StartThread(agbThreadId, NULL); - printf("Starting threads\n"); - StartThread(agbThreadId, NULL); + // ChangeThreadPriority(GetThreadId(), 30); + // REG_KEYINPUT = 0x3FF; - ChangeThreadPriority(GetThreadId(), 30); + DoMain(NULL); - DoControl(NULL); + // DoControl(NULL); // printf("terminating\n"); // TerminateThread(agbThreadId); @@ -547,10 +550,10 @@ int DoControl(void *data) SDL_RenderClear(vramRenderer); SDL_RenderCopy(vramRenderer, vramTexture, NULL, NULL); #endif - if (videoScaleChanged) { - SDL_SetWindowSize(sdlWindow, DISPLAY_WIDTH * videoScale, DISPLAY_HEIGHT * videoScale); - videoScaleChanged = false; - } + // if (videoScaleChanged) { + // SDL_SetWindowSize(sdlWindow, DISPLAY_WIDTH * videoScale, DISPLAY_HEIGHT * videoScale); + // videoScaleChanged = false; + // } SDL_RenderPresent(sdlRenderer); #if ENABLE_VRAM_VIEW SDL_RenderPresent(vramRenderer); @@ -2164,8 +2167,8 @@ static void DrawFrame(uint16_t *pixels) { int i; int j; - static uint16_t scanlines[DISPLAY_HEIGHT][DISPLAY_WIDTH]; - unsigned int blendMode = (REG_BLDCNT >> 6) & 3; + // static uint16_t scanlines[DISPLAY_HEIGHT][DISPLAY_WIDTH]; + // unsigned int blendMode = (REG_BLDCNT >> 6) & 3; for (i = 0; i < DISPLAY_HEIGHT; i++) { REG_VCOUNT = i; @@ -2175,10 +2178,23 @@ static void DrawFrame(uint16_t *pixels) gIntrTable[INTR_INDEX_VCOUNT](); } + unsigned int blendMode = (REG_BLDCNT >> 6) & 3; + uint16_t backdropColor = *(uint16_t *)PLTT; + if (REG_BLDCNT & BLDCNT_TGT1_BD) { + switch (blendMode) { + case 2: + backdropColor = alphaBrightnessIncrease(backdropColor); + break; + case 3: + backdropColor = alphaBrightnessDecrease(backdropColor); + break; + } + } + // Render the backdrop color before the each individual scanline. // HBlank interrupt code could have changed it inbetween lines. - memsetu16(scanlines[i], *(uint16_t *)PLTT, DISPLAY_WIDTH); - DrawScanline(scanlines[i], i); + memsetu16(&pixels[i * DISPLAY_WIDTH], backdropColor, DISPLAY_WIDTH); + DrawScanline(&pixels[i * DISPLAY_WIDTH], i); REG_DISPSTAT |= INTR_FLAG_HBLANK; @@ -2192,12 +2208,12 @@ static void DrawFrame(uint16_t *pixels) } // Copy to screen - for (i = 0; i < DISPLAY_HEIGHT; i++) { - uint16_t *src = scanlines[i]; - for (j = 0; j < DISPLAY_WIDTH; j++) { - pixels[i * DISPLAY_WIDTH + j] = src[j]; - } - } + // for (i = 0; i < DISPLAY_HEIGHT; i++) { + // uint16_t *src = scanlines[i]; + // for (j = 0; j < DISPLAY_WIDTH; j++) { + // pixels[i * DISPLAY_WIDTH + j] = src[j]; + // } + // } } #if ENABLE_VRAM_VIEW @@ -2251,18 +2267,37 @@ int DoMain(void *data) return 0; } +#include void VBlankIntrWait(void) { - // printf("INTRWAIT\n"); - SDL_AtomicSet(&isFrameAvailable, 1); - // printf("WAITING FOR SEM\n"); - // while (!SDL_AtomicGet(&isVblankReady)) { - // printf("WAITING FOR SEM\n"); - // // SleepThread(); - // } - // printf("SEM DONE\n"); - // SDL_AtomicSet(&isVblankReady, 0); - SDL_SemWait(vBlankSemaphore); + // // printf("INTRWAIT\n"); + // SDL_AtomicSet(&isFrameAvailable, 1); + // // printf("WAITING FOR SEM\n"); + // // while (!SDL_AtomicGet(&isVblankReady)) { + // // printf("WAITING FOR SEM\n"); + // // // SleepThread(); + // // } + // // printf("SEM DONE\n"); + // // SDL_AtomicSet(&isVblankReady, 0); + // SDL_SemWait(vBlankSemaphore); + + VDraw(sdlTexture); + + // SDL_AtomicSet(&isFrameAvailable, 0); + + REG_DISPSTAT |= INTR_FLAG_VBLANK; + + // TODO(Jace): I think this should be DMA_VBLANK. + // If not, and it is HBLANK instead, add a note here, why it is! + RunDMAs(DMA_VBLANK); + + if (REG_DISPSTAT & DISPSTAT_VBLANK_INTR) + gIntrTable[INTR_INDEX_VBLANK](); + REG_DISPSTAT &= ~INTR_FLAG_VBLANK; + + SDL_RenderClear(sdlRenderer); + SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); + SDL_RenderPresent(sdlRenderer); } u8 BinToBcd(u8 bin) diff --git a/src/platform/shared/audio/cgb_audio.c b/src/platform/shared/audio/cgb_audio.c index 51b6791d8..f4920d1bb 100644 --- a/src/platform/shared/audio/cgb_audio.c +++ b/src/platform/shared/audio/cgb_audio.c @@ -103,7 +103,7 @@ void cgb_trigger_note(u8 channel) void cgb_audio_generate(u16 samplesPerFrame) { - + return; float *outBuffer = gb.outBuffer; switch (REG_NR11 & 0xC0) { case 0x00: From facbd57cf7a979ea8ae7fabf39200f00474c87ac Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Sun, 1 Dec 2024 23:20:50 +0000 Subject: [PATCH 06/11] it "runs" --- include/gba/defines.h | 4 ++-- src/platform/ps2/ps2.c | 17 +++++------------ 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/include/gba/defines.h b/include/gba/defines.h index 165ce41ed..057138435 100644 --- a/include/gba/defines.h +++ b/include/gba/defines.h @@ -37,8 +37,8 @@ #define OAM_ENTRY_COUNT 128 #if PORTABLE // NOTE: Used in gba/types.h, so they have to be defined before the #include -#define DISPLAY_WIDTH 240 -#define DISPLAY_HEIGHT 160 +#define DISPLAY_WIDTH 426 +#define DISPLAY_HEIGHT 240 //#include "gba/types.h" // TODO: Fix #define OAM_SIZE (OAM_ENTRY_COUNT*sizeof(OamData)) diff --git a/src/platform/ps2/ps2.c b/src/platform/ps2/ps2.c index e5687452b..293fec5b0 100644 --- a/src/platform/ps2/ps2.c +++ b/src/platform/ps2/ps2.c @@ -314,8 +314,9 @@ int main(int argc, char **argv) const char *title = "SAT-R sa2"; #endif - sdlWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, DISPLAY_WIDTH * videoScale, - DISPLAY_HEIGHT * videoScale, SDL_WINDOW_SHOWN); + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); + + sdlWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN); if (sdlWindow == NULL) { fprintf(stderr, "Window could not be created! SDL_Error: %s\n", SDL_GetError()); return 1; @@ -371,6 +372,8 @@ int main(int argc, char **argv) return 1; } + SDL_SetTextureColorMod(sdlTexture, 140, 140, 140); + #if ENABLE_VRAM_VIEW vramTexture = SDL_CreateTexture(vramRenderer, SDL_PIXELFORMAT_ABGR1555, SDL_TEXTUREACCESS_STREAMING, vramWindowWidth, vramWindowHeight); if (vramTexture == NULL) { @@ -2167,8 +2170,6 @@ static void DrawFrame(uint16_t *pixels) { int i; int j; - // static uint16_t scanlines[DISPLAY_HEIGHT][DISPLAY_WIDTH]; - // unsigned int blendMode = (REG_BLDCNT >> 6) & 3; for (i = 0; i < DISPLAY_HEIGHT; i++) { REG_VCOUNT = i; @@ -2206,14 +2207,6 @@ static void DrawFrame(uint16_t *pixels) REG_DISPSTAT &= ~INTR_FLAG_HBLANK; REG_DISPSTAT &= ~INTR_FLAG_VCOUNT; } - - // Copy to screen - // for (i = 0; i < DISPLAY_HEIGHT; i++) { - // uint16_t *src = scanlines[i]; - // for (j = 0; j < DISPLAY_WIDTH; j++) { - // pixels[i * DISPLAY_WIDTH + j] = src[j]; - // } - // } } #if ENABLE_VRAM_VIEW From 8610387c5561a0ba77a552800eb7acc038403313 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Tue, 3 Dec 2024 21:18:19 +0000 Subject: [PATCH 07/11] example dockerfile --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 580bfd77a..35b3b538d 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -8,7 +8,7 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ && apt-get -y install --no-install-recommends binutils-arm-none-eabi \ gcc-arm-none-eabi libpng-dev build-essential clang-format-13 xorg-dev \ libsdl2-dev gcc-mingw-w64 texinfo flex bison gettext libgsl-dev libgmp3-dev \ - libmpfr-dev libmpc-dev zlib1g-dev autopoint cmake autoconf patch + libmpfr-dev libmpc-dev zlib1g-dev autopoint cmake automake patch WORKDIR /deps RUN git clone https://github.com/SAT-R/agbcc.git && cd agbcc && ./build.sh From b3357678113f7ce16f2361b46a767315e877cf4f Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Thu, 5 Dec 2024 20:50:10 +0000 Subject: [PATCH 08/11] some work --- include/config.h | 13 +++++++++ include/gba/dma_macros.h | 2 -- include/global.h | 7 ----- src/core.c | 7 ++--- src/platform/pret_sdl/sdl2.c | 42 +++++++++++++++++---------- src/platform/ps2/ps2.c | 5 ++-- src/platform/shared/audio/cgb_audio.c | 2 ++ 7 files changed, 46 insertions(+), 32 deletions(-) diff --git a/include/config.h b/include/config.h index 8824d101c..bbd642a2f 100644 --- a/include/config.h +++ b/include/config.h @@ -20,4 +20,17 @@ #define TAS_TESTING 1 #define TAS_TESTING_WIDESCREEN_HACK 1 +#if PLATFORM_GBA +#define ENABLE_AUDIO TRUE +#else +#ifdef PS2 +#define ENABLE_AUDIO FALSE +#define ENABLE_VRAM_VIEW FALSE +#else +#define ENABLE_AUDIO TRUE +#define ENABLE_VRAM_VIEW FALSE +#endif + +#endif + #endif // GUARD_SA2_CONFIG_H diff --git a/include/gba/dma_macros.h b/include/gba/dma_macros.h index cae132972..e99fac488 100644 --- a/include/gba/dma_macros.h +++ b/include/gba/dma_macros.h @@ -1,8 +1,6 @@ #ifndef GUARD_GBA_DMA_MACROS_H #define GUARD_GBA_DMA_MACROS_H -#include "config.h" - #if PLATFORM_GBA #define DmaSet(dmaNum, src, dest, control) \ { \ diff --git a/include/global.h b/include/global.h index f6c2d08d3..172c3eb70 100644 --- a/include/global.h +++ b/include/global.h @@ -4,13 +4,6 @@ #include "config.h" #include "gba/gba.h" -#if PLATFORM_GBA -#define ENABLE_AUDIO TRUE -#else -#define ENABLE_AUDIO TRUE -#define ENABLE_VRAM_VIEW !TRUE -#endif - #define CONST_DATA __attribute__((section(".data"))) // #include "types.h" diff --git a/src/core.c b/src/core.c index c7a9ef380..dfe1ce94f 100644 --- a/src/core.c +++ b/src/core.c @@ -358,8 +358,6 @@ void GameInit(void) MultiSioInit(0); } -#include - void GameLoop(void) { while (TRUE) { @@ -401,9 +399,8 @@ void GameLoop(void) } // Wait for vblank to finish - while (REG_DISPSTAT & DISPSTAT_VBLANK) { - // SleepThread(); - } + while (REG_DISPSTAT & DISPSTAT_VBLANK) + ; }; } diff --git a/src/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index 50420593a..af57ae836 100644 --- a/src/platform/pret_sdl/sdl2.c +++ b/src/platform/pret_sdl/sdl2.c @@ -9,6 +9,8 @@ #include #endif +#define SDL_MAIN_HANDLED + #include #include "global.h" @@ -139,6 +141,10 @@ void Platform_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); } int main(int argc, char **argv) { +#ifdef PS2 + SDL_SetMainReady(); +#endif + // Open an output console on Windows #ifdef _WIN32 AllocConsole(); @@ -146,9 +152,15 @@ int main(int argc, char **argv) freopen("CON", "w", stdout); #endif +#ifndef PS2 ReadSaveFile("sa2.sav"); +#endif +#if !ENABLE_AUDIO + if (SDL_Init(SDL_INIT_VIDEO) < 0) { +#else if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) { +#endif fprintf(stderr, "SDL could not initialize! SDL_Error: %s\n", SDL_GetError()); return 1; } @@ -159,8 +171,12 @@ int main(int argc, char **argv) const char *title = "SAT-R sa2"; #endif +#ifdef PS2 + sdlWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN); +#else sdlWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, DISPLAY_WIDTH * videoScale, DISPLAY_HEIGHT * videoScale, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); +#endif if (sdlWindow == NULL) { fprintf(stderr, "Window could not be created! SDL_Error: %s\n", SDL_GetError()); return 1; @@ -182,7 +198,7 @@ int main(int argc, char **argv) } #endif - sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_PRESENTVSYNC); + sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, 0); if (sdlRenderer == NULL) { fprintf(stderr, "Renderer could not be created! SDL_Error: %s\n", SDL_GetError()); return 1; @@ -220,6 +236,10 @@ int main(int argc, char **argv) } #endif +#ifdef PS2 + SDL_SetTextureColorMod(sdlTexture, 140, 140, 140); +#endif + #if ENABLE_AUDIO SDL_AudioSpec want; @@ -314,10 +334,13 @@ void VBlankIntrWait(void) SDL_RenderClear(vramRenderer); SDL_RenderCopy(vramRenderer, vramTexture, NULL, NULL); #endif + +#ifndef PS2 if (videoScaleChanged) { SDL_SetWindowSize(sdlWindow, DISPLAY_WIDTH * videoScale, DISPLAY_HEIGHT * videoScale); videoScaleChanged = false; } +#endif SDL_RenderPresent(sdlRenderer); #if ENABLE_VRAM_VIEW SDL_RenderPresent(vramRenderer); @@ -401,6 +424,7 @@ static SDL_DisplayMode sdlDispMode = { 0 }; void Platform_QueueAudio(const void *data, uint32_t bytesCount) { +#if ENABLE_AUDIO // Reset the audio buffer if we are 10 frames out of sync // If this happens it suggests there was some OS level lag // in playing audio. The queue length should remain stable at < 10 otherwise @@ -410,6 +434,7 @@ void Platform_QueueAudio(const void *data, uint32_t bytesCount) SDL_QueueAudio(1, data, bytesCount); // printf("Queueing %d\n, QueueSize %d\n", bytesCount, SDL_GetQueuedAudioSize(1)); +#endif } void ProcessSDLEvents(void) @@ -2011,21 +2036,6 @@ void VDraw(SDL_Texture *texture) REG_VCOUNT = 161; // prep for being in VBlank period } -<<<<<<< HEAD -======= -int DoMain(void *data) -{ - AgbMain(); - return 0; -} - -void VBlankIntrWait(void) -{ - SDL_AtomicSet(&isFrameAvailable, 1); - SDL_SemWait(vBlankSemaphore); -} - ->>>>>>> b1b34f15 (more progress) u8 BinToBcd(u8 bin) { int placeCounter = 1; diff --git a/src/platform/ps2/ps2.c b/src/platform/ps2/ps2.c index 293fec5b0..bfa1b6d5e 100644 --- a/src/platform/ps2/ps2.c +++ b/src/platform/ps2/ps2.c @@ -371,6 +371,7 @@ int main(int argc, char **argv) fprintf(stderr, "Texture could not be created! SDL_Error: %s\n", SDL_GetError()); return 1; } + SDL_SetTextureScaleMode(sdlTexture, SDL_ScaleModeLinear); SDL_SetTextureColorMod(sdlTexture, 140, 140, 140); @@ -557,7 +558,7 @@ int DoControl(void *data) // SDL_SetWindowSize(sdlWindow, DISPLAY_WIDTH * videoScale, DISPLAY_HEIGHT * videoScale); // videoScaleChanged = false; // } - SDL_RenderPresent(sdlRenderer); + // SDL_RenderPresent(sdlRenderer); #if ENABLE_VRAM_VIEW SDL_RenderPresent(vramRenderer); #endif @@ -2290,7 +2291,7 @@ void VBlankIntrWait(void) SDL_RenderClear(sdlRenderer); SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); - SDL_RenderPresent(sdlRenderer); + // SDL_RenderPresent(sdlRenderer); } u8 BinToBcd(u8 bin) diff --git a/src/platform/shared/audio/cgb_audio.c b/src/platform/shared/audio/cgb_audio.c index f4920d1bb..3f6ec93d5 100644 --- a/src/platform/shared/audio/cgb_audio.c +++ b/src/platform/shared/audio/cgb_audio.c @@ -103,7 +103,9 @@ void cgb_trigger_note(u8 channel) void cgb_audio_generate(u16 samplesPerFrame) { +#if !ENABLE_AUDIO return; +#endif float *outBuffer = gb.outBuffer; switch (REG_NR11 & 0xC0) { case 0x00: From 0a5b7a8f53bd29b1d73f53584f30be09d360d413 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Sat, 7 Dec 2024 17:33:13 +0000 Subject: [PATCH 09/11] no idea whats going on --- include/config.h | 2 +- include/gba/io_reg.h | 23 +- src/core.c | 3 + src/platform/ps2/ps2.c | 289 +++++++++++++++++--------- src/platform/shared/audio/cgb_audio.c | 1 + 5 files changed, 209 insertions(+), 109 deletions(-) diff --git a/include/config.h b/include/config.h index bbd642a2f..3339c8987 100644 --- a/include/config.h +++ b/include/config.h @@ -17,7 +17,7 @@ #define USE_NEW_DMA 1 #endif -#define TAS_TESTING 1 +#define TAS_TESTING 0 #define TAS_TESTING_WIDESCREEN_HACK 1 #if PLATFORM_GBA diff --git a/include/gba/io_reg.h b/include/gba/io_reg.h index 3348fb083..befa1dec9 100644 --- a/include/gba/io_reg.h +++ b/include/gba/io_reg.h @@ -3,9 +3,10 @@ #include -#define IO_SIZE 0x400 -#if !PORTABLE -#define REG_BASE 0x4000000 // I/O register base address +#define IO_SIZE 0x800 +#if PLATFORM_GBA +// I/O register base address +#define REG_BASE 0x4000000 #else // TODO: Needs to be u8 because of the address macros extern unsigned char REG_BASE[IO_SIZE]; @@ -160,7 +161,9 @@ extern unsigned char REG_BASE[IO_SIZE]; #define REG_OFFSET_DMA3CNT_H (REG_OFFSET_DMA3CNT_L + sizeof(uint16_t)) #endif -#define REG_OFFSET_TMCNT 0x100 +#define REG_OFFSET_DMA_END REG_OFFSET_DMA3CNT_H + sizeof(uint16_t) + +#define REG_OFFSET_TMCNT REG_OFFSET_DMA_END + 0x10 #define REG_OFFSET_TMCNT_L 0x100 #define REG_OFFSET_TMCNT_H 0x102 #define REG_OFFSET_TM0CNT 0x100 @@ -186,8 +189,8 @@ extern unsigned char REG_BASE[IO_SIZE]; #define REG_OFFSET_SIOMULTI2 0x124 #define REG_OFFSET_SIOMULTI3 0x126 -#define REG_OFFSET_KEYINPUT 0x130 -#define REG_OFFSET_KEYCNT 0x132 +#define REG_OFFSET_KEYINPUT REG_OFFSET_TMCNT + 0x30 +#define REG_OFFSET_KEYCNT REG_OFFSET_TMCNT + 0x32 #define REG_OFFSET_RCNT 0x134 @@ -200,11 +203,11 @@ extern unsigned char REG_BASE[IO_SIZE]; #define REG_OFFSET_JOY_TRANS_L 0x154 #define REG_OFFSET_JOY_TRANS_H 0x156 -#define REG_OFFSET_IME 0x208 -#define REG_OFFSET_IE 0x200 -#define REG_OFFSET_IF 0x202 +#define REG_OFFSET_IME REG_OFFSET_TMCNT + 0x108 +#define REG_OFFSET_IE REG_OFFSET_TMCNT + 0x100 +#define REG_OFFSET_IF REG_OFFSET_TMCNT + 0x102 -#define REG_OFFSET_WAITCNT 0x204 +#define REG_OFFSET_WAITCNT REG_OFFSET_TMCNT + 0x104 // I/O register addresses diff --git a/src/core.c b/src/core.c index dfe1ce94f..988ce6ede 100644 --- a/src/core.c +++ b/src/core.c @@ -596,6 +596,8 @@ static void UpdateScreenCpuSet(void) } } +void somefunc(void) { } + static void VBlankIntr(void) { u16 keys; @@ -633,6 +635,7 @@ static void VBlankIntr(void) if (!(gFlagsPreVBlank & FLAGS_8000)) { keys = ~REG_KEYINPUT & (START_BUTTON | SELECT_BUTTON | B_BUTTON | A_BUTTON); if (keys == (START_BUTTON | SELECT_BUTTON | B_BUTTON | A_BUTTON)) { + somefunc(); gFlags |= FLAGS_8000; REG_IE = 0; REG_IME = 0; diff --git a/src/platform/ps2/ps2.c b/src/platform/ps2/ps2.c index bfa1b6d5e..9fed5b885 100644 --- a/src/platform/ps2/ps2.c +++ b/src/platform/ps2/ps2.c @@ -118,6 +118,7 @@ double lastGameTime = 0; double curGameTime = 0; double fixedTimestep = 1.0 / 60.0; // 16.666667ms double timeScale = 1.0; +double accumulator = 0.0; // struct SiiRtcInfo internalClock; static FILE *sSaveFile = NULL; @@ -145,27 +146,9 @@ void *Platform_malloc(int numBytes) { return HeapAlloc(GetProcessHeap(), HEAP_GE void Platform_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); } #endif -#include - static volatile int counter = 0; static volatile int continueloop; -#define THREAD_STACK_SIZE (512 * 1024) - -static u8 thread_stack[THREAD_STACK_SIZE] ALIGNED(16); -static ee_thread_t thread_thread; -static int thread_threadid; - -static u8 thread_stack2[THREAD_STACK_SIZE] ALIGNED(16); -static ee_thread_t thread_thread2; -static int thread_threadid2; - -static u8 disp_stack[THREAD_STACK_SIZE] ALIGNED(16); -static int disp_threadid; - -void TheThread(void *arg); -void TheThread2(void *arg); - // void dispatcher(void *apParam) // { @@ -266,30 +249,12 @@ void TheThread2(void *arg); // } // } -void dispatcher(void *apParam) -{ - - while (1) { - - SleepThread(); - - } /* end while */ - -} /* end dispatcher */ - -void RotateThreads(s32 id, u16 time, void *arg) -{ - iWakeupThread(disp_threadid); - iRotateThreadReadyQueue(30); - iSetAlarm(1, RotateThreads, NULL); -} - int main(int argc, char **argv) { - // REG_RCNT = 0x8000; - // cgb_audio_init(48000); - // AgbMain(); - // return 0; +#ifdef PS2 + SDL_SetMainReady(); +#endif + // Open an output console on Windows #ifdef _WIN32 AllocConsole(); @@ -297,16 +262,18 @@ int main(int argc, char **argv) freopen("CON", "w", stdout); #endif - // ReadSaveFile("sa2.sav"); +#ifndef PS2 + ReadSaveFile("sa2.sav"); +#endif - printf("Starting\n"); - SDL_SetMainReady(); - printf("Ready \n"); +#if !ENABLE_AUDIO if (SDL_Init(SDL_INIT_VIDEO) < 0) { +#else + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) { +#endif fprintf(stderr, "SDL could not initialize! SDL_Error: %s\n", SDL_GetError()); return 1; } - printf("INITIALISED\n"); #ifdef TITLE_BAR const char *title = STR(TITLE_BAR); @@ -314,16 +281,17 @@ int main(int argc, char **argv) const char *title = "SAT-R sa2"; #endif - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); - +#ifdef PS2 sdlWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN); +#else + sdlWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, DISPLAY_WIDTH * videoScale, + DISPLAY_HEIGHT * videoScale, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); +#endif if (sdlWindow == NULL) { fprintf(stderr, "Window could not be created! SDL_Error: %s\n", SDL_GetError()); return 1; } - printf("WINDOW CREATED\n"); - #if ENABLE_VRAM_VIEW int mainWindowX; int mainWindowWidth; @@ -345,7 +313,6 @@ int main(int argc, char **argv) fprintf(stderr, "Renderer could not be created! SDL_Error: %s\n", SDL_GetError()); return 1; } - printf("RENDERER CREATED\n"); #if ENABLE_VRAM_VIEW vramRenderer = SDL_CreateRenderer(vramWindow, -1, SDL_RENDERER_PRESENTVSYNC); @@ -357,9 +324,8 @@ int main(int argc, char **argv) SDL_SetRenderDrawColor(sdlRenderer, 255, 255, 255, 255); SDL_RenderClear(sdlRenderer); - // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); SDL_RenderSetLogicalSize(sdlRenderer, DISPLAY_WIDTH, DISPLAY_HEIGHT); - #if ENABLE_VRAM_VIEW SDL_SetRenderDrawColor(vramRenderer, 0, 0, 0, 255); SDL_RenderClear(vramRenderer); @@ -371,9 +337,6 @@ int main(int argc, char **argv) fprintf(stderr, "Texture could not be created! SDL_Error: %s\n", SDL_GetError()); return 1; } - SDL_SetTextureScaleMode(sdlTexture, SDL_ScaleModeLinear); - - SDL_SetTextureColorMod(sdlTexture, 140, 140, 140); #if ENABLE_VRAM_VIEW vramTexture = SDL_CreateTexture(vramRenderer, SDL_PIXELFORMAT_ABGR1555, SDL_TEXTUREACCESS_STREAMING, vramWindowWidth, vramWindowHeight); @@ -383,14 +346,10 @@ int main(int argc, char **argv) } #endif - simTime = curGameTime = lastGameTime = SDL_GetPerformanceCounter(); - - isFrameAvailable.value = 0; - isVblankReady.value = 0; - vBlankSemaphore = SDL_CreateSemaphore(0); - if (vBlankSemaphore == NULL) { - SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to create Semaphore:\n %s", SDL_GetError()); - } +#ifdef PS2 + SDL_SetTextureScaleMode(sdlTexture, SDL_ScaleModeLinear); + SDL_SetTextureColorMod(sdlTexture, 140, 140, 140); +#endif #if ENABLE_AUDIO SDL_AudioSpec want; @@ -400,15 +359,15 @@ int main(int argc, char **argv) want.format = AUDIO_F32; want.channels = 2; want.samples = (want.freq / 60); - cgb_audio_init(48000); - - // if (SDL_OpenAudio(&want, 0) < 0) - // SDL_Log("Failed to open audio: %s", SDL_GetError()); - // else { - // if (want.format != AUDIO_F32) /* we let this one thing change. */ - // SDL_Log("We didn't get Float32 audio format."); - // SDL_PauseAudio(0); - // } + cgb_audio_init(want.freq); + + if (SDL_OpenAudio(&want, 0) < 0) + SDL_Log("Failed to open audio: %s", SDL_GetError()); + else { + if (want.format != AUDIO_F32) /* we let this one thing change. */ + SDL_Log("We didn't get Float32 audio format."); + SDL_PauseAudio(0); + } #endif VDraw(sdlTexture); @@ -451,7 +410,11 @@ int main(int argc, char **argv) // StartThread(agbThreadId, NULL); // ChangeThreadPriority(GetThreadId(), 30); - // REG_KEYINPUT = 0x3FF; + // Who knows why, but something to do with the way we set + // REG_KEYINPUT whilst in tas testing mode causes a soft lock + // if we don't set this when not doing tas testing then the game + // softlocks on the intro + REG_KEYINPUT = KEYS_MASK; DoMain(NULL); @@ -495,8 +458,8 @@ int DoControl(void *data) REG_KEYINPUT = 0x3FF; while (isRunning) { - // printf("PROCESS EVENT\n"); ProcessSDLEvents(); + REG_KEYINPUT = KEYS_MASK ^ Platform_GetKeyInput(); if (!paused || stepOneFrame) { double dt = fixedTimestep / timeScale; // TODO: Fix speedup @@ -516,7 +479,7 @@ int DoControl(void *data) while (accumulator >= dt) { // printf("WAITING %d %d\n", accumulator, dt); - REG_KEYINPUT = KEYS_MASK ^ Platform_GetKeyInput(); + if (SDL_AtomicGet(&isFrameAvailable)) { // printf("Frame is ready\n"); VDraw(sdlTexture); @@ -2261,39 +2224,169 @@ int DoMain(void *data) return 0; } -#include void VBlankIntrWait(void) { - // // printf("INTRWAIT\n"); - // SDL_AtomicSet(&isFrameAvailable, 1); - // // printf("WAITING FOR SEM\n"); - // // while (!SDL_AtomicGet(&isVblankReady)) { - // // printf("WAITING FOR SEM\n"); - // // // SleepThread(); - // // } - // // printf("SEM DONE\n"); - // // SDL_AtomicSet(&isVblankReady, 0); - // SDL_SemWait(vBlankSemaphore); + bool frameAvailable = TRUE; - VDraw(sdlTexture); + while (isRunning) { + ProcessSDLEvents(); - // SDL_AtomicSet(&isFrameAvailable, 0); + if (!paused || stepOneFrame) { + double dt = fixedTimestep / timeScale; // TODO: Fix speedup + double deltaTime = 0; - REG_DISPSTAT |= INTR_FLAG_VBLANK; + curGameTime = SDL_GetPerformanceCounter(); - // TODO(Jace): I think this should be DMA_VBLANK. - // If not, and it is HBLANK instead, add a note here, why it is! - RunDMAs(DMA_VBLANK); +#ifdef PS2 + deltaTime = dt; +#else + if (stepOneFrame) { + deltaTime = dt; + } else { + deltaTime = (double)((curGameTime - lastGameTime) / (double)SDL_GetPerformanceFrequency()); + if (deltaTime > (dt * 5)) + deltaTime = dt * 5; + } +#endif - if (REG_DISPSTAT & DISPSTAT_VBLANK_INTR) - gIntrTable[INTR_INDEX_VBLANK](); - REG_DISPSTAT &= ~INTR_FLAG_VBLANK; + lastGameTime = curGameTime; - SDL_RenderClear(sdlRenderer); - SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); - // SDL_RenderPresent(sdlRenderer); + accumulator += deltaTime; + + while (accumulator >= dt) { + if (frameAvailable) { + VDraw(sdlTexture); + frameAvailable = FALSE; + + REG_DISPSTAT |= INTR_FLAG_VBLANK; + + // TODO(Jace): I think this should be DMA_VBLANK. + // If not, and it is HBLANK instead, add a note here, why it is! + RunDMAs(DMA_VBLANK); + + if (REG_DISPSTAT & DISPSTAT_VBLANK_INTR) + gIntrTable[INTR_INDEX_VBLANK](); + REG_DISPSTAT &= ~INTR_FLAG_VBLANK; + accumulator -= dt; + } else { + REG_KEYINPUT = KEYS_MASK ^ Platform_GetKeyInput(); + accumulator -= dt; + // Get another frame; + return; + } + } + + if (paused && stepOneFrame) { + stepOneFrame = false; + } + } + + SDL_RenderClear(sdlRenderer); + SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); + +#if ENABLE_VRAM_VIEW + VramDraw(vramTexture); + SDL_RenderClear(vramRenderer); + SDL_RenderCopy(vramRenderer, vramTexture, NULL, NULL); +#endif + +#ifndef PS2 + if (videoScaleChanged) { + SDL_SetWindowSize(sdlWindow, DISPLAY_WIDTH * videoScale, DISPLAY_HEIGHT * videoScale); + videoScaleChanged = false; + } +#endif + SDL_RenderPresent(sdlRenderer); +#if ENABLE_VRAM_VIEW + SDL_RenderPresent(vramRenderer); +#endif + } + + CloseSaveFile(); + + SDL_DestroyWindow(sdlWindow); + SDL_Quit(); + exit(0); } +// while (isRunning) { +// ProcessSDLEvents(); +// REG_KEYINPUT = KEYS_MASK ^ Platform_GetKeyInput(); + +// if (!paused || stepOneFrame) { +// double dt = fixedTimestep / timeScale; // TODO: Fix speedup +// double deltaTime = 0; + +// curGameTime = SDL_GetPerformanceCounter(); +// #ifdef PS2 +// deltaTime = dt; +// #else +// if (stepOneFrame) { +// deltaTime = dt; +// } else { +// deltaTime = (double)((curGameTime - lastGameTime) / (double)SDL_GetPerformanceFrequency()); +// if (deltaTime > (dt * 5)) +// deltaTime = dt * 5; +// } +// #endif +// lastGameTime = curGameTime; +// accumulator += deltaTime; + +// while (accumulator >= dt) { +// if (frameAvailable) { +// VDraw(sdlTexture); +// frameAvailable = FALSE; + +// REG_DISPSTAT |= INTR_FLAG_VBLANK; + +// // TODO(Jace): I think this should be DMA_VBLANK. +// // If not, and it is HBLANK instead, add a note here, why it is! +// RunDMAs(DMA_VBLANK); + +// if (REG_DISPSTAT & DISPSTAT_VBLANK_INTR) +// gIntrTable[INTR_INDEX_VBLANK](); +// REG_DISPSTAT &= ~INTR_FLAG_VBLANK; + +// accumulator -= dt; +// } else { +// accumulator -= dt; +// // Get another frame +// return; +// } +// } + +// if (paused && stepOneFrame) { +// stepOneFrame = false; +// } +// } + +// SDL_RenderClear(sdlRenderer); +// SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); + +// #if ENABLE_VRAM_VIEW +// VramDraw(vramTexture); +// SDL_RenderClear(vramRenderer); +// SDL_RenderCopy(vramRenderer, vramTexture, NULL, NULL); +// #endif + +// #ifndef PS2 +// if (videoScaleChanged) { +// SDL_SetWindowSize(sdlWindow, DISPLAY_WIDTH * videoScale, DISPLAY_HEIGHT * videoScale); +// videoScaleChanged = false; +// } +// #endif +// SDL_RenderPresent(sdlRenderer); +// #if ENABLE_VRAM_VIEW +// SDL_RenderPresent(vramRenderer); +// #endif +// } + +// CloseSaveFile(); + +// SDL_DestroyWindow(sdlWindow); +// SDL_Quit(); +// exit(0); + u8 BinToBcd(u8 bin) { int placeCounter = 1; diff --git a/src/platform/shared/audio/cgb_audio.c b/src/platform/shared/audio/cgb_audio.c index 3f6ec93d5..662f13076 100644 --- a/src/platform/shared/audio/cgb_audio.c +++ b/src/platform/shared/audio/cgb_audio.c @@ -103,6 +103,7 @@ void cgb_trigger_note(u8 channel) void cgb_audio_generate(u16 samplesPerFrame) { + return; #if !ENABLE_AUDIO return; #endif From fccd90f0f6e8d9d534839a56479a0291bdfc9c50 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Sun, 8 Dec 2024 04:08:59 +0000 Subject: [PATCH 10/11] fix port, make audio work etc --- Makefile | 13 +- asm/macros/portable.inc | 2 +- include/config.h | 4 +- src/platform/pret_sdl/sdl2.c | 38 +- src/platform/ps2/.gitignore | 0 src/platform/ps2/lib/.gitkeep | 0 src/platform/ps2/ps2.c | 2487 ------------------------- src/platform/shared/audio/cgb_audio.c | 1 - 8 files changed, 33 insertions(+), 2512 deletions(-) delete mode 100644 src/platform/ps2/.gitignore delete mode 100644 src/platform/ps2/lib/.gitkeep delete mode 100644 src/platform/ps2/ps2.c diff --git a/Makefile b/Makefile index b97f61742..d4954279f 100644 --- a/Makefile +++ b/Makefile @@ -116,8 +116,9 @@ else CPPFLAGS += -D TITLE_BAR=$(BUILD_NAME).$(PLATFORM) -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 $(shell sdl2-config --cflags) else ifeq ($(PLATFORM),sdl_ps2) CC1FLAGS += -Wno-parentheses-equality -Wno-unused-value - CPPFLAGS += -I$(PS2SDK)/common/include -I$(PS2SDK)/ee/include -I$(PS2SDK)/ports/include $(shell $(SDL2_PS2_PKG)/bin/sdl2-config --cflags) - CPPFLAGS += -D TITLE_BAR=$(BUILD_NAME).$(PLATFORM) -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 -D_EE -DPS2 -D__PS2__ + CC1FLAGS += -ffast-math + CPPFLAGS += -I$(PS2SDK)/common/include -I$(PS2SDK)/ee/include -I$(PS2SDK)/ports/include $(shell $(PS2SDK)/ports/bin/sdl2-config --cflags) + CPPFLAGS += -D TITLE_BAR=$(BUILD_NAME).$(PLATFORM) -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 -D_EE -DPS2 -D__PS2__ -Dmain=SDL_main else ifeq ($(PLATFORM),sdl_win32) CPPFLAGS += -D TITLE_BAR=$(BUILD_NAME).$(PLATFORM) -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 $(SDL_MINGW_FLAGS) else ifeq ($(PLATFORM),win32) @@ -155,7 +156,11 @@ ifeq ($(DEBUG),1) CC1FLAGS += -g3 -O0 CPPFLAGS += -D DEBUG=1 else +ifeq ($(PLATFORM), gba) CC1FLAGS += -O2 +else + CC1FLAGS += -O3 +endif endif ifeq ($(PORTABLE),1) @@ -273,7 +278,7 @@ C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/*") else ifeq ($(PLATFORM),sdl) C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/ps2/*") else ifeq ($(PLATFORM),sdl_ps2) -C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/pret_sdl/*") +C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/ps2/*") else ifeq ($(PLATFORM),sdl_win32) C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/ps2/*") else ifeq ($(PLATFORM),win32) @@ -447,7 +452,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 ifeq ($(PLATFORM),sdl_ps2) - @cd $(OBJ_DIR) && $(CC1) $(OBJS_REL) $(shell $(SDL2_PS2_PKG)/bin/sdl2-config --cflags --libs) $(LINKER_MAP_FLAGS) -T$(PS2SDK)/ee/startup/linkfile -L$(PS2SDK)/common/lib -L$(PS2SDK)/ee/lib -L$(PS2DEV)/gsKit/lib -L$(PS2SDK)/ports/lib -Wl,-zmax-page-size=128 -o $(ROOT_DIR)/$@ + @cd $(OBJ_DIR) && $(CC1) $(OBJS_REL) -lSDL2main -lSDL2 $(shell $(PS2SDK)/ports/bin/sdl2-config --libs) $(LINKER_MAP_FLAGS) -T$(PS2SDK)/ee/startup/linkfile -L$(PS2SDK)/common/lib -L$(PS2SDK)/ee/lib -L$(PS2DEV)/gsKit/lib -Wl,-zmax-page-size=128 -o $(ROOT_DIR)/$@ else @cd $(OBJ_DIR) && $(CC1) -mwin32 $(OBJS_REL) -L$(ROOT_DIR)/libagbsyscall -lagbsyscall -lkernel32 -o $(ROOT_DIR)/$@ -Xlinker -Map "$(ROOT_DIR)/$(MAP)" endif diff --git a/asm/macros/portable.inc b/asm/macros/portable.inc index b389fb26a..3eadcd08d 100644 --- a/asm/macros/portable.inc +++ b/asm/macros/portable.inc @@ -11,7 +11,7 @@ #if defined(__aarch64__) || defined(__x86_64__) .quad \value #else - .int \value + .4byte \value #endif .endm diff --git a/include/config.h b/include/config.h index 3339c8987..88d1d21a5 100644 --- a/include/config.h +++ b/include/config.h @@ -17,14 +17,14 @@ #define USE_NEW_DMA 1 #endif -#define TAS_TESTING 0 +#define TAS_TESTING 1 #define TAS_TESTING_WIDESCREEN_HACK 1 #if PLATFORM_GBA #define ENABLE_AUDIO TRUE #else #ifdef PS2 -#define ENABLE_AUDIO FALSE +#define ENABLE_AUDIO TRUE #define ENABLE_VRAM_VIEW FALSE #else #define ENABLE_AUDIO TRUE diff --git a/src/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index af57ae836..0a07fb7a0 100644 --- a/src/platform/pret_sdl/sdl2.c +++ b/src/platform/pret_sdl/sdl2.c @@ -9,9 +9,8 @@ #include #endif -#define SDL_MAIN_HANDLED - #include +#include #include "global.h" #include "core.h" @@ -141,10 +140,6 @@ void Platform_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); } int main(int argc, char **argv) { -#ifdef PS2 - SDL_SetMainReady(); -#endif - // Open an output console on Windows #ifdef _WIN32 AllocConsole(); @@ -156,11 +151,7 @@ int main(int argc, char **argv) ReadSaveFile("sa2.sav"); #endif -#if !ENABLE_AUDIO - if (SDL_Init(SDL_INIT_VIDEO) < 0) { -#else - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) { -#endif + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) { fprintf(stderr, "SDL could not initialize! SDL_Error: %s\n", SDL_GetError()); return 1; } @@ -181,6 +172,7 @@ int main(int argc, char **argv) fprintf(stderr, "Window could not be created! SDL_Error: %s\n", SDL_GetError()); return 1; } + printf("CREATED!\n"); #if ENABLE_VRAM_VIEW int mainWindowX; @@ -198,7 +190,7 @@ int main(int argc, char **argv) } #endif - sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, 0); + sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); if (sdlRenderer == NULL) { fprintf(stderr, "Renderer could not be created! SDL_Error: %s\n", SDL_GetError()); return 1; @@ -237,6 +229,7 @@ int main(int argc, char **argv) #endif #ifdef PS2 + SDL_SetTextureScaleMode(sdlTexture, SDL_ScaleModeLinear); SDL_SetTextureColorMod(sdlTexture, 140, 140, 140); #endif @@ -250,6 +243,7 @@ int main(int argc, char **argv) want.samples = (want.freq / 60); cgb_audio_init(want.freq); + SDL_InitSubSystem(SDL_INIT_AUDIO); if (SDL_OpenAudio(&want, 0) < 0) SDL_Log("Failed to open audio: %s", SDL_GetError()); else { @@ -287,6 +281,12 @@ void VBlankIntrWait(void) double deltaTime = 0; curGameTime = SDL_GetPerformanceCounter(); + +// For now the PS2 renders too slowly so we just +// have to render as far as we can +#ifdef PS2 + deltaTime = dt; +#else if (stepOneFrame) { deltaTime = dt; } else { @@ -294,6 +294,8 @@ void VBlankIntrWait(void) if (deltaTime > (dt * 5)) deltaTime = dt * 5; } +#endif + lastGameTime = curGameTime; accumulator += deltaTime; @@ -301,6 +303,7 @@ void VBlankIntrWait(void) while (accumulator >= dt) { REG_KEYINPUT = KEYS_MASK ^ Platform_GetKeyInput(); if (frameAvailable) { + // The draw function is super slow on constrained hardware VDraw(sdlTexture); frameAvailable = FALSE; @@ -313,10 +316,13 @@ void VBlankIntrWait(void) if (REG_DISPSTAT & DISPSTAT_VBLANK_INTR) gIntrTable[INTR_INDEX_VBLANK](); REG_DISPSTAT &= ~INTR_FLAG_VBLANK; - accumulator -= dt; } else { - // Get another frame + // remove this once the PS2 renders fast enough +#ifdef PS2 + accumulator -= dt; +#endif + // Get another frame; return; } } @@ -335,12 +341,11 @@ void VBlankIntrWait(void) SDL_RenderCopy(vramRenderer, vramTexture, NULL, NULL); #endif -#ifndef PS2 if (videoScaleChanged) { SDL_SetWindowSize(sdlWindow, DISPLAY_WIDTH * videoScale, DISPLAY_HEIGHT * videoScale); videoScaleChanged = false; } -#endif + SDL_RenderPresent(sdlRenderer); #if ENABLE_VRAM_VIEW SDL_RenderPresent(vramRenderer); @@ -353,7 +358,6 @@ void VBlankIntrWait(void) SDL_Quit(); exit(0); } - static void ReadSaveFile(char *path) { // Check whether the saveFile exists, and create it if not diff --git a/src/platform/ps2/.gitignore b/src/platform/ps2/.gitignore deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/platform/ps2/lib/.gitkeep b/src/platform/ps2/lib/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/platform/ps2/ps2.c b/src/platform/ps2/ps2.c deleted file mode 100644 index 9fed5b885..000000000 --- a/src/platform/ps2/ps2.c +++ /dev/null @@ -1,2487 +0,0 @@ -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#include -#include -#endif - -#define SDL_MAIN_HANDLED - -#include - -#include "global.h" -#include "core.h" -#include "gba/defines.h" -#include "gba/io_reg.h" -#include "gba/types.h" -#include "lib/agb_flash/flash_internal.h" -#define DMA_DEST_MASK 0x0060 -#define DMA_SRC_MASK 0x0180 - -#if ENABLE_AUDIO -#include "platform/shared/audio/cgb_audio.h" -#endif - -#ifndef TILE_WIDTH -#define TILE_WIDTH 8 -#endif - -extern IntrFunc gIntrTable[16]; - -#if 0 -extern u16 INTR_CHECK; -extern void *INTR_VECTOR; -extern unsigned char REG_BASE[0x400]; -extern unsigned char PLTT[PLTT_SIZE]; -extern unsigned char VRAM_[VRAM_SIZE]; -extern unsigned char OAM[OAM_SIZE]; -extern unsigned char FLASH_BASE[131072]; -#endif -extern uint8_t EWRAM_START[EWRAM_SIZE]; -extern uint8_t IWRAM_START[IWRAM_SIZE]; -// TODO: REG_BASE needs to be u8, because of the address macro definitions -extern uint8_t REG_BASE[IO_SIZE]; -extern uint16_t PLTT[PLTT_SIZE / sizeof(uint16_t)]; -extern uint8_t VRAM[VRAM_SIZE]; -extern uint8_t OAM[OAM_SIZE]; -extern uint8_t FLASH_BASE[FLASH_ROM_SIZE_1M * SECTORS_PER_BANK]; -ALIGNED(256) uint16_t gameImage[DISPLAY_WIDTH * DISPLAY_HEIGHT]; -#if ENABLE_VRAM_VIEW -#define VRAM_VIEW_WIDTH (32 * TILE_WIDTH) -#define VRAM_VIEW_HEIGHT (((VRAM_SIZE / TILE_SIZE_4BPP) / 32) * TILE_WIDTH) -uint16_t vramBuffer[VRAM_VIEW_WIDTH * VRAM_VIEW_HEIGHT]; -uint8_t vramPalIdBuffer[(VRAM_VIEW_WIDTH / TILE_WIDTH) * (VRAM_VIEW_HEIGHT / TILE_WIDTH)]; -#endif - -#define DMA_COUNT 4 - -struct DMATransfer { - union { - const void *src; - const u16 *src16; - const u32 *src32; - }; - union { - void *dst; - vu16 *dst16; - vu32 *dst32; - }; - u32 size; - u16 control; -} DMAList[DMA_COUNT]; - -enum { DMA_NOW, DMA_VBLANK, DMA_HBLANK, DMA_SPECIAL }; - -struct scanlineData { - uint16_t layers[4][DISPLAY_WIDTH]; - uint16_t spriteLayers[4][DISPLAY_WIDTH]; - uint16_t bgcnts[4]; - uint16_t winMask[DISPLAY_WIDTH]; - // priority bookkeeping - char bgtoprio[4]; // background to priority - char prioritySortedBgs[4][4]; - char prioritySortedBgsCount[4]; -}; - -struct bgPriority { - char priority; - char subPriority; -}; - -SDL_Thread *mainLoopThread; -SDL_Thread *controlThread; -SDL_Window *sdlWindow; -SDL_Renderer *sdlRenderer; -SDL_Texture *sdlTexture; -#if ENABLE_VRAM_VIEW -SDL_Window *vramWindow; -SDL_Renderer *vramRenderer; -SDL_Texture *vramTexture; -#endif -#define INITIAL_VIDEO_SCALE 1 -unsigned int videoScale = INITIAL_VIDEO_SCALE; -unsigned int preFullscreenVideoScale = INITIAL_VIDEO_SCALE; -SDL_sem *vBlankSemaphore; -SDL_atomic_t isVblankReady; -SDL_atomic_t isFrameAvailable; -bool speedUp = false; -bool videoScaleChanged = false; -bool isRunning = true; -bool paused = false; -bool stepOneFrame = false; -double simTime = 0; -double lastGameTime = 0; -double curGameTime = 0; -double fixedTimestep = 1.0 / 60.0; // 16.666667ms -double timeScale = 1.0; -double accumulator = 0.0; -// struct SiiRtcInfo internalClock; - -static FILE *sSaveFile = NULL; - -extern void AgbMain(void); -void DoSoftReset(void) {}; - -int DoMain(void *param); -int DoControl(void *data); -void ProcessSDLEvents(void); -void VDraw(SDL_Texture *texture); -void VramDraw(SDL_Texture *texture); - -static void ReadSaveFile(char *path); -static void StoreSaveFile(void); -static void CloseSaveFile(void); - -static void UpdateInternalClock(void); -static void RunDMAs(u32 type); - -u16 Platform_GetKeyInput(void); - -#ifdef _WIN32 -void *Platform_malloc(int numBytes) { return HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY, numBytes); } -void Platform_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); } -#endif - -static volatile int counter = 0; -static volatile int continueloop; - -// void dispatcher(void *apParam) -// { - -// while (1) { -// printf("Dispatch\n"); - -// SleepThread(); - -// } /* end while */ - -// } /* end dispatcher */ - -// void alarmfunction(s32 id, u16 time, void *arg) -// { -// counter++; -// iWakeupThread(disp_threadid); -// iRotateThreadReadyQueue(30); -// iSetAlarm(625, alarmfunction, NULL); -// } - -// int main(int argc, char **argv) -// { -// extern void *_gp; - -// // EEUG : pay attention at the priority of your 'main' thread. -// // Make sure that it is higher than threads you create -// //(i.e. priority value is lower than 0x1E). I think ps2link sets it to 64 -// // - set the priority of your main thread to '0x1D': -// // - create/start your "vegetables counters", set alarm handlers etc.; -// // - lower priority of your 'main' thread -// ChangeThreadPriority(GetThreadId(), 29); // 29 is lower than 30 ;) - -// continueloop = 1; - -// SetAlarm(625, alarmfunction, NULL); - -// printf("\ncreating thread\n"); - -// thread_thread.func = dispatcher; -// thread_thread.stack = disp_stack; -// thread_thread.stack_size = THREAD_STACK_SIZE; -// thread_thread.gp_reg = &_gp; -// thread_thread.initial_priority = 0; -// StartThread(disp_threadid = CreateThread(&thread_thread), NULL); - -// thread_thread.func = TheThread; -// thread_thread.stack = thread_stack; -// thread_thread.stack_size = THREAD_STACK_SIZE; -// thread_thread.gp_reg = &_gp; -// thread_thread.initial_priority = 30; -// if ((thread_threadid = CreateThread(&thread_thread)) < 0) { -// printf("CREATE THREAD ERROR!!!\n"); -// return -1; -// } -// StartThread(thread_threadid, NULL); -// printf("thread started\n"); - -// thread_thread2.func = TheThread2; -// thread_thread2.stack = thread_stack2; -// thread_thread2.stack_size = THREAD_STACK_SIZE; -// thread_thread2.gp_reg = &_gp; -// thread_thread2.initial_priority = 31; -// if ((thread_threadid2 = CreateThread(&thread_thread2)) < 0) { -// printf("CREATE THREAD ERROR!!!\n"); -// return -1; -// } -// StartThread(thread_threadid2, NULL); -// printf("thread 2 started\n"); - -// ChangeThreadPriority(GetThreadId(), 30); - -// while (continueloop == 1) { } - -// printf("terminating\n"); -// TerminateThread(thread_threadid); -// DeleteThread(thread_threadid); - -// printf("\ndone\n"); -// return 0; -// } - -// void TheThread(void *arg) -// { -// while (1) { -// printf("Thread loop iter\n"); -// if (counter > 50) -// continueloop = 0; -// SleepThread(); -// } -// } -// void TheThread2(void *arg) -// { -// while (1) { -// printf("Thread 2 loop iter\n"); -// if (counter > 50) -// continueloop = 0; -// SleepThread(); -// } -// } - -int main(int argc, char **argv) -{ -#ifdef PS2 - SDL_SetMainReady(); -#endif - - // Open an output console on Windows -#ifdef _WIN32 - AllocConsole(); - AttachConsole(GetCurrentProcessId()); - freopen("CON", "w", stdout); -#endif - -#ifndef PS2 - ReadSaveFile("sa2.sav"); -#endif - -#if !ENABLE_AUDIO - if (SDL_Init(SDL_INIT_VIDEO) < 0) { -#else - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) { -#endif - fprintf(stderr, "SDL could not initialize! SDL_Error: %s\n", SDL_GetError()); - return 1; - } - -#ifdef TITLE_BAR - const char *title = STR(TITLE_BAR); -#else - const char *title = "SAT-R sa2"; -#endif - -#ifdef PS2 - sdlWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN); -#else - sdlWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, DISPLAY_WIDTH * videoScale, - DISPLAY_HEIGHT * videoScale, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); -#endif - if (sdlWindow == NULL) { - fprintf(stderr, "Window could not be created! SDL_Error: %s\n", SDL_GetError()); - return 1; - } - -#if ENABLE_VRAM_VIEW - int mainWindowX; - int mainWindowWidth; - SDL_GetWindowPosition(sdlWindow, &mainWindowX, NULL); - SDL_GetWindowSize(sdlWindow, &mainWindowWidth, NULL); - int vramWindowX = mainWindowX + mainWindowWidth; - u16 vramWindowWidth = VRAM_VIEW_WIDTH; - u16 vramWindowHeight = VRAM_VIEW_HEIGHT; - vramWindow = SDL_CreateWindow("VRAM View", vramWindowX, SDL_WINDOWPOS_CENTERED, vramWindowWidth, vramWindowHeight, - SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); - if (vramWindow == NULL) { - fprintf(stderr, "VRAM Window could not be created! SDL_Error: %s\n", SDL_GetError()); - return 1; - } -#endif - - sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, 0); - if (sdlRenderer == NULL) { - fprintf(stderr, "Renderer could not be created! SDL_Error: %s\n", SDL_GetError()); - return 1; - } - -#if ENABLE_VRAM_VIEW - vramRenderer = SDL_CreateRenderer(vramWindow, -1, SDL_RENDERER_PRESENTVSYNC); - if (vramRenderer == NULL) { - fprintf(stderr, "VRAM Renderer could not be created! SDL_Error: %s\n", SDL_GetError()); - return 1; - } -#endif - - SDL_SetRenderDrawColor(sdlRenderer, 255, 255, 255, 255); - SDL_RenderClear(sdlRenderer); - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); - SDL_RenderSetLogicalSize(sdlRenderer, DISPLAY_WIDTH, DISPLAY_HEIGHT); -#if ENABLE_VRAM_VIEW - SDL_SetRenderDrawColor(vramRenderer, 0, 0, 0, 255); - SDL_RenderClear(vramRenderer); - SDL_RenderSetLogicalSize(vramRenderer, vramWindowWidth, vramWindowHeight); -#endif - - sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ABGR1555, SDL_TEXTUREACCESS_STREAMING, DISPLAY_WIDTH, DISPLAY_HEIGHT); - if (sdlTexture == NULL) { - fprintf(stderr, "Texture could not be created! SDL_Error: %s\n", SDL_GetError()); - return 1; - } - -#if ENABLE_VRAM_VIEW - vramTexture = SDL_CreateTexture(vramRenderer, SDL_PIXELFORMAT_ABGR1555, SDL_TEXTUREACCESS_STREAMING, vramWindowWidth, vramWindowHeight); - if (vramTexture == NULL) { - fprintf(stderr, "Texture could not be created! SDL_Error: %s\n", SDL_GetError()); - return 1; - } -#endif - -#ifdef PS2 - SDL_SetTextureScaleMode(sdlTexture, SDL_ScaleModeLinear); - SDL_SetTextureColorMod(sdlTexture, 140, 140, 140); -#endif - -#if ENABLE_AUDIO - SDL_AudioSpec want; - - SDL_memset(&want, 0, sizeof(want)); /* or SDL_zero(want) */ - want.freq = 48000; - want.format = AUDIO_F32; - want.channels = 2; - want.samples = (want.freq / 60); - cgb_audio_init(want.freq); - - if (SDL_OpenAudio(&want, 0) < 0) - SDL_Log("Failed to open audio: %s", SDL_GetError()); - else { - if (want.format != AUDIO_F32) /* we let this one thing change. */ - SDL_Log("We didn't get Float32 audio format."); - SDL_PauseAudio(0); - } -#endif - - VDraw(sdlTexture); -#if ENABLE_VRAM_VIEW - VramDraw(vramTexture); -#endif - // Prevent the multiplayer screen from being drawn ( see core.c:GameInit() ) - REG_RCNT = 0x8000; - - // ChangeThreadPriority(GetThreadId(), 29); // 29 is lower than 30 ;) - - // // Set the time in miliseconds to call the function RotateThreads - // SetAlarm(1, RotateThreads, 0); - - // // mainLoopThread = SDL_CreateThread(DoMain, "AgbMain", NULL); - // // controlThread = SDL_CreateThread(DoControl, "DoControl", NULL); - // struct t_ee_thread agbThread, controlThread, thread_thread; - // int agbThreadId, controlThreadId; - - // printf("\nBeginning thread demo:\n"); - - // thread_thread.func = dispatcher; - // thread_thread.stack = disp_stack; - // thread_thread.stack_size = THREAD_STACK_SIZE; - // thread_thread.gp_reg = &_gp; - // thread_thread.initial_priority = 0; - // StartThread(disp_threadid = CreateThread(&thread_thread), NULL); - - // thread_thread.func = DoMain; - // thread_thread.stack = thread_stack; - // thread_thread.stack_size = THREAD_STACK_SIZE; - // thread_thread.gp_reg = &_gp; - // thread_thread.initial_priority = 30; - // if ((agbThreadId = CreateThread(&thread_thread)) < 0) { - // printf("CREATE THREAD ERROR!!!\n"); - // return -1; - // } - - // printf("Starting threads\n"); - // StartThread(agbThreadId, NULL); - - // ChangeThreadPriority(GetThreadId(), 30); - // Who knows why, but something to do with the way we set - // REG_KEYINPUT whilst in tas testing mode causes a soft lock - // if we don't set this when not doing tas testing then the game - // softlocks on the intro - REG_KEYINPUT = KEYS_MASK; - - DoMain(NULL); - - // DoControl(NULL); - - // printf("terminating\n"); - // TerminateThread(agbThreadId); - // DeleteThread(agbThreadId); - - // StoreSaveFile(); - // CloseSaveFile(); - // while (1) { - // if (SDL_AtomicGet(&isFrameAvailable)) { - // SDL_AtomicSet(&isFrameAvailable, 0); - // REG_DISPSTAT |= INTR_FLAG_VBLANK; - // RunDMAs(DMA_VBLANK); - // if (REG_DISPSTAT & DISPSTAT_VBLANK_INTR) - // gIntrTable[INTR_INDEX_VBLANK](); - // REG_DISPSTAT &= ~INTR_FLAG_VBLANK; - - // SDL_SemPost(vBlankSemaphore); - // } - // } - - SDL_DestroyWindow(sdlWindow); - SDL_Quit(); - return 0; -} - -int DoControl(void *data) -{ - printf("CONTROL??\n"); - double accumulator = 0.0; - -#if 0 - memset(&internalClock, 0, sizeof(internalClock)); - internalClock.status = SIIRTCINFO_24HOUR; - UpdateInternalClock(); -#endif - - REG_KEYINPUT = 0x3FF; - - while (isRunning) { - ProcessSDLEvents(); - REG_KEYINPUT = KEYS_MASK ^ Platform_GetKeyInput(); - - if (!paused || stepOneFrame) { - double dt = fixedTimestep / timeScale; // TODO: Fix speedup - double deltaTime = 0; - - curGameTime = SDL_GetPerformanceCounter(); - if (stepOneFrame) { - deltaTime = dt; - } else { - deltaTime = (double)((curGameTime - lastGameTime) / (double)SDL_GetPerformanceFrequency()); - if (deltaTime > (dt * 5)) - deltaTime = dt * 5; - } - lastGameTime = curGameTime; - - accumulator += deltaTime; - - while (accumulator >= dt) { - // printf("WAITING %d %d\n", accumulator, dt); - - if (SDL_AtomicGet(&isFrameAvailable)) { - // printf("Frame is ready\n"); - VDraw(sdlTexture); - SDL_AtomicSet(&isFrameAvailable, 0); - - REG_DISPSTAT |= INTR_FLAG_VBLANK; - - // TODO(Jace): I think this should be DMA_VBLANK. - // If not, and it is HBLANK instead, add a note here, why it is! - RunDMAs(DMA_VBLANK); - - if (REG_DISPSTAT & DISPSTAT_VBLANK_INTR) - gIntrTable[INTR_INDEX_VBLANK](); - REG_DISPSTAT &= ~INTR_FLAG_VBLANK; - - SDL_SemPost(vBlankSemaphore); - // SDL_AtomicSet(&isVblankReady, 1); - - accumulator -= dt; - } else { - // SleepThread(); - } - } - - if (paused && stepOneFrame) { - stepOneFrame = false; - } - } - - SDL_RenderClear(sdlRenderer); - SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); - -#if ENABLE_VRAM_VIEW - VramDraw(vramTexture); - SDL_RenderClear(vramRenderer); - SDL_RenderCopy(vramRenderer, vramTexture, NULL, NULL); -#endif - // if (videoScaleChanged) { - // SDL_SetWindowSize(sdlWindow, DISPLAY_WIDTH * videoScale, DISPLAY_HEIGHT * videoScale); - // videoScaleChanged = false; - // } - // SDL_RenderPresent(sdlRenderer); -#if ENABLE_VRAM_VIEW - SDL_RenderPresent(vramRenderer); -#endif - // SleepThread(); - } - return 0; -} - -static void ReadSaveFile(char *path) -{ - // Check whether the saveFile exists, and create it if not - sSaveFile = fopen(path, "r+b"); - if (sSaveFile == NULL) { - sSaveFile = fopen(path, "w+b"); - } - - fseek(sSaveFile, 0, SEEK_END); - int fileSize = ftell(sSaveFile); - fseek(sSaveFile, 0, SEEK_SET); - - // Only read as many bytes as fit inside the buffer - // or as many bytes as are in the file - int bytesToRead = (fileSize < sizeof(FLASH_BASE)) ? fileSize : sizeof(FLASH_BASE); - - int bytesRead = fread(FLASH_BASE, 1, bytesToRead, sSaveFile); - - // Fill the buffer if the savefile was just created or smaller than the buffer itself - for (int i = bytesRead; i < sizeof(FLASH_BASE); i++) { - FLASH_BASE[i] = 0xFF; - } -} - -static void StoreSaveFile() -{ - if (sSaveFile != NULL) { - fseek(sSaveFile, 0, SEEK_SET); - fwrite(FLASH_BASE, 1, sizeof(FLASH_BASE), sSaveFile); - } -} - -void Platform_StoreSaveFile(void) { StoreSaveFile(); } - -static void CloseSaveFile() -{ - if (sSaveFile != NULL) { - fclose(sSaveFile); - } -} - -// Key mappings -#define KEY_A_BUTTON SDLK_c -#define KEY_B_BUTTON SDLK_x -#define KEY_START_BUTTON SDLK_RETURN -#define KEY_SELECT_BUTTON SDLK_BACKSLASH -#define KEY_L_BUTTON SDLK_s -#define KEY_R_BUTTON SDLK_d -#define KEY_DPAD_UP SDLK_UP -#define KEY_DPAD_DOWN SDLK_DOWN -#define KEY_DPAD_LEFT SDLK_LEFT -#define KEY_DPAD_RIGHT SDLK_RIGHT - -#define HANDLE_KEYUP(key) \ - case KEY_##key: \ - keys &= ~key; \ - break; - -#define HANDLE_KEYDOWN(key) \ - case KEY_##key: \ - keys |= key; \ - break; - -static u16 keys; - -u32 fullScreenFlags = 0; -static SDL_DisplayMode sdlDispMode = { 0 }; - -void Platform_QueueAudio(const void *data, uint32_t bytesCount) -{ - // Reset the audio buffer if we are 10 frames out of sync - // If this happens it suggests there was some OS level lag - // in playing audio. The queue length should remain stable at < 10 otherwise - // if (SDL_GetQueuedAudioSize(1) > (bytesCount * 10)) { - // SDL_ClearQueuedAudio(1); - // } - - // SDL_QueueAudio(1, data, bytesCount); - // printf("Queueing %d\n, QueueSize %d\n", bytesCount, SDL_GetQueuedAudioSize(1)); -} - -void ProcessSDLEvents(void) -{ - SDL_Event event; - - while (SDL_PollEvent(&event)) { - SDL_Keycode keyCode = event.key.keysym.sym; - Uint16 keyMod = event.key.keysym.mod; - - switch (event.type) { - case SDL_QUIT: - isRunning = false; - break; - case SDL_KEYUP: - switch (event.key.keysym.sym) { - HANDLE_KEYUP(A_BUTTON) - HANDLE_KEYUP(B_BUTTON) - HANDLE_KEYUP(START_BUTTON) - HANDLE_KEYUP(SELECT_BUTTON) - HANDLE_KEYUP(L_BUTTON) - HANDLE_KEYUP(R_BUTTON) - HANDLE_KEYUP(DPAD_UP) - HANDLE_KEYUP(DPAD_DOWN) - HANDLE_KEYUP(DPAD_LEFT) - HANDLE_KEYUP(DPAD_RIGHT) - case SDLK_SPACE: - if (speedUp) { - speedUp = false; - timeScale = 1.0; - SDL_ClearQueuedAudio(1); - SDL_PauseAudio(0); - } - break; - } - break; - case SDL_KEYDOWN: - if (keyCode == SDLK_RETURN && (keyMod & KMOD_ALT)) { - fullScreenFlags ^= SDL_WINDOW_FULLSCREEN_DESKTOP; - if (fullScreenFlags & SDL_WINDOW_FULLSCREEN_DESKTOP) { - SDL_GetWindowDisplayMode(sdlWindow, &sdlDispMode); - preFullscreenVideoScale = videoScale; - } else { - SDL_SetWindowDisplayMode(sdlWindow, &sdlDispMode); - videoScale = preFullscreenVideoScale; - } - SDL_SetWindowFullscreen(sdlWindow, fullScreenFlags); - - SDL_SetWindowSize(sdlWindow, DISPLAY_WIDTH * videoScale, DISPLAY_HEIGHT * videoScale); - videoScaleChanged = FALSE; - } else - switch (event.key.keysym.sym) { - HANDLE_KEYDOWN(A_BUTTON) - HANDLE_KEYDOWN(B_BUTTON) - HANDLE_KEYDOWN(START_BUTTON) - HANDLE_KEYDOWN(SELECT_BUTTON) - HANDLE_KEYDOWN(L_BUTTON) - HANDLE_KEYDOWN(R_BUTTON) - HANDLE_KEYDOWN(DPAD_UP) - HANDLE_KEYDOWN(DPAD_DOWN) - HANDLE_KEYDOWN(DPAD_LEFT) - HANDLE_KEYDOWN(DPAD_RIGHT) - case SDLK_r: - if (event.key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) { - DoSoftReset(); - } - break; - case SDLK_p: - if (event.key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) { - paused = !paused; - } - break; - case SDLK_SPACE: - if (!speedUp) { - speedUp = true; - timeScale = 5.0; - SDL_PauseAudio(1); - } - break; - case SDLK_F10: - paused = true; - stepOneFrame = true; - break; - } - break; - case SDL_WINDOWEVENT: - if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { - unsigned int w = event.window.data1; - unsigned int h = event.window.data2; - - videoScale = 0; - if (w / DISPLAY_WIDTH > videoScale) - videoScale = w / DISPLAY_WIDTH; - if (h / DISPLAY_HEIGHT > videoScale) - videoScale = h / DISPLAY_HEIGHT; - if (videoScale < 1) - videoScale = 1; - - videoScaleChanged = true; - } - break; - } - } -} - -#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 - u16 gamepadKeys = GetXInputKeys(); - return (gamepadKeys != 0) ? gamepadKeys : keys; -#endif - - return keys; -} - -// BIOS function implementations are based on the VBA-M source code. - -static uint32_t CPUReadMemory(const void *src) { return *(uint32_t *)src; } - -static void CPUWriteMemory(void *dest, uint32_t val) { *(uint32_t *)dest = val; } - -static uint16_t CPUReadHalfWord(const void *src) { return *(uint16_t *)src; } - -static void CPUWriteHalfWord(void *dest, uint16_t val) { *(uint16_t *)dest = val; } - -static uint8_t CPUReadByte(const void *src) { return *(uint8_t *)src; } - -static void CPUWriteByte(void *dest, uint8_t val) { *(uint8_t *)dest = val; } - -static void RunDMAs(u32 type) -{ - // printf("Runing DMAs\n"); - for (int dmaNum = 0; dmaNum < DMA_COUNT; dmaNum++) { - struct DMATransfer *dma = &DMAList[dmaNum]; -#if !USE_NEW_DMA - // Regular GBA order - u32 dmaCntReg = (®_DMA0CNT)[dmaNum * 3]; -#else - // "64 bit" order - u32 dmaCntReg = (®_DMA0CNT)[dmaNum]; -#endif - if (!((dmaCntReg >> 16) & DMA_ENABLE)) { - dma->control &= ~DMA_ENABLE; - } - - if ((dma->control & DMA_ENABLE) && (((dma->control & DMA_START_MASK) >> 12) == type)) { - // printf("DMA%d src=%p, dest=%p, control=%d\n", dmaNum, dma->src, dma->dst, dma->control); - for (int i = 0; i < dma->size; i++) { - if ((dma->control) & DMA_32BIT) - *dma->dst32 = *dma->src32; - else - *dma->dst16 = *dma->src16; - - // process destination pointer changes - if (((dma->control) & DMA_DEST_MASK) == DMA_DEST_INC) { - if ((dma->control) & DMA_32BIT) - dma->dst32++; - else - dma->dst16++; - } else if (((dma->control) & DMA_DEST_MASK) == DMA_DEST_DEC) { - if ((dma->control) & DMA_32BIT) - dma->dst32--; - else - dma->dst16--; - } else if (((dma->control) & DMA_DEST_MASK) == DMA_DEST_RELOAD) // TODO - { - if ((dma->control) & DMA_32BIT) - dma->dst32++; - else - dma->dst16++; - } - - // process source pointer changes - if (((dma->control) & DMA_SRC_MASK) == DMA_SRC_INC) { - if ((dma->control) & DMA_32BIT) - dma->src32++; - else - dma->src16++; - } else if (((dma->control) & DMA_SRC_MASK) == DMA_SRC_DEC) { - if ((dma->control) & DMA_32BIT) - dma->src32--; - else - dma->src16--; - } - } - - if (dma->control & DMA_REPEAT) { - // NOTE: If we change dma->size anywhere above, we need to reset its value here. - - if (((dma->control) & DMA_DEST_MASK) == DMA_DEST_RELOAD) { -#if !USE_NEW_DMA - dma->dst = (void *)(uintptr_t)(®_DMA0DAD)[dmaNum * 3]; -#else - dma->dst = (void *)(uintptr_t)(®_DMA0DAD)[dmaNum]; -#endif - } - } else { - dma->control &= ~DMA_ENABLE; - } - } - } -} - -#if 0 -s32 Div(s32 num, s32 denom) -{ - if (denom != 0) { - return num / denom; - } else { - return 0; - } -} - -s32 Mod(s32 num, s32 denom) -{ - if (denom != 0) { - return num % denom; - } else { - return 0; - } -} -#endif - -int MultiBoot(struct MultiBootParam *mp) { return 0; } - -#ifdef DmaSet -#undef DmaSet -#endif -void DmaSet(int dmaNum, const void *src, void *dest, u32 control) -{ - if (dmaNum >= DMA_COUNT) { - fprintf(stderr, "DmaSet with invalid DMA number: dmaNum=%d, src=%p, dest=%p, control=%d\n", dmaNum, src, dest, control); - return; - } - -#if !USE_NEW_DMA - // Regular GBA order - (®_DMA0SAD)[dmaNum * 3] = (uintptr_t)src; - (®_DMA0DAD)[dmaNum * 3] = (uintptr_t)dest; - (®_DMA0CNT)[dmaNum * 3] = (size_t)control; -#else - // "64 bit" order - (®_DMA0SAD)[dmaNum] = (uintptr_t)src; - (®_DMA0DAD)[dmaNum] = (uintptr_t)dest; - (®_DMA0CNT)[dmaNum] = (size_t)control; -#endif - - struct DMATransfer *dma = &DMAList[dmaNum]; - dma->src = src; - dma->dst = dest; - dma->size = control & 0x1ffff; - dma->control = control >> 16; - - // printf("\nDMA%d: S:%p %p -> %p\n", dmaNum, src, dest, dest + dma->size); - - RunDMAs(DMA_NOW); -} - -void DmaStop(int dmaNum) -{ -#if !USE_NEW_DMA - (®_DMA0CNT)[dmaNum * 3] &= ~((DMA_ENABLE | DMA_START_MASK | DMA_DREQ_ON | DMA_REPEAT) << 16); -#else - (®_DMA0CNT)[dmaNum] &= ~((DMA_ENABLE | DMA_START_MASK | DMA_DREQ_ON | DMA_REPEAT) << 16); -#endif - - struct DMATransfer *dma = &DMAList[dmaNum]; - dma->control &= ~(DMA_ENABLE | DMA_START_MASK | DMA_DREQ_ON | DMA_REPEAT); -} - -void DmaWait(int dmaNum) -{ - vu32 *ctrlRegs = ®_DMA0CNT; -#if !USE_NEW_DMA - while (ctrlRegs[dmaNum * 3] & (DMA_ENABLE << 16)) -#else - while (ctrlRegs[dmaNum] & (DMA_ENABLE << 16)) -#endif - // SleepThread(); - ; -} - -void TestFunc(void) { } - -void CpuSet(const void *src, void *dst, u32 cnt) -{ - if (dst == NULL) { - TestFunc(); - printf("Attempted to CpuSet from %p to NULL\n", src); - return; - } - - int count = cnt & 0x1FFFFF; - - const u8 *source = src; - u8 *dest = dst; - - // 32-bit ? - if ((cnt >> 26) & 1) { - // assert(((uintptr_t)src & ~3) == (uintptr_t)src); - // assert(((uintptr_t)dst & ~3) == (uintptr_t)dst); - - // needed for 32-bit mode! - // source = (u8 *)((uint32_t )source & ~3); - // dest = (u8 *)((uint32_t )dest & ~3); - - // fill ? - if ((cnt >> 24) & 1) { - uint32_t value = CPUReadMemory(source); - while (count) { - CPUWriteMemory(dest, value); - dest += 4; - count--; - } - } else { - // copy - while (count) { - CPUWriteMemory(dest, CPUReadMemory(source)); - source += 4; - dest += 4; - count--; - } - } - } else { - // No align on 16-bit fill? - // assert(((uintptr_t)src & ~1) == (uintptr_t)src); - // assert(((uintptr_t)dst & ~1) == (uintptr_t)dst); - - // 16-bit fill? - if ((cnt >> 24) & 1) { - uint16_t value = CPUReadHalfWord(source); - while (count) { - CPUWriteHalfWord(dest, value); - dest += 2; - count--; - } - } else { - // copy - while (count) { - CPUWriteHalfWord(dest, CPUReadHalfWord(source)); - source += 2; - dest += 2; - count--; - } - } - } -} - -void CpuFastSet(const void *src, void *dst, u32 cnt) -{ - if (dst == NULL) { - puts("Attempted to CpuFastSet to NULL\n"); - return; - } - - int count = cnt & 0x1FFFFF; - - const u8 *source = src; - u8 *dest = dst; - - // source = (u8 *)((uint32_t )source & ~3); - // dest = (u8 *)((uint32_t )dest & ~3); - - // fill? - if ((cnt >> 24) & 1) { - uint32_t value = CPUReadMemory(source); - while (count > 0) { - // BIOS always transfers 32 bytes at a time - for (int i = 0; i < 8; i++) { - CPUWriteMemory(dest, value); - dest += 4; - } - count -= 8; - } - } else { - // copy - while (count > 0) { - // BIOS always transfers 32 bytes at a time - for (int i = 0; i < 8; i++) { - uint32_t value = CPUReadMemory(source); - CPUWriteMemory(dest, value); - source += 4; - dest += 4; - } - count -= 8; - } - } -} - -void LZ77UnCompVram(const void *src_, void *dest_) -{ - const u8 *src = (const u8 *)src_; - u8 *dest = dest_; - int destSize = (src[3] << 16) | (src[2] << 8) | src[1]; - int srcPos = 4; - int destPos = 0; - - for (;;) { - unsigned char flags = src[srcPos++]; - - for (int i = 0; i < 8; i++) { - if (flags & 0x80) { - int blockSize = (src[srcPos] >> 4) + 3; - int blockDistance = (((src[srcPos] & 0xF) << 8) | src[srcPos + 1]) + 1; - - srcPos += 2; - - int blockPos = destPos - blockDistance; - - // Some Ruby/Sapphire tilesets overflow. - if (destPos + blockSize > destSize) { - blockSize = destSize - destPos; - // fprintf(stderr, "Destination buffer overflow.\n"); - puts("Destination buffer overflow.\n"); - } - - if (blockPos < 0) - goto fail; - - for (int j = 0; j < blockSize; j++) - dest[destPos++] = dest[blockPos + j]; - } else { - if (destPos >= destSize) - goto fail; - - dest[destPos++] = src[srcPos++]; - } - - if (destPos == destSize) { - return; - } - - flags <<= 1; - } - } - -fail: - puts("Fatal error while decompressing LZ file.\n"); -} - -void LZ77UnCompWram(const void *src, void *dst) -{ - const uint8_t *source = src; - uint8_t *dest = dst; - - uint32_t header = CPUReadMemory(source); - source += 4; - - int len = header >> 8; - - while (len > 0) { - uint8_t d = CPUReadByte(source++); - - if (d) { - for (int i = 0; i < 8; i++) { - if (d & 0x80) { - uint16_t data = CPUReadByte(source++) << 8; - data |= CPUReadByte(source++); - int length = (data >> 12) + 3; - int offset = (data & 0x0FFF); - uint8_t *windowOffset = dest - offset - 1; - for (int i2 = 0; i2 < length; i2++) { - CPUWriteByte(dest++, CPUReadByte(windowOffset++)); - len--; - if (len == 0) - return; - } - } else { - CPUWriteByte(dest++, CPUReadByte(source++)); - len--; - if (len == 0) - return; - } - d <<= 1; - } - } else { - for (int i = 0; i < 8; i++) { - CPUWriteByte(dest++, CPUReadByte(source++)); - len--; - if (len == 0) - return; - } - } - } -} - -void RLUnCompWram(const void *src, void *dest) -{ - int remaining = CPUReadMemory(src) >> 8; - int blockHeader; - int block; - src += 4; - while (remaining > 0) { - blockHeader = CPUReadByte(src); - src++; - if (blockHeader & 0x80) // Compressed? - { - blockHeader &= 0x7F; - blockHeader += 3; - block = CPUReadByte(src); - src++; - while (blockHeader-- && remaining) { - remaining--; - CPUWriteByte(dest, block); - dest++; - } - } else // Uncompressed - { - blockHeader++; - while (blockHeader-- && remaining) { - remaining--; - u8 byte = CPUReadByte(src); - src++; - CPUWriteByte(dest, byte); - dest++; - } - } - } -} - -void RLUnCompVram(const void *src, void *dest) -{ - int remaining = CPUReadMemory(src) >> 8; - int padding = (4 - remaining) & 0x3; - int blockHeader; - int block; - int halfWord = 0; - src += 4; - while (remaining > 0) { - blockHeader = CPUReadByte(src); - src++; - if (blockHeader & 0x80) // Compressed? - { - blockHeader &= 0x7F; - blockHeader += 3; - block = CPUReadByte(src); - src++; - while (blockHeader-- && remaining) { - remaining--; - if ((uintptr_t)dest & 1) { - halfWord |= block << 8; - CPUWriteHalfWord((void *)((uintptr_t)dest ^ 1), halfWord); - } else - halfWord = block; - dest++; - } - } else // Uncompressed - { - blockHeader++; - while (blockHeader-- && remaining) { - remaining--; - u8 byte = CPUReadByte(src); - src++; - if ((uintptr_t)dest & 1) { - halfWord |= byte << 8; - CPUWriteHalfWord((void *)((uintptr_t)dest ^ 1), halfWord); - } else - halfWord = byte; - dest++; - } - } - } - if ((uintptr_t)dest & 1) { - padding--; - dest++; - } - for (; padding > 0; padding -= 2, dest += 2) - CPUWriteHalfWord(dest, 0); -} - -const s16 sineTable[256] - = { (s16)0x0000, (s16)0x0192, (s16)0x0323, (s16)0x04B5, (s16)0x0645, (s16)0x07D5, (s16)0x0964, (s16)0x0AF1, (s16)0x0C7C, (s16)0x0E05, - (s16)0x0F8C, (s16)0x1111, (s16)0x1294, (s16)0x1413, (s16)0x158F, (s16)0x1708, (s16)0x187D, (s16)0x19EF, (s16)0x1B5D, (s16)0x1CC6, - (s16)0x1E2B, (s16)0x1F8B, (s16)0x20E7, (s16)0x223D, (s16)0x238E, (s16)0x24DA, (s16)0x261F, (s16)0x275F, (s16)0x2899, (s16)0x29CD, - (s16)0x2AFA, (s16)0x2C21, (s16)0x2D41, (s16)0x2E5A, (s16)0x2F6B, (s16)0x3076, (s16)0x3179, (s16)0x3274, (s16)0x3367, (s16)0x3453, - (s16)0x3536, (s16)0x3612, (s16)0x36E5, (s16)0x37AF, (s16)0x3871, (s16)0x392A, (s16)0x39DA, (s16)0x3A82, (s16)0x3B20, (s16)0x3BB6, - (s16)0x3C42, (s16)0x3CC5, (s16)0x3D3E, (s16)0x3DAE, (s16)0x3E14, (s16)0x3E71, (s16)0x3EC5, (s16)0x3F0E, (s16)0x3F4E, (s16)0x3F84, - (s16)0x3FB1, (s16)0x3FD3, (s16)0x3FEC, (s16)0x3FFB, (s16)0x4000, (s16)0x3FFB, (s16)0x3FEC, (s16)0x3FD3, (s16)0x3FB1, (s16)0x3F84, - (s16)0x3F4E, (s16)0x3F0E, (s16)0x3EC5, (s16)0x3E71, (s16)0x3E14, (s16)0x3DAE, (s16)0x3D3E, (s16)0x3CC5, (s16)0x3C42, (s16)0x3BB6, - (s16)0x3B20, (s16)0x3A82, (s16)0x39DA, (s16)0x392A, (s16)0x3871, (s16)0x37AF, (s16)0x36E5, (s16)0x3612, (s16)0x3536, (s16)0x3453, - (s16)0x3367, (s16)0x3274, (s16)0x3179, (s16)0x3076, (s16)0x2F6B, (s16)0x2E5A, (s16)0x2D41, (s16)0x2C21, (s16)0x2AFA, (s16)0x29CD, - (s16)0x2899, (s16)0x275F, (s16)0x261F, (s16)0x24DA, (s16)0x238E, (s16)0x223D, (s16)0x20E7, (s16)0x1F8B, (s16)0x1E2B, (s16)0x1CC6, - (s16)0x1B5D, (s16)0x19EF, (s16)0x187D, (s16)0x1708, (s16)0x158F, (s16)0x1413, (s16)0x1294, (s16)0x1111, (s16)0x0F8C, (s16)0x0E05, - (s16)0x0C7C, (s16)0x0AF1, (s16)0x0964, (s16)0x07D5, (s16)0x0645, (s16)0x04B5, (s16)0x0323, (s16)0x0192, (s16)0x0000, (s16)0xFE6E, - (s16)0xFCDD, (s16)0xFB4B, (s16)0xF9BB, (s16)0xF82B, (s16)0xF69C, (s16)0xF50F, (s16)0xF384, (s16)0xF1FB, (s16)0xF074, (s16)0xEEEF, - (s16)0xED6C, (s16)0xEBED, (s16)0xEA71, (s16)0xE8F8, (s16)0xE783, (s16)0xE611, (s16)0xE4A3, (s16)0xE33A, (s16)0xE1D5, (s16)0xE075, - (s16)0xDF19, (s16)0xDDC3, (s16)0xDC72, (s16)0xDB26, (s16)0xD9E1, (s16)0xD8A1, (s16)0xD767, (s16)0xD633, (s16)0xD506, (s16)0xD3DF, - (s16)0xD2BF, (s16)0xD1A6, (s16)0xD095, (s16)0xCF8A, (s16)0xCE87, (s16)0xCD8C, (s16)0xCC99, (s16)0xCBAD, (s16)0xCACA, (s16)0xC9EE, - (s16)0xC91B, (s16)0xC851, (s16)0xC78F, (s16)0xC6D6, (s16)0xC626, (s16)0xC57E, (s16)0xC4E0, (s16)0xC44A, (s16)0xC3BE, (s16)0xC33B, - (s16)0xC2C2, (s16)0xC252, (s16)0xC1EC, (s16)0xC18F, (s16)0xC13B, (s16)0xC0F2, (s16)0xC0B2, (s16)0xC07C, (s16)0xC04F, (s16)0xC02D, - (s16)0xC014, (s16)0xC005, (s16)0xC000, (s16)0xC005, (s16)0xC014, (s16)0xC02D, (s16)0xC04F, (s16)0xC07C, (s16)0xC0B2, (s16)0xC0F2, - (s16)0xC13B, (s16)0xC18F, (s16)0xC1EC, (s16)0xC252, (s16)0xC2C2, (s16)0xC33B, (s16)0xC3BE, (s16)0xC44A, (s16)0xC4E0, (s16)0xC57E, - (s16)0xC626, (s16)0xC6D6, (s16)0xC78F, (s16)0xC851, (s16)0xC91B, (s16)0xC9EE, (s16)0xCACA, (s16)0xCBAD, (s16)0xCC99, (s16)0xCD8C, - (s16)0xCE87, (s16)0xCF8A, (s16)0xD095, (s16)0xD1A6, (s16)0xD2BF, (s16)0xD3DF, (s16)0xD506, (s16)0xD633, (s16)0xD767, (s16)0xD8A1, - (s16)0xD9E1, (s16)0xDB26, (s16)0xDC72, (s16)0xDDC3, (s16)0xDF19, (s16)0xE075, (s16)0xE1D5, (s16)0xE33A, (s16)0xE4A3, (s16)0xE611, - (s16)0xE783, (s16)0xE8F8, (s16)0xEA71, (s16)0xEBED, (s16)0xED6C, (s16)0xEEEF, (s16)0xF074, (s16)0xF1FB, (s16)0xF384, (s16)0xF50F, - (s16)0xF69C, (s16)0xF82B, (s16)0xF9BB, (s16)0xFB4B, (s16)0xFCDD, (s16)0xFE6E }; - -void BgAffineSet(struct BgAffineSrcData *src, struct BgAffineDstData *dest, s32 count) -{ - for (s32 i = 0; i < count; i++) { - s32 cx = src[i].texX; - s32 cy = src[i].texY; - s16 dispx = src[i].scrX; - s16 dispy = src[i].scrY; - s16 rx = src[i].sx; - s16 ry = src[i].sy; - u16 theta = src[i].alpha >> 8; - s32 a = sineTable[(theta + 0x40) & 255]; - s32 b = sineTable[theta]; - - s16 dx = (rx * a) >> 14; - s16 dmx = (rx * b) >> 14; - s16 dy = (ry * b) >> 14; - s16 dmy = (ry * a) >> 14; - - dest[i].pa = dx; - dest[i].pb = -dmx; - dest[i].pc = dy; - dest[i].pd = dmy; - - s32 startx = cx - dx * dispx + dmx * dispy; - s32 starty = cy - dy * dispx - dmy * dispy; - - dest[i].dx = startx; - dest[i].dy = starty; - } -} - -void ObjAffineSet(struct ObjAffineSrcData *src, void *dest, s32 count, s32 offset) -{ - for (s32 i = 0; i < count; i++) { - s16 rx = src[i].xScale; - s16 ry = src[i].yScale; - u16 theta = src[i].rotation >> 8; - - s32 a = (s32)sineTable[(theta + 64) & 255]; - s32 b = (s32)sineTable[theta]; - - s16 dx = ((s32)rx * a) >> 14; - s16 dmx = ((s32)rx * b) >> 14; - s16 dy = ((s32)ry * b) >> 14; - s16 dmy = ((s32)ry * a) >> 14; - - CPUWriteHalfWord(dest, dx); - dest += offset; - CPUWriteHalfWord(dest, -dmx); - dest += offset; - CPUWriteHalfWord(dest, dy); - dest += offset; - CPUWriteHalfWord(dest, dmy); - dest += offset; - } -} - -void SoftReset(u32 resetFlags) { } - -void SoftResetExram(u32 resetFlags) { } - -static const uint16_t bgMapSizes[][2] = { - { 32, 32 }, - { 64, 32 }, - { 32, 64 }, - { 64, 64 }, -}; - -#define mosaicBGEffectX (REG_MOSAIC & 0xF) -#define mosaicBGEffectY ((REG_MOSAIC >> 4) & 0xF) -#define mosaicSpriteEffectX ((REG_MOSAIC >> 8) & 0xF) -#define mosaicSpriteEffectY ((REG_MOSAIC >> 12) & 0xF) -#define applyBGHorizontalMosaicEffect(x) (x - (x % (mosaicBGEffectX + 1))) -#define applyBGVerticalMosaicEffect(y) (y - (y % (mosaicBGEffectY + 1))) -#define applySpriteHorizontalMosaicEffect(x) (x - (x % (mosaicSpriteEffectX + 1))) -#define applySpriteVerticalMosaicEffect(y) (y - (y % (mosaicSpriteEffectY + 1))) - -static void RenderBGScanline(int bgNum, uint16_t control, uint16_t hoffs, uint16_t voffs, int lineNum, uint16_t *line) -{ - unsigned int charBaseBlock = (control >> 2) & 3; - unsigned int screenBaseBlock = (control & BGCNT_SCREENBASE_MASK) >> 8; - - unsigned int bitsPerPixel = ((control >> 7) & 1) ? 8 : 4; - unsigned int mapWidth = bgMapSizes[control >> 14][0]; - unsigned int mapHeight = bgMapSizes[control >> 14][1]; - unsigned int mapWidthInPixels = mapWidth * 8; - unsigned int mapHeightInPixels = mapHeight * 8; - - uint8_t *bgtiles = (uint8_t *)BG_CHAR_ADDR(charBaseBlock); - uint16_t *pal = (uint16_t *)PLTT; - - if (control & BGCNT_MOSAIC) - lineNum = applyBGVerticalMosaicEffect(lineNum); - - hoffs &= 0x1FF; - voffs &= 0x1FF; - - for (unsigned int x = 0; x < DISPLAY_WIDTH; x++) { - uint16_t *bgmap = (uint16_t *)BG_SCREEN_ADDR(screenBaseBlock); - // adjust for scroll - unsigned int xx; - if (control & BGCNT_MOSAIC) - xx = (applyBGHorizontalMosaicEffect(x) + hoffs) & 0x1FF; - else { - if (!(control & BGCNT_TXT512x256)) { - xx = (x + hoffs) & 0xFF; - } else { - xx = (x + hoffs) & 0x1FF; - } - } - - unsigned int yy = (lineNum + voffs); - - if (!(control & BGCNT_TXT256x512)) { - yy &= 0xFF; - } else { - yy &= 0x1FF; - } - - unsigned int mapX = xx / 8; - unsigned int mapY = yy / 8; - - // TODO: The mult. with 64 doesn't break stage maps, but most regular tilemaps are broken. -#if !WIDESCREEN_HACK - unsigned int mapIndex = mapY * 32 + mapX; -#else - unsigned int mapIndex = mapY * ((control & BGCNT_TXT512x256) ? 64 : 32) + mapX; -#endif - uint16_t entry = bgmap[mapIndex]; - - unsigned int tileNum = entry & 0x3FF; - unsigned int paletteNum = (entry >> 12) & 0xF; -#if ENABLE_VRAM_VIEW - vramPalIdBuffer[tileNum] = paletteNum; -#endif - - unsigned int tileX = xx % 8; - unsigned int tileY = yy % 8; - - // Flip if necessary - if (entry & (1 << 10)) - tileX = 7 - tileX; - if (entry & (1 << 11)) - tileY = 7 - tileY; - - uint16_t tileLoc = tileNum * (bitsPerPixel * 8); - uint16_t tileLocY = tileY * bitsPerPixel; - uint16_t tileLocX = tileX; - if (bitsPerPixel == 4) - tileLocX /= 2; - - uint8_t pixel = bgtiles[tileLoc + tileLocY + tileLocX]; - - if (bitsPerPixel == 4) { - if (tileX & 1) - pixel >>= 4; - else - pixel &= 0xF; - - if (pixel != 0) - line[x] = pal[16 * paletteNum + pixel] | 0x8000; - } else { - line[x] = pal[pixel] | 0x8000; - } - } -} - -static inline uint32_t getBgX(int bgNumber) -{ - if (bgNumber == 2) { - return REG_BG2X; - } else if (bgNumber == 3) { - return REG_BG3X; - } - - return 0; -} - -static inline uint32_t getBgY(int bgNumber) -{ - if (bgNumber == 2) { - return REG_BG2Y; - } else if (bgNumber == 3) { - return REG_BG3Y; - } - - return 0; -} - -static inline uint16_t getBgPA(int bgNumber) -{ - if (bgNumber == 2) { - return REG_BG2PA; - } else if (bgNumber == 3) { - return REG_BG3PA; - } - return 0; -} - -static inline uint16_t getBgPB(int bgNumber) -{ - if (bgNumber == 2) { - return REG_BG2PB; - } else if (bgNumber == 3) { - return REG_BG3PB; - } - - return 0; -} - -static inline uint16_t getBgPC(int bgNumber) -{ - if (bgNumber == 2) { - return REG_BG2PC; - } else if (bgNumber == 3) { - return REG_BG3PC; - } - - return 0; -} - -static inline uint16_t getBgPD(int bgNumber) -{ - if (bgNumber == 2) { - return REG_BG2PD; - } else if (bgNumber == 3) { - return REG_BG3PD; - } - - return 0; -} - -static void RenderRotScaleBGScanline(int bgNum, uint16_t control, uint16_t x, uint16_t y, int lineNum, uint16_t *line) -{ - vBgCnt *bgcnt = (vBgCnt *)&control; - unsigned int charBaseBlock = bgcnt->charBaseBlock; - unsigned int screenBaseBlock = bgcnt->screenBaseBlock; - unsigned int mapWidth = 1 << (4 + (bgcnt->screenSize)); // number of tiles - - uint8_t *bgtiles = (uint8_t *)(VRAM + charBaseBlock * 0x4000); - uint8_t *bgmap = (uint8_t *)(VRAM + screenBaseBlock * 0x800); - uint16_t *pal = (uint16_t *)PLTT; - - if (control & BGCNT_MOSAIC) - lineNum = applyBGVerticalMosaicEffect(lineNum); - - s16 pa = getBgPA(bgNum); - s16 pb = getBgPB(bgNum); - s16 pc = getBgPC(bgNum); - s16 pd = getBgPD(bgNum); - - int sizeX = 128; - int sizeY = 128; - - switch (bgcnt->screenSize) { - case 0: - break; - case 1: - sizeX = sizeY = 256; - break; - case 2: - sizeX = sizeY = 512; - break; - case 3: - sizeX = sizeY = 1024; - break; - } - - int maskX = sizeX - 1; - int maskY = sizeY - 1; - - int yshift = ((control >> 14) & 3) + 4; - - /*int dx = pa & 0x7FFF; - if (pa & 0x8000) - dx |= 0xFFFF8000; - int dmx = pb & 0x7FFF; - if (pb & 0x8000) - dmx |= 0xFFFF8000; - int dy = pc & 0x7FFF; - if (pc & 0x8000) - dy |= 0xFFFF8000; - int dmy = pd & 0x7FFF; - if (pd & 0x8000) - dmy |= 0xFFFF8000;*/ - - s32 currentX = getBgX(bgNum); - s32 currentY = getBgY(bgNum); - // sign extend 28 bit number - currentX = ((currentX & (1 << 27)) ? currentX | 0xF0000000 : currentX); - currentY = ((currentY & (1 << 27)) ? currentY | 0xF0000000 : currentY); - - currentX += lineNum * pb; - currentY += lineNum * pd; - - int realX = currentX; - int realY = currentY; - - if (bgcnt->areaOverflowMode) { - for (int x = 0; x < DISPLAY_WIDTH; x++) { - int xxx = (realX >> 8) & maskX; - int yyy = (realY >> 8) & maskY; - - int tile = bgmap[(xxx >> 3) + ((yyy >> 3) << yshift)]; - - int tileX = xxx & 7; - int tileY = yyy & 7; - - uint8_t pixel = bgtiles[(tile << 6) + (tileY << 3) + tileX]; - - if (pixel != 0) { - line[x] = pal[pixel] | 0x8000; - } - - realX += pa; - realY += pc; - } - } else { - for (int x = 0; x < DISPLAY_WIDTH; x++) { - int xxx = (realX >> 8); - int yyy = (realY >> 8); - - if (xxx < 0 || yyy < 0 || xxx >= sizeX || yyy >= sizeY) { - // line[x] = 0x80000000; - } else { - int tile = bgmap[(xxx >> 3) + ((yyy >> 3) << yshift)]; - - int tileX = xxx & 7; - int tileY = yyy & 7; - - uint8_t pixel = bgtiles[(tile << 6) + (tileY << 3) + tileX]; - - if (pixel != 0) { - line[x] = pal[pixel] | 0x8000; - } - } - realX += pa; - realY += pc; - } - } - // the only way i could figure out how to get accurate mosaic on affine bgs - // luckily i dont think pokemon emerald uses mosaic on affine bgs - if (control & BGCNT_MOSAIC && mosaicBGEffectX > 0) { - for (int x = 0; x < DISPLAY_WIDTH; x++) { - uint16_t color = line[applyBGHorizontalMosaicEffect(x)]; - line[x] = color; - } - } -} - -const u8 spriteSizes[][2] = { - { 8, 16 }, - { 8, 32 }, - { 16, 32 }, - { 32, 64 }, -}; - -#define getAlphaBit(x) ((x >> 15) & 1) -#define getRedChannel(x) ((x >> 0) & 0x1F) -#define getGreenChannel(x) ((x >> 5) & 0x1F) -#define getBlueChannel(x) ((x >> 10) & 0x1F) -#define isbgEnabled(x) ((REG_DISPCNT >> 8) & 0xF) & (1 << x) - -static uint16_t alphaBlendColor(uint16_t targetA, uint16_t targetB) -{ - unsigned int eva = REG_BLDALPHA & 0x1F; - unsigned int evb = (REG_BLDALPHA >> 8) & 0x1F; - // shift right by 4 = division by 16 - unsigned int r = ((getRedChannel(targetA) * eva) + (getRedChannel(targetB) * evb)) >> 4; - unsigned int g = ((getGreenChannel(targetA) * eva) + (getGreenChannel(targetB) * evb)) >> 4; - unsigned int b = ((getBlueChannel(targetA) * eva) + (getBlueChannel(targetB) * evb)) >> 4; - - if (r > 31) - r = 31; - if (g > 31) - g = 31; - if (b > 31) - b = 31; - - return r | (g << 5) | (b << 10) | (1 << 15); -} - -static uint16_t alphaBrightnessIncrease(uint16_t targetA) -{ - unsigned int evy = (REG_BLDY & 0x1F); - unsigned int r = getRedChannel(targetA) + (31 - getRedChannel(targetA)) * evy / 16; - unsigned int g = getGreenChannel(targetA) + (31 - getGreenChannel(targetA)) * evy / 16; - unsigned int b = getBlueChannel(targetA) + (31 - getBlueChannel(targetA)) * evy / 16; - - if (r > 31) - r = 31; - if (g > 31) - g = 31; - if (b > 31) - b = 31; - - return r | (g << 5) | (b << 10) | (1 << 15); -} - -static uint16_t alphaBrightnessDecrease(uint16_t targetA) -{ - unsigned int evy = (REG_BLDY & 0x1F); - unsigned int r = getRedChannel(targetA) - getRedChannel(targetA) * evy / 16; - unsigned int g = getGreenChannel(targetA) - getGreenChannel(targetA) * evy / 16; - unsigned int b = getBlueChannel(targetA) - getBlueChannel(targetA) * evy / 16; - - if (r > 31) - r = 31; - if (g > 31) - g = 31; - if (b > 31) - b = 31; - - return r | (g << 5) | (b << 10) | (1 << 15); -} - -// outputs the blended pixel in colorOutput, the prxxx are the bg priority and -// subpriority, pixelpos is pixel offset in scanline -static bool alphaBlendSelectTargetB(struct scanlineData *scanline, uint16_t *colorOutput, char prnum, char prsub, int pixelpos, - bool spriteBlendEnabled) -{ - // iterate trough every possible bg to blend with, starting from specified priorities - // from arguments - for (unsigned int blndprnum = prnum; blndprnum <= 3; blndprnum++) { - // check if sprite is available to blend with, if sprite blending is enabled - if (spriteBlendEnabled == true && getAlphaBit(scanline->spriteLayers[blndprnum][pixelpos]) == 1) { - *colorOutput = scanline->spriteLayers[blndprnum][pixelpos]; - return true; - } - - for (unsigned int blndprsub = prsub; blndprsub < scanline->prioritySortedBgsCount[blndprnum]; blndprsub++) { - char currLayer = scanline->prioritySortedBgs[blndprnum][blndprsub]; - if (getAlphaBit(scanline->layers[currLayer][pixelpos]) == 1 && REG_BLDCNT & (1 << (8 + currLayer)) && isbgEnabled(currLayer)) { - *colorOutput = scanline->layers[currLayer][pixelpos]; - return true; - } - // if we hit a non target layer we should bail - if (getAlphaBit(scanline->layers[currLayer][pixelpos]) == 1 && isbgEnabled(currLayer) && prnum != blndprnum) { - return false; - } - } - prsub = 0; // start from zero in the next iteration - } - // no background got hit, check if backdrop is enabled and return it if enabled - // otherwise fail - if (REG_BLDCNT & BLDCNT_TGT2_BD) { - *colorOutput = *(uint16_t *)PLTT; - return true; - } else { - return false; - } -} - -#define WINMASK_BG0 (1 << 0) -#define WINMASK_BG1 (1 << 1) -#define WINMASK_BG2 (1 << 2) -#define WINMASK_BG3 (1 << 3) -#define WINMASK_OBJ (1 << 4) -#define WINMASK_CLR (1 << 5) -#define WINMASK_WINOUT (1 << 6) - -// checks if window horizontal is in bounds and takes account WIN wraparound -static bool winCheckHorizontalBounds(u16 left, u16 right, u16 xpos) -{ - if (left > right) - return (xpos >= left || xpos < right); - else - return (xpos >= left && xpos < right); -} - -// Parts of this code heavily borrowed from NanoboyAdvance. -static void DrawSprites(struct scanlineData *scanline, uint16_t vcount, bool windowsEnabled) -{ - int i; - unsigned int x; - unsigned int y; - void *objtiles = OBJ_VRAM0; - unsigned int blendMode = (REG_BLDCNT >> 6) & 3; - bool winShouldBlendPixel = true; - - int16_t matrix[2][2] = {}; - - if (!(REG_DISPCNT & (1 << 6))) { - puts("2-D OBJ Character mapping not supported."); - } - - for (i = OAM_ENTRY_COUNT - 1; i >= 0; i--) { - OamData *oam = &((OamData *)OAM)[i]; - unsigned int width; - unsigned int height; - uint16_t *pixels; - - bool isAffine = oam->split.affineMode & 1; - bool doubleSizeOrDisabled = (oam->split.affineMode >> 1) & 1; - bool isSemiTransparent = (oam->split.objMode == 1); - bool isObjWin = (oam->split.objMode == 2); - - if (!(isAffine) && doubleSizeOrDisabled) // disable for non-affine - { - continue; - } - - if (oam->split.shape == 0) { - width = (1 << oam->split.size) * 8; - height = (1 << oam->split.size) * 8; - } else if (oam->split.shape == 1) // wide - { - width = spriteSizes[oam->split.size][1]; - height = spriteSizes[oam->split.size][0]; - } else if (oam->split.shape == 2) // tall - { - width = spriteSizes[oam->split.size][0]; - height = spriteSizes[oam->split.size][1]; - } else { - continue; // prohibited, do not draw - } - - int rect_width = width; - int rect_height = height; - - int half_width = width / 2; - int half_height = height / 2; - - pixels = scanline->spriteLayers[oam->split.priority]; - - int32_t x = oam->split.x; - int32_t y = oam->split.y; - - if (x >= DISPLAY_WIDTH) - x -= 512; - if (y >= DISPLAY_HEIGHT) - y -= 256; - - if (isAffine) { - // TODO: there is probably a better way to do this - u8 matrixNum = oam->split.matrixNum * 4; - - OamData *oam1 = &((OamData *)OAM)[matrixNum]; - OamData *oam2 = &((OamData *)OAM)[matrixNum + 1]; - OamData *oam3 = &((OamData *)OAM)[matrixNum + 2]; - OamData *oam4 = &((OamData *)OAM)[matrixNum + 3]; - - matrix[0][0] = oam1->all.affineParam; - matrix[0][1] = oam2->all.affineParam; - matrix[1][0] = oam3->all.affineParam; - matrix[1][1] = oam4->all.affineParam; - - if (doubleSizeOrDisabled) // double size for affine - { - rect_width *= 2; - rect_height *= 2; - half_width *= 2; - half_height *= 2; - } - } else { - // Identity - matrix[0][0] = 0x100; - matrix[0][1] = 0; - matrix[1][0] = 0; - matrix[1][1] = 0x100; - } - - x += half_width; - y += half_height; - - // Does this sprite actually draw on this scanline? - if (vcount >= (y - half_height) && vcount < (y + half_height)) { - int local_y = (oam->split.mosaic == 1) ? applySpriteVerticalMosaicEffect(vcount) - y : vcount - y; - int number = oam->split.tileNum; - int palette = oam->split.paletteNum; - bool flipX = !isAffine && ((oam->split.matrixNum >> 3) & 1); - bool flipY = !isAffine && ((oam->split.matrixNum >> 4) & 1); - bool is8BPP = oam->split.bpp & 1; - - for (int local_x = -half_width; local_x <= half_width; local_x++) { - uint8_t *tiledata = (uint8_t *)objtiles; - uint16_t *palette = (uint16_t *)(PLTT + (0x200 / 2)); - int local_mosaicX; - int tex_x; - int tex_y; - - unsigned int global_x = local_x + x; - - if (global_x < 0 || global_x >= DISPLAY_WIDTH) - continue; - - if (oam->split.mosaic == 1) { - // mosaic effect has to be applied to global coordinates otherwise - // the mosaic will scroll - local_mosaicX = applySpriteHorizontalMosaicEffect(global_x) - x; - tex_x = ((matrix[0][0] * local_mosaicX + matrix[0][1] * local_y) >> 8) + (width / 2); - tex_y = ((matrix[1][0] * local_mosaicX + matrix[1][1] * local_y) >> 8) + (height / 2); - } else { - tex_x = ((matrix[0][0] * local_x + matrix[0][1] * local_y) >> 8) + (width / 2); - tex_y = ((matrix[1][0] * local_x + matrix[1][1] * local_y) >> 8) + (height / 2); - } - - /* Check if transformed coordinates are inside bounds. */ - - if (tex_x >= width || tex_y >= height || tex_x < 0 || tex_y < 0) - continue; - - if (flipX) - tex_x = width - tex_x - 1; - if (flipY) - tex_y = height - tex_y - 1; - - int tile_x = tex_x % 8; - int tile_y = tex_y % 8; - int block_x = tex_x / 8; - int block_y = tex_y / 8; - int block_offset = ((block_y * (REG_DISPCNT & 0x40 ? (width / 8) : 16)) + block_x); - uint16_t pixel = 0; - - if (!is8BPP) { - int tileDataIndex = (block_offset + oam->split.tileNum) * 32 + (tile_y * 4) + (tile_x / 2); - pixel = tiledata[tileDataIndex]; - if (tile_x & 1) - pixel >>= 4; - else - pixel &= 0xF; - palette += oam->split.paletteNum * 16; -#if ENABLE_VRAM_VIEW - vramPalIdBuffer[0x800 + (tileDataIndex / 32)] = 16 + oam->split.paletteNum; -#endif - } else { - pixel = tiledata[(block_offset * 2 + oam->split.tileNum) * 32 + (tile_y * 8) + tile_x]; - } - - if (pixel != 0) { - uint16_t color = palette[pixel]; - - // if sprite mode is 2 then write to the window mask instead - if (isObjWin) { - if (scanline->winMask[global_x] & WINMASK_WINOUT) - scanline->winMask[global_x] = (REG_WINOUT >> 8) & 0x3F; - continue; - } - // this code runs if pixel is to be drawn - if (global_x < DISPLAY_WIDTH && global_x >= 0) { - // check if its enabled in the window (if window is enabled) - winShouldBlendPixel = (windowsEnabled == false || scanline->winMask[global_x] & WINMASK_CLR); - - // has to be separated from the blend mode switch statement - // because of OBJ semi transparancy feature - if ((blendMode == 1 && REG_BLDCNT & BLDCNT_TGT1_OBJ && winShouldBlendPixel) || isSemiTransparent) { - uint16_t targetA = color; - uint16_t targetB = 0; - if (alphaBlendSelectTargetB(scanline, &targetB, oam->split.priority, 0, global_x, false)) { - color = alphaBlendColor(targetA, targetB); - } - } else if (REG_BLDCNT & BLDCNT_TGT1_OBJ && winShouldBlendPixel) { - switch (blendMode) { - case 2: - color = alphaBrightnessIncrease(color); - break; - case 3: - color = alphaBrightnessDecrease(color); - break; - } - } - - // write pixel to pixel framebuffer - pixels[global_x] = color | (1 << 15); - } - } - } - } - } -} - -static void DrawScanline(uint16_t *pixels, uint16_t vcount) -{ - unsigned int mode = REG_DISPCNT & 3; - unsigned char numOfBgs = (mode == 0 ? 4 : 3); - int bgnum, prnum; - struct scanlineData scanline; - unsigned int blendMode = (REG_BLDCNT >> 6) & 3; - unsigned int xpos; - - // initialize all priority bookkeeping data - memset(scanline.layers, 0, sizeof(scanline.layers)); - memset(scanline.winMask, 0, sizeof(scanline.winMask)); - memset(scanline.spriteLayers, 0, sizeof(scanline.spriteLayers)); - memset(scanline.prioritySortedBgsCount, 0, sizeof(scanline.prioritySortedBgsCount)); - - for (bgnum = 0; bgnum < numOfBgs; bgnum++) { - uint16_t bgcnt = *(uint16_t *)(REG_ADDR_BG0CNT + bgnum * 2); - uint16_t priority; - scanline.bgcnts[bgnum] = bgcnt; - scanline.bgtoprio[bgnum] = priority = (bgcnt & 3); - - char priorityCount = scanline.prioritySortedBgsCount[priority]; - scanline.prioritySortedBgs[priority][priorityCount] = bgnum; - scanline.prioritySortedBgsCount[priority]++; - } - - switch (mode) { - case 0: - // All backgrounds are text mode - for (bgnum = 3; bgnum >= 0; bgnum--) { - if (isbgEnabled(bgnum)) { - uint16_t bghoffs = *(uint16_t *)(REG_ADDR_BG0HOFS + bgnum * 4); - uint16_t bgvoffs = *(uint16_t *)(REG_ADDR_BG0VOFS + bgnum * 4); - - RenderBGScanline(bgnum, scanline.bgcnts[bgnum], bghoffs, bgvoffs, vcount, scanline.layers[bgnum]); - } - } - - break; - case 1: - // BG2 is affine - bgnum = 2; - if (isbgEnabled(bgnum)) { - RenderRotScaleBGScanline(bgnum, scanline.bgcnts[bgnum], REG_BG2X, REG_BG2Y, vcount, scanline.layers[bgnum]); - } - // BG0 and BG1 are text mode - for (bgnum = 1; bgnum >= 0; bgnum--) { - if (isbgEnabled(bgnum)) { - uint16_t bghoffs = *(uint16_t *)(REG_ADDR_BG0HOFS + bgnum * 4); - uint16_t bgvoffs = *(uint16_t *)(REG_ADDR_BG0VOFS + bgnum * 4); - - RenderBGScanline(bgnum, scanline.bgcnts[bgnum], bghoffs, bgvoffs, vcount, scanline.layers[bgnum]); - } - } - break; - default: - printf("Video mode %u is unsupported.\n", mode); - break; - } - - bool windowsEnabled = false; - u16 WIN0bottom, WIN0top, WIN0right, WIN0left; - u16 WIN1bottom, WIN1top, WIN1right, WIN1left; - bool WIN0enable, WIN1enable; - WIN0enable = false; - WIN1enable = false; - - // figure out if WIN0 masks on this scanline - if (REG_DISPCNT & DISPCNT_WIN0_ON) { - // acquire the window coordinates - - WIN0bottom = WIN_GET_HIGHER(REG_WIN0V); // y2; - WIN0top = WIN_GET_LOWER(REG_WIN0V); // y1; - WIN0right = WIN_GET_HIGHER(REG_WIN0H); // x2 - WIN0left = WIN_GET_LOWER(REG_WIN0H); // x1 - - // printf("%d, %d, %d, %d\n", WIN0bottom, WIN0top, WIN0right, WIN0left); - // figure out WIN Y wraparound and check bounds accordingly - if (WIN0top > WIN0bottom) { - if (vcount >= WIN0top || vcount < WIN0bottom) - WIN0enable = true; - } else { - if (vcount >= WIN0top && vcount < WIN0bottom) - WIN0enable = true; - } - - windowsEnabled = true; - } - // figure out if WIN1 masks on this scanline - if (REG_DISPCNT & DISPCNT_WIN1_ON) { - WIN1bottom = WIN_GET_HIGHER(REG_WIN1V); // y2; - WIN1top = WIN_GET_LOWER(REG_WIN1V); // y1; - WIN1right = WIN_GET_HIGHER(REG_WIN1H); // x2 - WIN1left = WIN_GET_LOWER(REG_WIN1H); // x1 - - if (WIN1top > WIN1bottom) { - if (vcount >= WIN1top || vcount < WIN1bottom) - WIN1enable = true; - } else { - if (vcount >= WIN1top && vcount < WIN1bottom) - WIN1enable = true; - } - - windowsEnabled = true; - } - // enable windows if OBJwin is enabled - if (REG_DISPCNT & DISPCNT_OBJWIN_ON && REG_DISPCNT & DISPCNT_OBJ_ON) { - windowsEnabled = true; - } - - // draw to pixel mask - if (windowsEnabled) { - for (xpos = 0; xpos < DISPLAY_WIDTH; xpos++) { - // win0 checks - if (WIN0enable && winCheckHorizontalBounds(WIN0left, WIN0right, xpos)) - scanline.winMask[xpos] = REG_WININ & 0x3F; - // win1 checks - else if (WIN1enable && winCheckHorizontalBounds(WIN1left, WIN1right, xpos)) - scanline.winMask[xpos] = (REG_WININ >> 8) & 0x3F; - else - scanline.winMask[xpos] = (REG_WINOUT & 0x3F) | WINMASK_WINOUT; - } - } - - if (REG_DISPCNT & DISPCNT_OBJ_ON) - DrawSprites(&scanline, vcount, windowsEnabled); - - // iterate trough every priority in order - for (prnum = 3; prnum >= 0; prnum--) { - for (char prsub = scanline.prioritySortedBgsCount[prnum] - 1; prsub >= 0; prsub--) { - char bgnum = scanline.prioritySortedBgs[prnum][prsub]; - // if background is enabled then draw it - if (isbgEnabled(bgnum)) { - uint16_t *src = scanline.layers[bgnum]; - // copy all pixels to framebuffer - for (xpos = 0; xpos < DISPLAY_WIDTH; xpos++) { - uint16_t color = src[xpos]; - bool winEffectEnable = true; - - if (!getAlphaBit(color)) - continue; // do nothing if alpha bit is not set - - if (windowsEnabled) { - winEffectEnable = ((scanline.winMask[xpos] & WINMASK_CLR) >> 5); - // if bg is disabled inside the window then do not draw the pixel - if (!(scanline.winMask[xpos] & 1 << bgnum)) - continue; - } - - // blending code - if (blendMode != 0 && REG_BLDCNT & (1 << bgnum) && winEffectEnable) { - uint16_t targetA = color; - uint16_t targetB = 0; - - switch (blendMode) { - case 1: { - char isSpriteBlendingEnabled = REG_BLDCNT & BLDCNT_TGT2_OBJ ? 1 : 0; - // find targetB and blend it - if (alphaBlendSelectTargetB(&scanline, &targetB, prnum, prsub + 1, xpos, isSpriteBlendingEnabled)) { - color = alphaBlendColor(targetA, targetB); - } - } break; - case 2: - color = alphaBrightnessIncrease(targetA); - break; - case 3: - color = alphaBrightnessDecrease(targetA); - break; - } - } - // write the pixel to scanline buffer output - pixels[xpos] = color; - } - } - } - // draw sprites on current priority - uint16_t *src = scanline.spriteLayers[prnum]; - for (xpos = 0; xpos < DISPLAY_WIDTH; xpos++) { - if (getAlphaBit(src[xpos])) { - // check if sprite pixel draws inside window - if (windowsEnabled && !(scanline.winMask[xpos] & WINMASK_OBJ)) - continue; - // draw the pixel - pixels[xpos] = src[xpos]; - } - } - } -} - -uint16_t *memsetu16(uint16_t *dst, uint16_t fill, size_t count) -{ - for (int i = 0; i < count; i++) { - *dst++ = fill; - } - - return 0; -} - -static void DrawFrame(uint16_t *pixels) -{ - int i; - int j; - - for (i = 0; i < DISPLAY_HEIGHT; i++) { - REG_VCOUNT = i; - if (((REG_DISPSTAT >> 8) & 0xFF) == REG_VCOUNT) { - REG_DISPSTAT |= INTR_FLAG_VCOUNT; - if (REG_DISPSTAT & DISPSTAT_VCOUNT_INTR) - gIntrTable[INTR_INDEX_VCOUNT](); - } - - unsigned int blendMode = (REG_BLDCNT >> 6) & 3; - uint16_t backdropColor = *(uint16_t *)PLTT; - if (REG_BLDCNT & BLDCNT_TGT1_BD) { - switch (blendMode) { - case 2: - backdropColor = alphaBrightnessIncrease(backdropColor); - break; - case 3: - backdropColor = alphaBrightnessDecrease(backdropColor); - break; - } - } - - // Render the backdrop color before the each individual scanline. - // HBlank interrupt code could have changed it inbetween lines. - memsetu16(&pixels[i * DISPLAY_WIDTH], backdropColor, DISPLAY_WIDTH); - DrawScanline(&pixels[i * DISPLAY_WIDTH], i); - - REG_DISPSTAT |= INTR_FLAG_HBLANK; - - RunDMAs(DMA_HBLANK); - - if (REG_DISPSTAT & DISPSTAT_HBLANK_INTR) - gIntrTable[INTR_INDEX_HBLANK](); - - REG_DISPSTAT &= ~INTR_FLAG_HBLANK; - REG_DISPSTAT &= ~INTR_FLAG_VCOUNT; - } -} - -#if ENABLE_VRAM_VIEW -void DrawVramView(Uint16 *buffer) -{ - for (int y = 0; y < VRAM_VIEW_HEIGHT / TILE_WIDTH; y++) { - for (int x = 0; x < VRAM_VIEW_WIDTH / TILE_WIDTH; x++) { - u16 tileId = y * (VRAM_VIEW_WIDTH / TILE_WIDTH) + x; - u16 *tileBase = &buffer[(y * VRAM_VIEW_WIDTH + x) * 8]; - - for (int ty = 0; ty < TILE_WIDTH; ty++) { - for (int tx = 0; tx < TILE_WIDTH; tx += 2) { - s32 tileIndex = ty * VRAM_VIEW_WIDTH + tx; - u16 *dest = &tileBase[tileIndex]; - - int i = (ty * TILE_WIDTH + tx) / 2; - u8 *colorPtr = &((u8 *)VRAM)[tileId * 0x20 + i]; - u8 colorId = colorPtr[0]; - u8 colA = (colorId & 0xF0) >> 4; - u8 colB = (colorId & 0x0F) >> 0; - - u8 paletteId = vramPalIdBuffer[tileId]; - dest[0] = PLTT[paletteId * 16 + colB]; - dest[1] = PLTT[paletteId * 16 + colA]; - } - } - } - } -} - -void VramDraw(SDL_Texture *texture) -{ - memset(vramBuffer, 0, sizeof(vramBuffer)); - DrawVramView(vramBuffer); - SDL_UpdateTexture(texture, NULL, vramBuffer, VRAM_VIEW_WIDTH * sizeof(Uint16)); -} -#endif - -void VDraw(SDL_Texture *texture) -{ - memset(gameImage, 0, sizeof(gameImage)); - DrawFrame(gameImage); - SDL_UpdateTexture(texture, NULL, gameImage, DISPLAY_WIDTH * sizeof(Uint16)); - REG_VCOUNT = 161; // prep for being in VBlank period -} - -int DoMain(void *data) -{ - printf("DO MAIN THREAD!\n"); - AgbMain(); - return 0; -} - -void VBlankIntrWait(void) -{ - bool frameAvailable = TRUE; - - while (isRunning) { - ProcessSDLEvents(); - - if (!paused || stepOneFrame) { - double dt = fixedTimestep / timeScale; // TODO: Fix speedup - double deltaTime = 0; - - curGameTime = SDL_GetPerformanceCounter(); - -#ifdef PS2 - deltaTime = dt; -#else - if (stepOneFrame) { - deltaTime = dt; - } else { - deltaTime = (double)((curGameTime - lastGameTime) / (double)SDL_GetPerformanceFrequency()); - if (deltaTime > (dt * 5)) - deltaTime = dt * 5; - } -#endif - - lastGameTime = curGameTime; - - accumulator += deltaTime; - - while (accumulator >= dt) { - if (frameAvailable) { - VDraw(sdlTexture); - frameAvailable = FALSE; - - REG_DISPSTAT |= INTR_FLAG_VBLANK; - - // TODO(Jace): I think this should be DMA_VBLANK. - // If not, and it is HBLANK instead, add a note here, why it is! - RunDMAs(DMA_VBLANK); - - if (REG_DISPSTAT & DISPSTAT_VBLANK_INTR) - gIntrTable[INTR_INDEX_VBLANK](); - REG_DISPSTAT &= ~INTR_FLAG_VBLANK; - accumulator -= dt; - } else { - REG_KEYINPUT = KEYS_MASK ^ Platform_GetKeyInput(); - accumulator -= dt; - // Get another frame; - return; - } - } - - if (paused && stepOneFrame) { - stepOneFrame = false; - } - } - - SDL_RenderClear(sdlRenderer); - SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); - -#if ENABLE_VRAM_VIEW - VramDraw(vramTexture); - SDL_RenderClear(vramRenderer); - SDL_RenderCopy(vramRenderer, vramTexture, NULL, NULL); -#endif - -#ifndef PS2 - if (videoScaleChanged) { - SDL_SetWindowSize(sdlWindow, DISPLAY_WIDTH * videoScale, DISPLAY_HEIGHT * videoScale); - videoScaleChanged = false; - } -#endif - SDL_RenderPresent(sdlRenderer); -#if ENABLE_VRAM_VIEW - SDL_RenderPresent(vramRenderer); -#endif - } - - CloseSaveFile(); - - SDL_DestroyWindow(sdlWindow); - SDL_Quit(); - exit(0); -} - -// while (isRunning) { -// ProcessSDLEvents(); -// REG_KEYINPUT = KEYS_MASK ^ Platform_GetKeyInput(); - -// if (!paused || stepOneFrame) { -// double dt = fixedTimestep / timeScale; // TODO: Fix speedup -// double deltaTime = 0; - -// curGameTime = SDL_GetPerformanceCounter(); -// #ifdef PS2 -// deltaTime = dt; -// #else -// if (stepOneFrame) { -// deltaTime = dt; -// } else { -// deltaTime = (double)((curGameTime - lastGameTime) / (double)SDL_GetPerformanceFrequency()); -// if (deltaTime > (dt * 5)) -// deltaTime = dt * 5; -// } -// #endif -// lastGameTime = curGameTime; -// accumulator += deltaTime; - -// while (accumulator >= dt) { -// if (frameAvailable) { -// VDraw(sdlTexture); -// frameAvailable = FALSE; - -// REG_DISPSTAT |= INTR_FLAG_VBLANK; - -// // TODO(Jace): I think this should be DMA_VBLANK. -// // If not, and it is HBLANK instead, add a note here, why it is! -// RunDMAs(DMA_VBLANK); - -// if (REG_DISPSTAT & DISPSTAT_VBLANK_INTR) -// gIntrTable[INTR_INDEX_VBLANK](); -// REG_DISPSTAT &= ~INTR_FLAG_VBLANK; - -// accumulator -= dt; -// } else { -// accumulator -= dt; -// // Get another frame -// return; -// } -// } - -// if (paused && stepOneFrame) { -// stepOneFrame = false; -// } -// } - -// SDL_RenderClear(sdlRenderer); -// SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); - -// #if ENABLE_VRAM_VIEW -// VramDraw(vramTexture); -// SDL_RenderClear(vramRenderer); -// SDL_RenderCopy(vramRenderer, vramTexture, NULL, NULL); -// #endif - -// #ifndef PS2 -// if (videoScaleChanged) { -// SDL_SetWindowSize(sdlWindow, DISPLAY_WIDTH * videoScale, DISPLAY_HEIGHT * videoScale); -// videoScaleChanged = false; -// } -// #endif -// SDL_RenderPresent(sdlRenderer); -// #if ENABLE_VRAM_VIEW -// SDL_RenderPresent(vramRenderer); -// #endif -// } - -// CloseSaveFile(); - -// SDL_DestroyWindow(sdlWindow); -// SDL_Quit(); -// exit(0); - -u8 BinToBcd(u8 bin) -{ - int placeCounter = 1; - u8 out = 0; - do { - out |= (bin % 10) * placeCounter; - placeCounter *= 16; - } while ((bin /= 10) > 0); - - return out; -} - -// Following functions taken from mGBA's source -u16 ArcTan(s16 i) -{ - s32 a = -((i * i) >> 14); - s32 b = ((0xA9 * a) >> 14) + 0x390; - b = ((b * a) >> 14) + 0x91C; - b = ((b * a) >> 14) + 0xFB6; - b = ((b * a) >> 14) + 0x16AA; - b = ((b * a) >> 14) + 0x2081; - b = ((b * a) >> 14) + 0x3651; - b = ((b * a) >> 14) + 0xA2F9; - - return (i * b) >> 16; -} - -u16 ArcTan2(s16 x, s16 y) -{ - if (!y) { - if (x >= 0) - return 0; - return 0x8000; - } - if (!x) { - if (y >= 0) - return 0x4000; - return 0xC000; - } - if (y >= 0) { - if (x >= 0) { - if (x >= y) - return ArcTan((y << 14) / x); - } else if (-x >= y) - return ArcTan((y << 14) / x) + 0x8000; - return 0x4000 - ArcTan((x << 14) / y); - } else { - if (x <= 0) { - if (-x > -y) - return ArcTan((y << 14) / x) + 0x8000; - } else if (x >= -y) - return ArcTan((y << 14) / x) + 0x10000; - return 0xC000 - ArcTan((x << 14) / y); - } -} - -u16 Sqrt(u32 num) -{ - if (!num) - return 0; - u32 lower; - u32 upper = num; - u32 bound = 1; - while (bound < upper) { - upper >>= 1; - bound <<= 1; - } - while (1) { - upper = num; - u32 accum = 0; - lower = bound; - while (1) { - u32 oldLower = lower; - if (lower <= upper >> 1) - lower <<= 1; - if (oldLower >= upper >> 1) - break; - } - while (1) { - accum <<= 1; - if (upper >= lower) { - ++accum; - upper -= lower; - } - if (lower == bound) - break; - lower >>= 1; - } - u32 oldBound = bound; - bound += accum; - bound >>= 1; - if (bound >= oldBound) { - bound = oldBound; - break; - } - } - return bound; -} diff --git a/src/platform/shared/audio/cgb_audio.c b/src/platform/shared/audio/cgb_audio.c index 662f13076..3f6ec93d5 100644 --- a/src/platform/shared/audio/cgb_audio.c +++ b/src/platform/shared/audio/cgb_audio.c @@ -103,7 +103,6 @@ void cgb_trigger_note(u8 channel) void cgb_audio_generate(u16 samplesPerFrame) { - return; #if !ENABLE_AUDIO return; #endif From 15318760ed4eef733cb25b317a3bcf951d3e03ba Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Tue, 10 Dec 2024 01:50:56 +0000 Subject: [PATCH 11/11] more progress, running on real hardware --- .devcontainer/Dockerfile | 2 +- .gitignore | 1 + Makefile | 48 ++++++++++++++++++---------- config.mk | 9 +++--- include/game/sa1_leftovers/player.h | 3 +- include/gba/defines.h | 4 +-- include/gba/io_reg.h | 2 +- ps2/ntsc/SYSTEM.CNF | 4 +++ src/game/game.c | 4 ++- src/game/stage/background/zone_7_2.c | 2 +- src/game/stage/collision.c | 5 +++ src/game/stage/player.c | 5 ++- src/platform/pret_sdl/sdl2.c | 38 ++++++++++++++++++++-- tools/mid2agb/agb.cpp | 1 + 14 files changed, 97 insertions(+), 31 deletions(-) create mode 100644 ps2/ntsc/SYSTEM.CNF diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 35b3b538d..af13f9dc6 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -8,7 +8,7 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ && apt-get -y install --no-install-recommends binutils-arm-none-eabi \ gcc-arm-none-eabi libpng-dev build-essential clang-format-13 xorg-dev \ libsdl2-dev gcc-mingw-w64 texinfo flex bison gettext libgsl-dev libgmp3-dev \ - libmpfr-dev libmpc-dev zlib1g-dev autopoint cmake automake patch + libmpfr-dev libmpc-dev zlib1g-dev autopoint cmake automake patch mkisofs WORKDIR /deps RUN git clone https://github.com/SAT-R/agbcc.git && cd agbcc && ./build.sh diff --git a/.gitignore b/.gitignore index 8ed183732..8038fb5ea 100644 --- a/.gitignore +++ b/.gitignore @@ -81,6 +81,7 @@ libagbsyscall/*.s *.exe *.dll *.sdl +*.iso # third party deps /ext diff --git a/Makefile b/Makefile index d4954279f..720a9bc13 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ else ifeq ($(CPU_ARCH),i386) else ifeq ($(PLATFORM),win32) PREFIX := i686-w64-mingw32- endif -else ifeq ($(CPU_ARCH),EE) +else ifeq ($(CPU_ARCH),MIPS) ifeq ($(PLATFORM),sdl_ps2) PREFIX := mips64r5900el-ps2-elf- else @@ -115,24 +115,24 @@ else CC1FLAGS += -Wno-parentheses-equality -Wno-unused-value CPPFLAGS += -D TITLE_BAR=$(BUILD_NAME).$(PLATFORM) -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 $(shell sdl2-config --cflags) else ifeq ($(PLATFORM),sdl_ps2) - CC1FLAGS += -Wno-parentheses-equality -Wno-unused-value - CC1FLAGS += -ffast-math + CC1FLAGS += -Wno-parentheses-equality -Wno-unused-value -ffast-math CPPFLAGS += -I$(PS2SDK)/common/include -I$(PS2SDK)/ee/include -I$(PS2SDK)/ports/include $(shell $(PS2SDK)/ports/bin/sdl2-config --cflags) - CPPFLAGS += -D TITLE_BAR=$(BUILD_NAME).$(PLATFORM) -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 -D_EE -DPS2 -D__PS2__ -Dmain=SDL_main + CPPFLAGS += -D TITLE_BAR=$(BUILD_NAME).$(PLATFORM) -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 -D_EE -DPS2 -D__PS2__ else ifeq ($(PLATFORM),sdl_win32) CPPFLAGS += -D TITLE_BAR=$(BUILD_NAME).$(PLATFORM) -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 $(SDL_MINGW_FLAGS) else ifeq ($(PLATFORM),win32) CPPFLAGS += -D TITLE_BAR=$(BUILD_NAME).$(PLATFORM) -D PLATFORM_GBA=0 -D PLATFORM_SDL=0 -D PLATFORM_WIN32=1 endif - ifeq ($(CPU_ARCH),i386) - CPPFLAGS += -D CPU_ARCH_X86=1 -D CPU_ARCH_ARM=0 - + ifeq ($(CPU_ARCH),i386) + CPPFLAGS += -D CPU_ARCH_X86=1 -D CPU_ARCH_ARM=0 -D CPU_ARCH_MIPS=0 # Use the more legible Intel dialect for x86, without underscores CC1FLAGS += -masm=intel - else - CPPFLAGS += -D CPU_ARCH_X86=0 -D CPU_ARCH_ARM=0 - endif + else ifeq ($(CPU_ARCH),MIPS) + CPPFLAGS += -D CPU_ARCH_X86=0 -D CPU_ARCH_ARM=0 -D CPU_ARCH_MIPS=1 + else + CPPFLAGS += -D CPU_ARCH_X86=0 -D CPU_ARCH_ARM=0 -D CPU_ARCH_MIPS=0 + endif endif ifeq ($(PLATFORM),gba) @@ -147,6 +147,9 @@ else # for modern we are using a modern compiler # so instead of CPP we can use gcc -E to "preprocess only" CPP := $(CC1) -E + else ifeq ($(PLATFORM), sdl_ps2) + # the linker complains if we don't set this + ASFLAGS += -msingle-float endif # Allow file input through stdin on modern GCC and set it to "compile only" CC1FLAGS += -x c -S @@ -236,6 +239,10 @@ else ifeq ($(PLATFORM),sdl) ROM := $(BUILD_NAME).sdl ELF := $(ROM).elf MAP := $(ROM).map +else ifeq ($(PLATFORM),sdl_ps2) +ROM := $(BUILD_NAME).$(PLATFORM).iso +ELF := $(ROM:.iso=.elf) +MAP := $(ROM:.iso=.map) else ROM := $(BUILD_NAME).$(PLATFORM).exe ELF := $(ROM:.exe=.elf) @@ -380,13 +387,17 @@ clean-tools: tidy: $(RM) $(ROM) $(ELF) $(MAP) - $(RM) $(BUILD_NAME)_europe.gba $(BUILD_NAME)_europe.elf $(BUILD_NAME)_europe.map - $(RM) $(BUILD_NAME)_japan.gba $(BUILD_NAME)_japan.elf $(BUILD_NAME)_japan.map - $(RM) -r build/* + $(RM) -r $(OBJ_DIR) +ifeq ($(PLATFORM), sdl_win32) $(RM) SDL2.dll -ifeq ($(PLATFORM), GBA) +else ifeq ($(PLATFORM), gba) +ifeq ($(GAME_REGION), USA) + $(MAKE) tidy GAME_REGION=JAPAN + $(MAKE) tidy GAME_REGION=EUROPE +endif $(MAKE) tidy PLATFORM=win32 CPU_ARCH=i386 $(MAKE) tidy PLATFORM=sdl_win32 CPU_ARCH=i386 + $(MAKE) tidy PLATFORM=sdl_ps2 CPU_ARCH=MIPS $(MAKE) tidy PLATFORM=sdl endif @@ -452,7 +463,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 ifeq ($(PLATFORM),sdl_ps2) - @cd $(OBJ_DIR) && $(CC1) $(OBJS_REL) -lSDL2main -lSDL2 $(shell $(PS2SDK)/ports/bin/sdl2-config --libs) $(LINKER_MAP_FLAGS) -T$(PS2SDK)/ee/startup/linkfile -L$(PS2SDK)/common/lib -L$(PS2SDK)/ee/lib -L$(PS2DEV)/gsKit/lib -Wl,-zmax-page-size=128 -o $(ROOT_DIR)/$@ + @cd $(OBJ_DIR) && $(CC1) $(OBJS_REL) -lSDL2 $(shell $(PS2SDK)/ports/bin/sdl2-config --libs) $(LINKER_MAP_FLAGS) -T$(PS2SDK)/ee/startup/linkfile -L$(PS2SDK)/common/lib -L$(PS2SDK)/ee/lib -L$(PS2DEV)/gsKit/lib -Wl,-zmax-page-size=128 -o $(ROOT_DIR)/$@ else @cd $(OBJ_DIR) && $(CC1) -mwin32 $(OBJS_REL) -L$(ROOT_DIR)/libagbsyscall -lagbsyscall -lkernel32 -o $(ROOT_DIR)/$@ -Xlinker -Map "$(ROOT_DIR)/$(MAP)" endif @@ -464,6 +475,11 @@ ifeq ($(PLATFORM),gba) $(FIX) $@ -p -t"$(TITLE)" -c$(GAME_CODE) -m$(MAKER_CODE) -r$(GAME_REVISION) --silent else ifeq ($(PLATFORM),sdl) cp $< $@ +else ifeq ($(PLATFORM),sdl_ps2) + @echo Creating $(ROM) from $(ELF) + @cp -r ps2/ntsc $(OBJ_DIR)/iso + @cp $< $(OBJ_DIR)/iso/$(PS2_GAME_CODE) + @mkisofs -o $(ROM) $(OBJ_DIR)/iso/ else $(OBJCOPY) -O pei-i386 $< $@ ifeq ($(CREATE_PDB),1) @@ -530,7 +546,7 @@ europe: ; @$(MAKE) GAME_REGION=EUROPE sdl: ; @$(MAKE) PLATFORM=sdl -sdl_ps2: ; @$(MAKE) CPU_ARCH=EE PLATFORM=sdl_ps2 +sdl_ps2: ; @$(MAKE) CPU_ARCH=MIPS PLATFORM=sdl_ps2 sdl_win32: SDL2.dll $(SDL_MINGW_LIB) @$(MAKE) PLATFORM=sdl_win32 CPU_ARCH=i386 diff --git a/config.mk b/config.mk index 80f86a8b8..77139afc0 100644 --- a/config.mk +++ b/config.mk @@ -18,7 +18,7 @@ ifeq ($(CPU_ARCH),arm) else ifeq ($(CPU_ARCH),i386) THUMB_SUPPORT ?= 0 MIDI_COMMENTS := "x86" -else ifeq ($(CPU_ARCH),EE) +else ifeq ($(CPU_ARCH),MIPS) THUMB_SUPPORT ?= 0 MIDI_COMMENTS := "x86" else @@ -62,9 +62,10 @@ DEBUG ?= 0 MAKER_CODE := 78 # Version -BUILD_NAME := sa2 -TITLE := SONICADVANC2 -GAME_CODE := A2N +BUILD_NAME := sa2 +TITLE := SONICADVANC2 +GAME_CODE := A2N +PS2_GAME_CODE := SLUS_054.02 # Revision diff --git a/include/game/sa1_leftovers/player.h b/include/game/sa1_leftovers/player.h index 4b0841e23..8ae877273 100644 --- a/include/game/sa1_leftovers/player.h +++ b/include/game/sa1_leftovers/player.h @@ -169,8 +169,7 @@ typedef struct Player_ { // Alternatively, some of the following data might be a union /* 0x94 */ PlayerSpriteInfo *unk94; /* 0x98 */ u8 unk98; // Multiplayer var. TODO: check sign! - /* 0x99 */ s8 unk99[15]; - /* 0xA8 */ u8 unkA8; + /* 0x99 */ s8 unk99[16]; /* 0x9A */ u8 fillerA9[0x3]; // Cream's framecounter for flying diff --git a/include/gba/defines.h b/include/gba/defines.h index 057138435..165ce41ed 100644 --- a/include/gba/defines.h +++ b/include/gba/defines.h @@ -37,8 +37,8 @@ #define OAM_ENTRY_COUNT 128 #if PORTABLE // NOTE: Used in gba/types.h, so they have to be defined before the #include -#define DISPLAY_WIDTH 426 -#define DISPLAY_HEIGHT 240 +#define DISPLAY_WIDTH 240 +#define DISPLAY_HEIGHT 160 //#include "gba/types.h" // TODO: Fix #define OAM_SIZE (OAM_ENTRY_COUNT*sizeof(OamData)) diff --git a/include/gba/io_reg.h b/include/gba/io_reg.h index befa1dec9..f694c78b5 100644 --- a/include/gba/io_reg.h +++ b/include/gba/io_reg.h @@ -3,7 +3,7 @@ #include -#define IO_SIZE 0x800 +#define IO_SIZE 0x400 #if PLATFORM_GBA // I/O register base address #define REG_BASE 0x4000000 diff --git a/ps2/ntsc/SYSTEM.CNF b/ps2/ntsc/SYSTEM.CNF new file mode 100644 index 000000000..d5c3d9821 --- /dev/null +++ b/ps2/ntsc/SYSTEM.CNF @@ -0,0 +1,4 @@ +BOOT2 = cdrom0:\SLUS_054.02;1 +VER = 1.00 +VMODE = NTSC + diff --git a/src/game/game.c b/src/game/game.c index fa0bfd94c..40edfa286 100644 --- a/src/game/game.c +++ b/src/game/game.c @@ -97,7 +97,9 @@ void GameStart(void) // GameStageStart(); #elif ENABLE_DECOMP_CREDITS - CreateDecompCreditsScreen(hasProfile); + gCurrentLevel = LEVEL_INDEX(ZONE_2, ACT_1); + ApplyGameStageSettings(); + GameStageStart(); #else if (gFlags & FLAGS_NO_FLASH_MEMORY) { CreateTitleScreen(); diff --git a/src/game/stage/background/zone_7_2.c b/src/game/stage/background/zone_7_2.c index 34c6ce8fc..84d858068 100644 --- a/src/game/stage/background/zone_7_2.c +++ b/src/game/stage/background/zone_7_2.c @@ -37,6 +37,6 @@ NONMATCH("asm/non_matching/game/stage/background/StageBgUpdate_Zone7Acts12.inc", Zone7BgUpdate_Outside(x, y); } - gPlayer.unkA8 = bgId; + gPlayer.unk99[15] = bgId; } END_NONMATCH diff --git a/src/game/stage/collision.c b/src/game/stage/collision.c index 13a098e34..7b8a2905d 100644 --- a/src/game/stage/collision.c +++ b/src/game/stage/collision.c @@ -618,6 +618,11 @@ s32 sub_801ED24(s32 p0, s32 p1, s32 p2, u8 *p3) // (100.00%) https://decomp.me/scratch/sJY4g s32 sub_801EE64(s32 p0in, s32 p1in, s32 p2in, u8 *p3in) { +#ifdef BUG_FIX + if (!gRefCollision) { + return 0; + } +#endif #ifndef NON_MATCHING register u32 r0 asm("r0"); register u32 r1 asm("r1"); diff --git a/src/game/stage/player.c b/src/game/stage/player.c index 7e61cc537..177d189c3 100644 --- a/src/game/stage/player.c +++ b/src/game/stage/player.c @@ -763,7 +763,7 @@ NONMATCH("asm/non_matching/game/InitializePlayer.inc", void InitializePlayer(Pla sub_8015750(); sub_801561C(); sub_802989C(p); - +#ifndef NON_MATCHING { // This smells like a memset macro. // Nonmatching reg-alloc between r4 & r6 here u32 *u99 = (void *)p->unk99; @@ -773,6 +773,9 @@ NONMATCH("asm/non_matching/game/InitializePlayer.inc", void InitializePlayer(Pla *u99++ = 0; } } +#else + memset(p->unk99, 0, sizeof(p->unk99)); +#endif p->unk99[0] = 0x7F; diff --git a/src/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index 0a07fb7a0..990613270 100644 --- a/src/platform/pret_sdl/sdl2.c +++ b/src/platform/pret_sdl/sdl2.c @@ -9,8 +9,11 @@ #include #endif +#ifdef PS2 +#define SDL_MAIN_HANDLED +#endif + #include -#include #include "global.h" #include "core.h" @@ -138,8 +141,39 @@ void *Platform_malloc(int numBytes) { return HeapAlloc(GetProcessHeap(), HEAP_GE void Platform_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); } #endif +#ifdef PS2 +// TODO: clean these for what is needed +#include +#include +#include + +#include +#include +#include +#include +#include + +__attribute__((weak)) void reset_IOP(void) +{ + SifInitRpc(0); + while (!SifIopReset(NULL, 0)) { } + while (!SifIopSync()) { } +} + +static void prepare_IOP(void) +{ + reset_IOP(); + SifInitRpc(0); + sbv_patch_enable_lmb(); +} +#endif + int main(int argc, char **argv) { +#if PS2 + prepare_IOP(); +#endif + // Open an output console on Windows #ifdef _WIN32 AllocConsole(); @@ -259,7 +293,7 @@ int main(int argc, char **argv) #endif // Prevent the multiplayer screen from being drawn ( see core.c:GameInit() ) REG_RCNT = 0x8000; - REG_KEYINPUT = 0x3FF; + REG_KEYINPUT = KEYS_MASK; AgbMain(); diff --git a/tools/mid2agb/agb.cpp b/tools/mid2agb/agb.cpp index a92807093..dddd96d0b 100644 --- a/tools/mid2agb/agb.cpp +++ b/tools/mid2agb/agb.cpp @@ -564,5 +564,6 @@ void PrintAgbFooter() for (int i = 1; i <= trackCount; i++) std::fprintf(g_outputFile, "\tmPtr\t%s_%u\n", g_asmLabel.c_str(), i); + // TODO: is this needed? std::fprintf(g_outputFile, "\n\t.end\n"); }