lemur/ui.c

218 lines
5.9 KiB
C

#include "audio.h"
#include "controller.h"
#include "emulation.h"
#include "external/tinyfiledialogs.h"
#include <stdio.h>
#include <stdlib.h>
#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 = NULL;
long fileSize;
uint32_t romSize;
int result;
if (!file) {
perror("could not open file");
return -1;
}
if (fseek(file, 0, SEEK_END)) {
perror("could not seek file end");
goto close_file;
}
fileSize = ftell(file);
if (fileSize == -1) {
perror("could not read file size");
goto close_file;
}
if (fseek(file, 0, SEEK_SET)) {
perror("could not seek file start");
goto close_file;
}
romSize = (uint32_t) fileSize;
rom = malloc(romSize);
if (!rom) {
perror("could not allocate ROM");
goto close_file;
}
fread(rom, 1, romSize, file);
if (ferror(file)) {
perror("could not read file");
goto free_rom;
}
result = fclose(file);
file = NULL;
if (result) {
perror("could not close file");
goto free_rom;
}
emuLoadGame(&ui->emu, rom, romSize);
return 0;
free_rom:
free(rom);
close_file:
if (file) fclose(file);
return -1;
}
static const char *MENU_ITEMS[4] = {
"File",
"Emulation",
"Video",
NULL
};
static const char *ROM_EXTENSIONS[2] = {
"*.vb",
NULL
};
typedef enum status_t {
status_paused,
status_running
} status_t;
int uiRun(UIContext *ui, bool running) {
static uint8_t leftEye[384*224] = {0};
static uint8_t rightEye[384*224] = {0};
status_t status = running ? status_running : status_paused;
windowUpdate(&ui->win, leftEye, rightEye);
while (1) {
struct nk_context *ctx;
SDL_Event event;
void *samples;
uint32_t bytes;
ctx = ui->win.nk;
if (status == status_running) {
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 (windowMenuBegin(&ui->win, "File", 100)) {
if (windowMenuItemLabel(&ui->win, "Open ROM")) {
char *file = tinyfd_openFileDialog("Pick a ROM", NULL, 1, ROM_EXTENSIONS, "Virtual Boy ROM files", false);
if (file) {
uiLoadGame(ui, file);
status = status_running;
}
}
if (windowMenuItemLabel(&ui->win, "Quit")) {
SDL_Event QuitEvent;
QuitEvent.type = SDL_QUIT;
QuitEvent.quit.timestamp = SDL_GetTicks();
SDL_PushEvent(&QuitEvent);
}
windowMenuEnd(&ui->win);
}
if (windowMenuBegin(&ui->win, "Emulation", 100)) {
const char *label = status == status_paused ? "Resume" : "Pause";
if (windowMenuItemLabel(&ui->win, label)) {
if (status == status_paused)
status = status_running;
else
status = status_paused;
}
if (windowMenuItemLabel(&ui->win, "Reset")) {
emuReset(&ui->emu);
status = emuIsGameLoaded(&ui->emu) ? status_running : status_paused;
}
windowMenuEnd(&ui->win);
}
if (windowMenuBegin(&ui->win, "Video", 100)) {
float multiplier = windowGetScreenSizeMultiplier(&ui->win);
if (windowMenuItemLabelChecked(&ui->win, "x1", multiplier == 1.0f)) {
windowSetScreenSizeMultiplier(&ui->win, 1.0f);
}
if (windowMenuItemLabelChecked(&ui->win, "x2", multiplier == 2.0f)) {
windowSetScreenSizeMultiplier(&ui->win, 2.0f);
}
if (windowMenuItemLabelChecked(&ui->win, "x3", multiplier == 3.0f)) {
windowSetScreenSizeMultiplier(&ui->win, 3.0f);
}
if (windowMenuItemLabelChecked(&ui->win, "x4", multiplier == 4.0f)) {
windowSetScreenSizeMultiplier(&ui->win, 4.0f);
}
windowMenuEnd(&ui->win);
}
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));
}
}