diff --git a/main.c b/main.c index 2260859..995e891 100644 --- a/main.c +++ b/main.c @@ -1,5 +1,4 @@ #define SDL_MAIN_USE_CALLBACKS 1 -#include "SDL3/SDL_atomic.h" #include "SDL3/SDL_blendmode.h" #include "SDL3/SDL_camera.h" #include "SDL3/SDL_dialog.h" @@ -20,6 +19,7 @@ #include "mgba/core/core.h" #include "mgba/core/interface.h" #include "mgba/feature/commandline.h" +#include "mgba/internal/gb/video.h" #include #include @@ -39,6 +39,12 @@ static SDL_Surface* scaled = NULL; static SDL_Surface* filtered[NUM_CHANNELS] = { NULL, NULL, NULL }; +enum DialogState { + DIALOG_NEVER = 0, + DIALOG_OPENED, + DIALOG_CLOSED, +}; + struct AppState { SDL_Camera* camera; SDL_Window* window; @@ -54,6 +60,9 @@ struct AppState { bool texture_updated; SDL_Texture* textures[NUM_CHANNELS]; SDL_Surface* screens[NUM_CHANNELS]; + + enum DialogState dialog_state; + struct mArguments args; struct mCore* cores[NUM_CHANNELS]; /* GB button presses fed to mgba */ @@ -84,12 +93,12 @@ enum mColorFormat pixfmt_sdl_to_mgba(uint32_t sdl_fmt) { const SDL_DialogFileFilter DIALOG_FILENAME_FILTER[1] = {{ "Gameboy Camera ROM", "gb" }}; static void SDLCALL dialog_callback(void* userdata, const char* const* files, int filter) { + struct AppState* st = (struct AppState*)userdata; if (files && *files) { SDL_Log("\nSelected: %s", *files); - SDL_SetAtomicPointer((void**)userdata, strdup(*files)); - } else { - exit(1); + st->args.fname = strdup(*files); } + st->dialog_state = DIALOG_CLOSED; } void myStartRequestImageRed(struct mImageSource* self, unsigned w, unsigned h, int colorFormats) { @@ -270,12 +279,6 @@ bool SelectCamera(struct AppState* st) { } SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) { - int i; - unsigned w, h; - - struct mArguments args; - bool parsed = mArgumentsParse(&args, argc, argv, NULL, 0); - struct AppState* st = malloc(sizeof(struct AppState)); memset(st, 0, sizeof(struct AppState)); *appstate = st; @@ -283,21 +286,13 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) { /* Enable standard application logging */ SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); + bool parsed = mArgumentsParse(&st->args, argc, argv, NULL, 0); + if (!parsed) { SDL_Log("Couldn't parse arguments"); return SDL_APP_FAILURE; } - if (!args.fname) { - SDL_ShowOpenFileDialog(dialog_callback, &args.fname, NULL, DIALOG_FILENAME_FILTER, 1, NULL, false); - printf("Must provide a Gameboy Camera ROM"); - do { - putchar('.'); - fflush(stdout); - SDL_Delay(1000); - } while (!SDL_GetAtomicPointer((void**)&args.fname)); - } - gb_img_src[0].requestImage = myRequestImageRed; gb_img_src[0].startRequestImage = myStartRequestImageRed; gb_img_src[0].stopRequestImage = myStopRequestImageRed; @@ -308,40 +303,12 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) { gb_img_src[2].startRequestImage = myStartRequestImageBlue; gb_img_src[2].stopRequestImage = myStopRequestImageBlue; - for (i = 0; i < NUM_CHANNELS; i++) { - struct mCore* core = mCoreFind(args.fname); - if (!core || !core->init(core)) { - SDL_Log("Couldn't initialize mgba core!"); - return SDL_APP_FAILURE; - } - - if (!mCoreLoadFile(core, args.fname)) { - SDL_Log("Failed to load ROM"); - return SDL_APP_FAILURE; - } - - mCoreConfigInit(&core->config, NULL); - /*mCoreConfigLoad(&core->config);*/ - - mArgumentsApply(&args, NULL, 0, &core->config); - mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "detect"); - mCoreConfigSetDefaultValue(&core->config, "frameskip", "4"); - mCoreConfigSetDefaultValue(&core->config, "sgb.borders", "0"); - - mCoreLoadConfig(core); - - st->cores[i] = core; - } - - /* without loss of generality */ - st->cores[0]->desiredVideoDimensions(st->cores[0], &w, &h); - if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_CAMERA)) { SDL_Log("Couldn't initialize SDL3: %s", SDL_GetError()); return SDL_APP_FAILURE; } - st->window = SDL_CreateWindow("cgbwebcam", w, h, SDL_WINDOW_RESIZABLE); + st->window = SDL_CreateWindow("cgbwebcam", GB_VIDEO_HORIZONTAL_PIXELS, GB_VIDEO_VERTICAL_PIXELS, SDL_WINDOW_RESIZABLE); if (!st->window) { SDL_Log("Couldn't create window: %s", SDL_GetError()); return SDL_APP_FAILURE; @@ -355,58 +322,6 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) { SDL_SetLogPriorities(SDL_LOG_PRIORITY_VERBOSE); - for (i = 0; i < NUM_CHANNELS; i++) { - int j; - struct mCore* core = st->cores[i]; - SDL_Texture* texture; - SDL_Surface* screen = SDL_CreateSurface(w, h, SCREEN_FMT); - - core->setVideoBuffer(core, screen->pixels, screen->pitch / BYTES_PER_PIXEL); - st->screens[i] = screen; - - /* Create texture with appropriate format */ - texture = SDL_CreateTextureFromSurface(st->renderer, st->screens[0]); - if (!texture) { - SDL_Log("Couldn't create texture: %s", SDL_GetError()); - return SDL_APP_FAILURE; - } - SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_ADD); - st->textures[i] = texture; - - core->setPeripheral(core, mPERIPH_IMAGE_SOURCE, &gb_img_src[i]); - - core->reset(core); - - core->setKeys(core, 0); - for (j = 0; j < 600; j++) { - core->runFrame(core); - } - core->setKeys(core, 1); /* title screen */ - core->runFrame(core); - core->setKeys(core, 0); - for (j = 0; j < 25; j++) { - core->runFrame(core); - } - core->setKeys(core, 1); /* select 'shoot' */ - core->runFrame(core); - core->setKeys(core, 0); - for (j = 0; j < 75; j++) { - core->runFrame(core); - } - core->setKeys(core, 1); /* select 'shoot' again */ - core->runFrame(core); - core->setKeys(core, 0); - for (j = 0; j < 100; j++) { - core->runFrame(core); - } - - SDL_Log("prepared core %d", i); - } - - SDL_SetTextureColorMod(st->textures[0], 255, 0, 0); - SDL_SetTextureColorMod(st->textures[1], 0, 255, 0); - SDL_SetTextureColorMod(st->textures[2], 0, 0, 255); - return SDL_APP_CONTINUE; /* start the main app loop. */ } @@ -558,6 +473,111 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) { SDL_AppResult SDL_AppIterate(void* appstate) { struct AppState* st = (struct AppState*)appstate; + if (!st->cores[0]) { + unsigned w, h; + int i; + + if (!st->args.fname) { + switch (st->dialog_state) { + case DIALOG_NEVER: + SDL_Log("Select your Gameboy Camera ROM dump..."); + st->dialog_state = DIALOG_OPENED; + SDL_ShowOpenFileDialog(dialog_callback, st, st->window, DIALOG_FILENAME_FILTER, 1, NULL, false); + return SDL_APP_CONTINUE; + case DIALOG_OPENED: + SDL_Delay(100); + return SDL_APP_CONTINUE; + case DIALOG_CLOSED: + SDL_Log("Must provide a Gameboy Camera ROM"); + return SDL_APP_FAILURE; + default: + SDL_Log("Invalid dialog state"); + return SDL_APP_FAILURE; + } + } + + for (i = 0; i < NUM_CHANNELS; i++) { + struct mCore* core = mCoreFind(st->args.fname); + if (!core || !core->init(core)) { + SDL_Log("Couldn't initialize mgba core!"); + return SDL_APP_FAILURE; + } + + if (!mCoreLoadFile(core, st->args.fname)) { + SDL_Log("Failed to load ROM"); + return SDL_APP_FAILURE; + } + + mCoreConfigInit(&core->config, NULL); + /*mCoreConfigLoad(&core->config);*/ + + mArgumentsApply(&st->args, NULL, 0, &core->config); + mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "detect"); + mCoreConfigSetDefaultValue(&core->config, "frameskip", "4"); + mCoreConfigSetDefaultValue(&core->config, "sgb.borders", "0"); + + mCoreLoadConfig(core); + + st->cores[i] = core; + } + + /* without loss of generality */ + st->cores[0]->desiredVideoDimensions(st->cores[0], &w, &h); + SDL_SetWindowSize(st->window, w, h); + + for (i = 0; i < NUM_CHANNELS; i++) { + int j; + struct mCore* core = st->cores[i]; + SDL_Texture* texture; + SDL_Surface* screen = SDL_CreateSurface(w, h, SCREEN_FMT); + + core->setVideoBuffer(core, screen->pixels, screen->pitch / BYTES_PER_PIXEL); + st->screens[i] = screen; + + /* Create texture with appropriate format */ + texture = SDL_CreateTextureFromSurface(st->renderer, st->screens[0]); + if (!texture) { + SDL_Log("Couldn't create texture: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_ADD); + st->textures[i] = texture; + + core->setPeripheral(core, mPERIPH_IMAGE_SOURCE, &gb_img_src[i]); + + core->reset(core); + + core->setKeys(core, 0); + for (j = 0; j < 600; j++) { + core->runFrame(core); + } + core->setKeys(core, 1); /* title screen */ + core->runFrame(core); + core->setKeys(core, 0); + for (j = 0; j < 25; j++) { + core->runFrame(core); + } + core->setKeys(core, 1); /* select 'shoot' */ + core->runFrame(core); + core->setKeys(core, 0); + for (j = 0; j < 75; j++) { + core->runFrame(core); + } + core->setKeys(core, 1); /* select 'shoot' again */ + core->runFrame(core); + core->setKeys(core, 0); + for (j = 0; j < 100; j++) { + core->runFrame(core); + } + + SDL_Log("prepared core %d", i); + } + + SDL_SetTextureColorMod(st->textures[0], 255, 0, 0); + SDL_SetTextureColorMod(st->textures[1], 0, 255, 0); + SDL_SetTextureColorMod(st->textures[2], 0, 0, 255); + } + if (st->camera == NULL) { if (!SelectCamera(st)) { SDL_Log("Failed to show camera device menu: %s", SDL_GetError());