Rearrange everything so the GUI is in the main loop
This commit is contained in:
parent
511ad086cd
commit
0fb8d8e59f
4
audio.c
4
audio.c
|
@ -37,6 +37,10 @@ int audioInit(AudioContext *aud) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void audioDestroy(AudioContext *aud) {
|
||||||
|
SDL_CloseAudioDevice(aud->id);
|
||||||
|
}
|
||||||
|
|
||||||
int audioUpdate(AudioContext *aud, void *data, uint32_t bytes) {
|
int audioUpdate(AudioContext *aud, void *data, uint32_t bytes) {
|
||||||
int filled;
|
int filled;
|
||||||
if (!aud->id) return -1;
|
if (!aud->id) return -1;
|
||||||
|
|
1
audio.h
1
audio.h
|
@ -13,6 +13,7 @@ typedef struct {
|
||||||
} AudioContext;
|
} AudioContext;
|
||||||
|
|
||||||
int audioInit(AudioContext *aud);
|
int audioInit(AudioContext *aud);
|
||||||
|
void audioDestroy(AudioContext *aud);
|
||||||
int audioUpdate(AudioContext *aud, void *data, uint32_t bytes);
|
int audioUpdate(AudioContext *aud, void *data, uint32_t bytes);
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -0,0 +1,61 @@
|
||||||
|
#include "emulation.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef SHROOMS_VB_NATIVE_EMULATION_
|
||||||
|
#define SHROOMS_VB_NATIVE_EMULATION_
|
||||||
|
|
||||||
|
#include "shrooms-vb-core/core/vb.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
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
|
72
game.c
72
game.c
|
@ -1,72 +0,0 @@
|
||||||
#include <audio.h>
|
|
||||||
#include <assets.h>
|
|
||||||
#include <controller.h>
|
|
||||||
#include <game.h>
|
|
||||||
#include <SDL2/SDL.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
9
game.h
9
game.h
|
@ -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
|
|
27
graphics.h
27
graphics.h
|
@ -1,27 +0,0 @@
|
||||||
#ifndef SHROOMS_VB_NATIVE_GRAPHICS_
|
|
||||||
#define SHROOMS_VB_NATIVE_GRAPHICS_
|
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
|
||||||
#include <nuklear.h>
|
|
||||||
|
|
||||||
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
|
|
73
main.c
73
main.c
|
@ -1,86 +1,35 @@
|
||||||
#include <cli.h>
|
#include "cli.h"
|
||||||
#include <game.h>
|
|
||||||
#include <graphics.h>
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
#include "shrooms-vb-core/core/vb.h"
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include "ui.h"
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
VB *sim;
|
|
||||||
uint8_t *rom;
|
|
||||||
uint32_t romSize;
|
|
||||||
GraphicsContext gfx;
|
|
||||||
CLIArgs args;
|
CLIArgs args;
|
||||||
|
UIContext *ui;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
if (parseCLIArgs(argc, argv, &args)) {
|
if (parseCLIArgs(argc, argv, &args)) {
|
||||||
return 1;
|
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");
|
SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "0");
|
||||||
if (SDL_Init(SDL_INIT_EVERYTHING)) {
|
if (SDL_Init(SDL_INIT_EVERYTHING)) {
|
||||||
fprintf(stderr, "Error initializing SDL: %s\n", SDL_GetError());
|
fprintf(stderr, "Error initializing SDL: %s\n", SDL_GetError());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gfxInit(&gfx)) {
|
ui = uiInit();
|
||||||
|
if (!ui) {
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = runGame(sim, &gfx);
|
if (args.filename) {
|
||||||
|
uiLoadGame(ui, args.filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
status = uiRun(ui);
|
||||||
|
uiDestroy(ui);
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,169 @@
|
||||||
|
#include "audio.h"
|
||||||
|
#include "controller.h"
|
||||||
|
#include "emulation.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;
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -1,9 +1,8 @@
|
||||||
#include <graphics.h>
|
#include "nuklear.h"
|
||||||
#include <stdio.h>
|
#include "window.h"
|
||||||
|
|
||||||
#define SCREEN_WIDTH 384
|
#define SCREEN_WIDTH 384
|
||||||
#define SCREEN_HEIGHT 224
|
#define SCREEN_HEIGHT 224
|
||||||
#define MENU_HEIGHT 20
|
|
||||||
|
|
||||||
#define WINDOW_WIDTH SCREEN_WIDTH
|
#define WINDOW_WIDTH SCREEN_WIDTH
|
||||||
#define WINDOW_HEIGHT (SCREEN_HEIGHT + MENU_HEIGHT)
|
#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);
|
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) {
|
static void copyScreenTexture(uint8_t *dst, const uint8_t *src, int pitch) {
|
||||||
int x, y, i;
|
int x, y, i;
|
||||||
uint8_t color;
|
uint8_t color;
|
||||||
|
@ -71,83 +150,7 @@ static void copyScreenTexture(uint8_t *dst, const uint8_t *src, int pitch) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int gfxInit(GraphicsContext *gfx) {
|
static void updateEye(SDL_Texture *eye, const uint8_t *bytes) {
|
||||||
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) {
|
|
||||||
void *target;
|
void *target;
|
||||||
int pitch;
|
int pitch;
|
||||||
if (SDL_LockTexture(eye, NULL, &target, &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);
|
SDL_UnlockTexture(eye);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfxUpdateEyes(GraphicsContext *gfx, const uint8_t *left, const uint8_t *right) {
|
void windowUpdate(WindowContext *win, const uint8_t *left, const uint8_t *right) {
|
||||||
gfxUpdateEye(gfx->leftEye, left);
|
updateEye(win->leftEye, left);
|
||||||
gfxUpdateEye(gfx->rightEye, right);
|
updateEye(win->rightEye, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfxMenuInputBegin(GraphicsContext *gfx) {
|
int windowGetScreenHeight(WindowContext *win) {
|
||||||
nk_input_begin(gfx->nk);
|
(void) win;
|
||||||
|
return SCREEN_HEIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfxMenuHandleEvent(GraphicsContext *gfx, SDL_Event *event) {
|
void windowDisplayBegin(WindowContext *win) {
|
||||||
(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) {
|
|
||||||
SDL_Rect dst;
|
SDL_Rect dst;
|
||||||
dst.x = 0;
|
dst.x = 0;
|
||||||
dst.y = MENU_HEIGHT;
|
dst.y = MENU_HEIGHT;
|
||||||
dst.w = SCREEN_WIDTH;
|
dst.w = SCREEN_WIDTH;
|
||||||
dst.h = SCREEN_HEIGHT;
|
dst.h = SCREEN_HEIGHT;
|
||||||
|
|
||||||
SDL_RenderClear(gfx->renderer);
|
SDL_RenderClear(win->renderer);
|
||||||
SDL_RenderCopy(gfx->renderer, gfx->leftEye, NULL, &dst);
|
SDL_RenderCopy(win->renderer, win->leftEye, NULL, &dst);
|
||||||
SDL_RenderCopy(gfx->renderer, gfx->rightEye, NULL, &dst);
|
SDL_RenderCopy(win->renderer, win->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);
|
|
||||||
|
|
||||||
|
void windowDisplayEnd(WindowContext *win) {
|
||||||
nk_sdl_render(NK_ANTI_ALIASING_ON);
|
nk_sdl_render(NK_ANTI_ALIASING_ON);
|
||||||
|
SDL_RenderPresent(win->renderer);
|
||||||
SDL_RenderPresent(gfx->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);
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef SHROOMS_VB_NATIVE_WINDOW_
|
||||||
|
#define SHROOMS_VB_NATIVE_WINDOW_
|
||||||
|
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
#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
|
Loading…
Reference in New Issue