diff --git a/audio.c b/audio.c index 169886e..4d9bd21 100644 --- a/audio.c +++ b/audio.c @@ -37,6 +37,10 @@ int audioInit(AudioContext *aud) { return 0; } +void audioDestroy(AudioContext *aud) { + SDL_CloseAudioDevice(aud->id); +} + int audioUpdate(AudioContext *aud, void *data, uint32_t bytes) { int filled; if (!aud->id) return -1; diff --git a/audio.h b/audio.h index 644724f..05c0df8 100644 --- a/audio.h +++ b/audio.h @@ -13,6 +13,7 @@ typedef struct { } AudioContext; int audioInit(AudioContext *aud); +void audioDestroy(AudioContext *aud); int audioUpdate(AudioContext *aud, void *data, uint32_t bytes); #endif \ No newline at end of file diff --git a/emulation.c b/emulation.c new file mode 100644 index 0000000..e0daae1 --- /dev/null +++ b/emulation.c @@ -0,0 +1,61 @@ +#include "emulation.h" +#include + +static int onFrame(VB *sim) { + SimContext *ctx = vbGetUserData(sim); + ctx->hasFrame = true; + return 1; +} + +int emuInit(EmulationContext *emu) { + emu->sim = malloc(vbSizeOf()); + vbInit(emu->sim); + + emu->ctx = malloc(sizeof(SimContext)); + vbSetUserData(emu->sim, emu->ctx); + vbSetFrameCallback(emu->sim, &onFrame); + + return 0; +} + +void emuDestroy(EmulationContext *emu) { + uint8_t *rom = vbGetCartROM(emu->sim, NULL); + SimContext *ctx = vbGetUserData(emu->sim); + + if (rom) free(rom); + if (ctx) free(ctx); + free(emu->sim); +} + +void emuLoadGame(EmulationContext *emu, uint8_t *rom, uint32_t romSize) { + vbSetCartROM(emu->sim, rom, romSize); +} + +#define MAX_STEP_CLOCKS 20000000 +void emuTick(EmulationContext *emu) { + uint32_t clocks = MAX_STEP_CLOCKS; + vbEmulate(emu->sim, &clocks); +} + +bool emuReadPixels(EmulationContext *emu, uint8_t *left, uint8_t *right) { + if (!emu->ctx->hasFrame) { + return false; + } + emu->ctx->hasFrame = false; + vbGetPixels(emu->sim, left, 1, 384, right, 1, 384); + return true; +} + +void emuReadSamples(EmulationContext *emu, void **data, uint32_t *bytes) { + uint32_t samplePairs; + + *data = vbGetSamples(emu->sim, NULL, &samplePairs); + *bytes = samplePairs * 4; + emu->ctx->currentSample += 1; + emu->ctx->currentSample %= 2; + vbSetSamples(emu->sim, emu->ctx->samples[emu->ctx->currentSample], 834); +} + +void emuSetKeys(EmulationContext *emu, uint16_t keys) { + vbSetKeys(emu->sim, keys); +} \ No newline at end of file diff --git a/emulation.h b/emulation.h new file mode 100644 index 0000000..da6e849 --- /dev/null +++ b/emulation.h @@ -0,0 +1,28 @@ +#ifndef SHROOMS_VB_NATIVE_EMULATION_ +#define SHROOMS_VB_NATIVE_EMULATION_ + +#include "shrooms-vb-core/core/vb.h" +#include +#include + +typedef struct SimContext { + bool hasFrame; + uint32_t samples[2][834]; + uint32_t currentSample; +} SimContext; + +typedef struct EmulationContext { + VB *sim; + SimContext *ctx; +} EmulationContext; + +int emuInit(EmulationContext *emu); +void emuDestroy(EmulationContext *emu); +void emuLoadGame(EmulationContext *emu, uint8_t *rom, uint32_t romSize); + +void emuTick(EmulationContext *emu); +bool emuReadPixels(EmulationContext *emu, uint8_t *left, uint8_t *right); +void emuReadSamples(EmulationContext *emu, void **data, uint32_t *bytes); +void emuSetKeys(EmulationContext *emu, uint16_t keys); + +#endif \ No newline at end of file diff --git a/game.c b/game.c deleted file mode 100644 index d0d95c9..0000000 --- a/game.c +++ /dev/null @@ -1,72 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -typedef struct { - GraphicsContext *gfx; - AudioContext aud; - int16_t audioBuffer[834 * 2]; -} GameState; - -int onFrame(VB *sim) { - static uint8_t leftEye[384*224]; - static uint8_t rightEye[384*224]; - GameState *state; - void *samples; - uint32_t samplePairs; - - state = vbGetUserData(sim); - - vbGetPixels(sim, leftEye, 1, 384, rightEye, 1, 384); - gfxUpdateEyes(state->gfx, leftEye, rightEye); - - samples = vbGetSamples(sim, NULL, &samplePairs); - audioUpdate(&state->aud, samples, samplePairs * 4); - vbSetSamples(sim, samples, 834); - gfxRender(state->gfx); - return 1; -} - -#define MAX_STEP_CLOCKS 20000000 - -int runGame(VB *sim, GraphicsContext *gfx) { - uint32_t clocks; - SDL_Event event; - GameState state; - ControllerState ctrl; - - state.gfx = gfx; - audioInit(&state.aud); - vbSetSamples(sim, &state.audioBuffer, 834); - vbSetUserData(sim, &state); - vbSetFrameCallback(sim, &onFrame); - - ctrlInit(&ctrl); - - gfxUpdateEyes(gfx, LEFT_EYE_DEFAULT, RIGHT_EYE_DEFAULT); - - while (1) { - clocks = MAX_STEP_CLOCKS; - vbEmulate(sim, &clocks); - - gfxMenuInputBegin(gfx); - while (SDL_PollEvent(&event)) { - if (event.type == SDL_QUIT) { - return 0; - } - if (event.type == SDL_KEYDOWN) { - ctrlKeyDown(&ctrl, event.key.keysym.sym); - } - if (event.type == SDL_KEYUP) { - ctrlKeyUp(&ctrl, event.key.keysym.sym); - } - gfxMenuHandleEvent(gfx, &event); - } - gfxMenuInputEnd(gfx); - vbSetKeys(sim, ctrlKeys(&ctrl)); - } -} diff --git a/game.h b/game.h deleted file mode 100644 index 9984eea..0000000 --- a/game.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef SHROOMS_VB_NATIVE_GAME_ -#define SHROOMS_VB_NATIVE_GAME_ - -#include "graphics.h" -#include "shrooms-vb-core/core/vb.h" - -int runGame(VB *sim, GraphicsContext *gfx); - -#endif \ No newline at end of file diff --git a/graphics.h b/graphics.h deleted file mode 100644 index cae568b..0000000 --- a/graphics.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef SHROOMS_VB_NATIVE_GRAPHICS_ -#define SHROOMS_VB_NATIVE_GRAPHICS_ - -#include -#include - -typedef struct { - SDL_Window *window; - SDL_Renderer *renderer; - SDL_Texture *leftEye; - SDL_Texture *rightEye; - struct nk_context *nk; - struct nk_font *font; -} GraphicsContext; - -int gfxInit(GraphicsContext *gfx); -void gfxDestroy(GraphicsContext *gfx); - -void gfxUpdateEyes(GraphicsContext *gfx, const uint8_t *left, const uint8_t *right); - -void gfxMenuInputBegin(GraphicsContext *gfx); -void gfxMenuHandleEvent(GraphicsContext *gfx, SDL_Event *event); -void gfxMenuInputEnd(GraphicsContext *gfx); - -void gfxRender(GraphicsContext *gfx); - -#endif diff --git a/main.c b/main.c index 0daf528..d09d7d6 100644 --- a/main.c +++ b/main.c @@ -1,73 +1,16 @@ -#include -#include -#include +#include "cli.h" #include -#include "shrooms-vb-core/core/vb.h" #include - -uint8_t *readROM(char *filename, uint32_t *size) { - FILE *file = fopen(filename, "rb"); - uint8_t *rom; - long filesize; - - if (!file) { - perror("could not open file"); - return NULL; - } - - if (fseek(file, 0, SEEK_END)) { - perror("could not seek file end"); - return NULL; - } - filesize = ftell(file); - if (filesize == -1) { - perror("could not read file size"); - return NULL; - } - if (fseek(file, 0, SEEK_SET)) { - perror("could not seek file start"); - return NULL; - } - - *size = (uint32_t) filesize; - rom = malloc(*size); - if (!rom) { - perror("could not allocate ROM"); - return NULL; - } - fread(rom, 1, *size, file); - if (ferror(file)) { - perror("could not read file"); - return NULL; - } - if (fclose(file)) { - perror("could not close file"); - return NULL; - } - - return rom; -} +#include "ui.h" int main(int argc, char **argv) { - VB *sim; - uint8_t *rom; - uint32_t romSize; - GraphicsContext gfx; CLIArgs args; + UIContext *ui; int status; if (parseCLIArgs(argc, argv, &args)) { return 1; } - - rom = readROM(args.filename, &romSize); - if (!rom) { - return 1; - } - - sim = malloc(vbSizeOf()); - vbInit(sim); - vbSetCartROM(sim, rom, romSize); SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "0"); if (SDL_Init(SDL_INIT_EVERYTHING)) { @@ -75,12 +18,18 @@ int main(int argc, char **argv) { return 1; } - if (gfxInit(&gfx)) { + ui = uiInit(); + if (!ui) { SDL_Quit(); return 1; } - status = runGame(sim, &gfx); + if (args.filename) { + uiLoadGame(ui, args.filename); + } + + status = uiRun(ui); + uiDestroy(ui); SDL_Quit(); return status; } diff --git a/ui.c b/ui.c new file mode 100644 index 0000000..f60acf6 --- /dev/null +++ b/ui.c @@ -0,0 +1,169 @@ +#include "audio.h" +#include "controller.h" +#include "emulation.h" +#include +#include +#include "ui.h" +#include "window.h" + +struct UIContext { + EmulationContext emu; + WindowContext win; + AudioContext aud; + ControllerState ctrl; +}; + +UIContext *uiInit() { + UIContext *ui = malloc(sizeof(UIContext)); + if (emuInit(&ui->emu)) { + goto destroy_ui; + } + if (windowInit(&ui->win, "Shrooms VB")) { + goto destroy_emu; + } + if (audioInit(&ui->aud)) { + goto destroy_window; + } + ctrlInit(&ui->ctrl); + return ui; + +destroy_window: + windowDestroy(&ui->win); +destroy_emu: + emuDestroy(&ui->emu); +destroy_ui: + free(ui); + return NULL; +} + +void uiDestroy(UIContext *ui) { + audioDestroy(&ui->aud); + windowDestroy(&ui->win); + emuDestroy(&ui->emu); + free(ui); +} + +int uiLoadGame(UIContext *ui, const char *path) { + FILE *file = fopen(path, "rb"); + uint8_t *rom; + long fileSize; + uint32_t romSize; + + if (!file) { + perror("could not open file"); + return -1; + } + + if (fseek(file, 0, SEEK_END)) { + perror("could not seek file end"); + return -1; + } + fileSize = ftell(file); + if (fileSize == -1) { + perror("could not read file size"); + return -1; + } + if (fseek(file, 0, SEEK_SET)) { + perror("could not seek file start"); + return -1; + } + romSize = (uint32_t) fileSize; + + rom = malloc(romSize); + if (!rom) { + perror("could not allocate ROM"); + return -1; + } + fread(rom, 1, romSize, file); + if (ferror(file)) { + perror("could not read file"); + return -1; + } + if (fclose(file)) { + perror("could not close file"); + return -1; + } + + emuLoadGame(&ui->emu, rom, romSize); + return 0; +} + +static const char *MENU_ITEMS[3] = { + "File", + "Emulation", + NULL +}; + +int uiRun(UIContext *ui) { + static uint8_t leftEye[384*224]; + static uint8_t rightEye[384*224]; + + while (1) { + struct nk_context *ctx; + SDL_Event event; + void *samples; + uint32_t bytes; + ctx = ui->win.nk; + + emuTick(&ui->emu); + + if (emuReadPixels(&ui->emu, leftEye, rightEye)) { + windowUpdate(&ui->win, leftEye, rightEye); + } + emuReadSamples(&ui->emu, &samples, &bytes); + if (bytes) { + audioUpdate(&ui->aud, samples, bytes); + } + + windowDisplayBegin(&ui->win); + /* GUI */ + if (windowGuiBegin(&ui->win, "Shrooms VB")) { + windowMenubarBegin(&ui->win, MENU_ITEMS); + + if (nk_menu_begin_label(ctx, "File", NK_TEXT_ALIGN_CENTERED, nk_vec2(120, windowGetScreenHeight(&ui->win)))) { + nk_layout_row_dynamic(ctx, MENU_HEIGHT + 2, 1); + if (nk_menu_item_label(ctx, "Open ROM", NK_TEXT_ALIGN_LEFT)) { + printf("Open ROM\n"); + } + if (nk_menu_item_label(ctx, "Quit", NK_TEXT_ALIGN_LEFT)) { + SDL_Event QuitEvent; + QuitEvent.type = SDL_QUIT; + QuitEvent.quit.timestamp = SDL_GetTicks(); + SDL_PushEvent(&QuitEvent); + } + nk_menu_end(ctx); + } + + if (nk_menu_begin_label(ctx, "Emulation", NK_TEXT_ALIGN_CENTERED, nk_vec2(120, windowGetScreenHeight(&ui->win)))) { + nk_layout_row_dynamic(ctx, MENU_HEIGHT + 2, 1); + if (nk_menu_item_label(ctx, "Pause", NK_TEXT_ALIGN_LEFT)) { + printf("Pause\n"); + } + if (nk_menu_item_label(ctx, "Reset", NK_TEXT_ALIGN_LEFT)) { + printf("Reset\n"); + } + nk_menu_end(ctx); + } + + windowMenubarEnd(&ui->win); + } + windowGuiEnd(&ui->win); + windowDisplayEnd(&ui->win); + + nk_input_begin(ctx); + while (SDL_PollEvent(&event)) { + nk_sdl_handle_event(&event); + if (event.type == SDL_QUIT) { + return 0; + } + if (event.type == SDL_KEYDOWN) { + ctrlKeyDown(&ui->ctrl, event.key.keysym.sym); + } + if (event.type == SDL_KEYUP) { + ctrlKeyUp(&ui->ctrl, event.key.keysym.sym); + } + } + nk_input_end(ctx); + emuSetKeys(&ui->emu, ctrlKeys(&ui->ctrl)); + } +} \ No newline at end of file diff --git a/ui.h b/ui.h new file mode 100644 index 0000000..145f630 --- /dev/null +++ b/ui.h @@ -0,0 +1,11 @@ +#ifndef SHROOMS_VB_NATIVE_UI_ +#define SHROOMS_VB_NATIVE_UI_ + +typedef struct UIContext UIContext; + +UIContext *uiInit(); +void uiDestroy(UIContext *ui); +int uiLoadGame(UIContext *ui, const char *path); +int uiRun(UIContext *ui); + +#endif diff --git a/graphics.c b/window.c similarity index 53% rename from graphics.c rename to window.c index 616eede..4ec8d61 100644 --- a/graphics.c +++ b/window.c @@ -1,9 +1,8 @@ -#include -#include +#include "nuklear.h" +#include "window.h" #define SCREEN_WIDTH 384 #define SCREEN_HEIGHT 224 -#define MENU_HEIGHT 20 #define WINDOW_WIDTH SCREEN_WIDTH #define WINDOW_HEIGHT (SCREEN_HEIGHT + MENU_HEIGHT) @@ -57,6 +56,86 @@ static void applyStyles(struct nk_context *ctx) { ctx->style.contextual_button.padding = nk_vec2(20, 4); } +int windowInit(WindowContext *win, const char *title) { + float fontScale; + + win->window = SDL_CreateWindow(title, + SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI); + if (!win->window) { + fprintf(stderr, "Error creating window: %s\n", SDL_GetError()); + return -1; + } + + win->renderer = SDL_CreateRenderer(win->window, -1, 0); + if (!win->renderer) { + fprintf(stderr, "Error creating renderer: %s\n", SDL_GetError()); + goto cleanup_window; + } + + win->leftEye = SDL_CreateTexture(win->renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, 384, 224); + if (!win->leftEye) { + fprintf(stderr, "Error creating left eye texture: %s\n", SDL_GetError()); + goto cleanup_renderer; + } + SDL_SetTextureColorMod(win->leftEye, 0xff, 0, 0); + + win->rightEye = SDL_CreateTexture(win->renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, 384, 224); + if (!win->rightEye) { + fprintf(stderr, "Error creating right eye texture: %s\n", SDL_GetError()); + goto cleanup_left_eye; + } + SDL_SetTextureColorMod(win->rightEye, 0, 0xc6, 0xf0); + SDL_SetTextureBlendMode(win->rightEye, SDL_BLENDMODE_ADD); + + /* scale the renderer output for High-DPI displays */ + { + int renderW, renderH; + int windowW, windowH; + float scaleX, scaleY; + SDL_GetRendererOutputSize(win->renderer, &renderW, &renderH); + SDL_GetWindowSize(win->window, &windowW, &windowH); + scaleX = (float)(renderW) / (float)(windowW); + scaleY = (float)(renderH) / (float)(windowH); + SDL_RenderSetScale(win->renderer, scaleX, scaleY); + fontScale = scaleY; + } + + win->nk = nk_sdl_init(win->window, win->renderer); + applyStyles(win->nk); + /* tell nuklear the mouse moved somewhere so it doesn't think we're hovering in the top left */ + nk_input_motion(win->nk, 1024, 1024); + + { + struct nk_font_atlas *atlas; + struct nk_font_config config = nk_font_config(0); + + nk_sdl_font_stash_begin(&atlas); + win->font = nk_font_atlas_add_default(atlas, 13 * fontScale, &config); + nk_sdl_font_stash_end(); + + win->font->handle.height /= fontScale; + nk_style_set_font(win->nk, &win->font->handle); + } + + return 0; + +cleanup_left_eye: + SDL_DestroyTexture(win->leftEye); +cleanup_renderer: + SDL_DestroyRenderer(win->renderer); +cleanup_window: + SDL_DestroyWindow(win->window); + return -1; +} + +void windowDestroy(WindowContext *win) { + SDL_DestroyTexture(win->rightEye); + SDL_DestroyTexture(win->leftEye); + SDL_DestroyRenderer(win->renderer); + SDL_DestroyWindow(win->window); +} + static void copyScreenTexture(uint8_t *dst, const uint8_t *src, int pitch) { int x, y, i; uint8_t color; @@ -71,83 +150,7 @@ static void copyScreenTexture(uint8_t *dst, const uint8_t *src, int pitch) { } } -int gfxInit(GraphicsContext *gfx) { - float fontScale = 1; - - gfx->window = SDL_CreateWindow("Shrooms VB", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI); - if (!gfx->window) { - fprintf(stderr, "Error creating window: %s\n", SDL_GetError()); - return 1; - } - - gfx->renderer = SDL_CreateRenderer(gfx->window, -1, 0); - if (!gfx->renderer) { - fprintf(stderr, "Error creating renderer: %s\n", SDL_GetError()); - goto cleanup_window; - } - - /* scale the renderer output for High-DPI displays */ - { - int renderW, renderH; - int windowW, windowH; - float scaleX, scaleY; - SDL_GetRendererOutputSize(gfx->renderer, &renderW, &renderH); - SDL_GetWindowSize(gfx->window, &windowW, &windowH); - scaleX = (float)(renderW) / (float)(windowW); - scaleY = (float)(renderH) / (float)(windowH); - SDL_RenderSetScale(gfx->renderer, scaleX, scaleY); - } - - gfx->nk = nk_sdl_init(gfx->window, gfx->renderer); - applyStyles(gfx->nk); - /* tell nuklear the mouse moved somewhere so it doesn't think we're hovering in the top left */ - nk_input_motion(gfx->nk, 1024, 1024); - - { - struct nk_font_atlas *atlas; - struct nk_font_config config = nk_font_config(0); - - nk_sdl_font_stash_begin(&atlas); - gfx->font = nk_font_atlas_add_default(atlas, 13 * fontScale, &config); - nk_sdl_font_stash_end(); - - gfx->font->handle.height /= fontScale; - nk_style_set_font(gfx->nk, &gfx->font->handle); - } - - gfx->leftEye = SDL_CreateTexture(gfx->renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, 384, 224); - if (!gfx->leftEye) { - fprintf(stderr, "Error creating left eye texture: %s\n", SDL_GetError()); - goto cleanup_window; - } - SDL_SetTextureColorMod(gfx->leftEye, 0xff, 0, 0); - - gfx->rightEye = SDL_CreateTexture(gfx->renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, 384, 224); - if (!gfx->rightEye) { - fprintf(stderr, "Error creating left eye texture: %s\n", SDL_GetError()); - goto cleanup_left_eye; - } - SDL_SetTextureColorMod(gfx->rightEye, 0, 0xc6, 0xf0); - SDL_SetTextureBlendMode(gfx->rightEye, SDL_BLENDMODE_ADD); - - return 0; - -cleanup_left_eye: - SDL_DestroyTexture(gfx->leftEye); -cleanup_window: - SDL_DestroyWindow(gfx->window); - return 1; -} - -void gfxDestroy(GraphicsContext *gfx) { - SDL_DestroyTexture(gfx->rightEye); - SDL_DestroyTexture(gfx->leftEye); - SDL_DestroyWindow(gfx->window); -} - -static void gfxUpdateEye(SDL_Texture *eye, const uint8_t *bytes) { +static void updateEye(SDL_Texture *eye, const uint8_t *bytes) { void *target; int pitch; if (SDL_LockTexture(eye, NULL, &target, &pitch)) { @@ -158,82 +161,57 @@ static void gfxUpdateEye(SDL_Texture *eye, const uint8_t *bytes) { SDL_UnlockTexture(eye); } -void gfxUpdateEyes(GraphicsContext *gfx, const uint8_t *left, const uint8_t *right) { - gfxUpdateEye(gfx->leftEye, left); - gfxUpdateEye(gfx->rightEye, right); +void windowUpdate(WindowContext *win, const uint8_t *left, const uint8_t *right) { + updateEye(win->leftEye, left); + updateEye(win->rightEye, right); } -void gfxMenuInputBegin(GraphicsContext *gfx) { - nk_input_begin(gfx->nk); +int windowGetScreenHeight(WindowContext *win) { + (void) win; + return SCREEN_HEIGHT; } -void gfxMenuHandleEvent(GraphicsContext *gfx, SDL_Event *event) { - (void) gfx; - nk_sdl_handle_event(event); -} - -void gfxMenuInputEnd(GraphicsContext *gfx) { - nk_sdl_handle_grab(); - nk_input_end(gfx->nk); -} - -static void pushMenubarSpace(GraphicsContext *gfx, const char *text) { - struct nk_user_font *handle; - int len; - float width; - handle = &gfx->font->handle; - len = nk_strlen(text); - width = handle->width(handle->userdata, handle->height, text, len) + 16; - nk_layout_row_template_push_static(gfx->nk, width); -} - -void gfxRender(GraphicsContext *gfx) { +void windowDisplayBegin(WindowContext *win) { SDL_Rect dst; dst.x = 0; dst.y = MENU_HEIGHT; dst.w = SCREEN_WIDTH; dst.h = SCREEN_HEIGHT; - SDL_RenderClear(gfx->renderer); - SDL_RenderCopy(gfx->renderer, gfx->leftEye, NULL, &dst); - SDL_RenderCopy(gfx->renderer, gfx->rightEye, NULL, &dst); - - /* GUI */ - if (nk_begin(gfx->nk, "Game", nk_rect(0, 0, SCREEN_WIDTH, MENU_HEIGHT), NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_BACKGROUND)) { - nk_menubar_begin(gfx->nk); - nk_layout_row_template_begin(gfx->nk, 20); - pushMenubarSpace(gfx, "File"); - pushMenubarSpace(gfx, "Emulation"); - nk_layout_row_template_end(gfx->nk); - if (nk_menu_begin_label(gfx->nk, "File", NK_TEXT_ALIGN_CENTERED, nk_vec2(120, WINDOW_HEIGHT))) { - nk_layout_row_dynamic(gfx->nk, 22, 1); - if (nk_menu_item_label(gfx->nk, "Open ROM", NK_TEXT_ALIGN_LEFT)) { - printf("Open ROM\n"); - } - if (nk_menu_item_label(gfx->nk, "Quit", NK_TEXT_ALIGN_LEFT)) { - SDL_Event QuitEvent; - QuitEvent.type = SDL_QUIT; - QuitEvent.quit.timestamp = SDL_GetTicks(); - SDL_PushEvent(&QuitEvent); - } - nk_menu_end(gfx->nk); - } - if (nk_menu_begin_label(gfx->nk, "Emulation", NK_TEXT_ALIGN_CENTERED, nk_vec2(120, WINDOW_HEIGHT))) { - nk_layout_row_dynamic(gfx->nk, 22, 1); - if (nk_menu_item_label(gfx->nk, "Pause", NK_TEXT_ALIGN_LEFT)) { - printf("Pause\n"); - } - if (nk_menu_item_label(gfx->nk, "Reset", NK_TEXT_ALIGN_LEFT)) { - printf("Reset\n"); - } - nk_menu_end(gfx->nk); - } - nk_menubar_end(gfx->nk); - } - nk_end(gfx->nk); - - nk_sdl_render(NK_ANTI_ALIASING_ON); - - SDL_RenderPresent(gfx->renderer); + SDL_RenderClear(win->renderer); + SDL_RenderCopy(win->renderer, win->leftEye, NULL, &dst); + SDL_RenderCopy(win->renderer, win->rightEye, NULL, &dst); } +void windowDisplayEnd(WindowContext *win) { + nk_sdl_render(NK_ANTI_ALIASING_ON); + SDL_RenderPresent(win->renderer); +} + +bool windowGuiBegin(WindowContext *win, const char *title) { + return nk_begin(win->nk, title, nk_rect(0, 0, SCREEN_WIDTH, MENU_HEIGHT), NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_BACKGROUND); +} + +void windowGuiEnd(WindowContext *win) { + nk_end(win->nk); +} + +void windowMenubarBegin(WindowContext *win, const char **items) { + const char **item; + nk_menubar_begin(win->nk); + nk_layout_row_template_begin(win->nk, MENU_HEIGHT); + for (item = items; *item != NULL; item++) { + struct nk_user_font *handle; + int len; + float width; + handle = &win->font->handle; + len = nk_strlen(*item); + width = handle->width(handle->userdata, handle->height, *item, len) + 16; + nk_layout_row_template_push_static(win->nk, width); + } + nk_layout_row_template_end(win->nk); +} + +void windowMenubarEnd(WindowContext *win) { + nk_menubar_end(win->nk); +} \ No newline at end of file diff --git a/window.h b/window.h new file mode 100644 index 0000000..fb159f1 --- /dev/null +++ b/window.h @@ -0,0 +1,32 @@ +#ifndef SHROOMS_VB_NATIVE_WINDOW_ +#define SHROOMS_VB_NATIVE_WINDOW_ + +#include +#include "nuklear.h" + +#define MENU_HEIGHT 20 + +typedef struct WindowContext { + SDL_Window *window; + SDL_Renderer *renderer; + SDL_Texture *leftEye; + SDL_Texture *rightEye; + struct nk_context *nk; + struct nk_font *font; +} WindowContext; + +int windowInit(WindowContext *win, const char *title); +void windowDestroy(WindowContext *win); + +void windowUpdate(WindowContext *win, const uint8_t *left, const uint8_t *right); + +int windowGetScreenHeight(WindowContext *win); + +void windowDisplayBegin(WindowContext *win); +void windowDisplayEnd(WindowContext *win); +bool windowGuiBegin(WindowContext *win, const char *title); +void windowGuiEnd(WindowContext *win); +void windowMenubarBegin(WindowContext *win, const char **items); +void windowMenubarEnd(WindowContext *win); + +#endif \ No newline at end of file