2024-05-17 00:33:37 -04:00
|
|
|
//
|
|
|
|
// Created by william on 16/05/24.
|
|
|
|
//
|
|
|
|
|
2024-06-16 19:22:40 -04:00
|
|
|
#include <SDL_ttf.h>
|
2024-10-03 19:24:03 -04:00
|
|
|
#include <assert.h>
|
2024-05-17 00:33:37 -04:00
|
|
|
#include "log.h"
|
2024-05-17 13:16:21 -04:00
|
|
|
#include "gui.h"
|
2024-06-16 19:22:40 -04:00
|
|
|
#include "main_window.h"
|
|
|
|
#include "pattern_window.h"
|
|
|
|
#include "../include/system.h"
|
2024-07-12 13:07:16 -04:00
|
|
|
#include "nametable_window.h"
|
2024-07-21 16:41:38 -04:00
|
|
|
#include "dbg_pattern_table.h"
|
2024-07-23 20:46:13 -04:00
|
|
|
#include "dbg_nametable.h"
|
2024-07-25 21:22:00 -04:00
|
|
|
#include "char_map.h"
|
2024-08-03 21:51:31 -04:00
|
|
|
#include "dbg_palette.h"
|
2024-05-17 00:33:37 -04:00
|
|
|
|
2024-05-17 13:16:21 -04:00
|
|
|
typedef struct nes_gui {
|
2024-10-03 19:24:03 -04:00
|
|
|
bool window_types_open[WINDOW_TYPE_MAX + 1];
|
|
|
|
void *window_types_ref[WINDOW_TYPE_MAX + 1];
|
|
|
|
int window_types_ids[WINDOW_TYPE_MAX + 1];
|
2024-06-16 19:22:40 -04:00
|
|
|
|
|
|
|
TTF_Font *font;
|
|
|
|
|
|
|
|
Uint32 last_frame_tick;
|
|
|
|
Uint32 frame_delay;
|
2024-07-25 21:22:00 -04:00
|
|
|
|
2024-07-21 16:41:38 -04:00
|
|
|
unsigned long tick;
|
2024-05-17 13:16:21 -04:00
|
|
|
} NesGui;
|
2024-05-17 00:33:37 -04:00
|
|
|
NesGui gui;
|
|
|
|
|
2024-10-03 19:24:03 -04:00
|
|
|
#define GUI_WINDOW_OPEN_(window_type) gui.window_types_open[window_type]
|
|
|
|
#define GUI_WINDOW_REF_(window_type) gui.window_types_ref[window_type]
|
|
|
|
#define GUI_WINDOW_ACTION_BASE(window_type, call) \
|
|
|
|
if (GUI_WINDOW_OPEN_(window_type)) { \
|
|
|
|
call(GUI_WINDOW_REF_(window_type)); \
|
|
|
|
}
|
|
|
|
|
|
|
|
void gui_window_create(WindowType type) {
|
|
|
|
void **ref = &gui.window_types_ref[type];
|
|
|
|
if (gui.window_types_open[type]) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
gui.window_types_open[type] = true;
|
|
|
|
int window_id = -1;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case WINDOW_TYPE_MAIN:
|
|
|
|
*ref = main_window_create(&window_id);
|
|
|
|
break;
|
|
|
|
case WINDOW_TYPE_NAMETABLE:
|
|
|
|
*ref = nametable_window_create(&window_id);
|
|
|
|
break;
|
|
|
|
case WINDOW_TYPE_PATTERN_TABLE:
|
|
|
|
*ref = pattern_window_create(&window_id);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
gui.window_types_ids[type] = window_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gui_window_destroy(WindowType type) {
|
|
|
|
bool *open = &gui.window_types_open[type];
|
|
|
|
if (*open == false) {
|
|
|
|
// The window doesn't exist
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *ref = gui.window_types_ref[type];
|
|
|
|
switch (type) {
|
|
|
|
case WINDOW_TYPE_MAIN:
|
|
|
|
main_window_destroy(ref);
|
|
|
|
break;
|
|
|
|
case WINDOW_TYPE_NAMETABLE:
|
|
|
|
nametable_window_destroy(ref);
|
|
|
|
break;
|
|
|
|
case WINDOW_TYPE_PATTERN_TABLE:
|
|
|
|
pattern_window_destroy(ref);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
gui.window_types_ids[type] = -1;
|
|
|
|
*open = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gui_window_destroy_by_id(int window_id) {
|
|
|
|
WindowType type = -1;
|
|
|
|
for (int i = 0; i <= WINDOW_TYPE_MAX; i++) {
|
|
|
|
if (gui.window_types_ids[i] == window_id) {
|
|
|
|
type = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type == -1) {
|
|
|
|
// Close event is sent twice?
|
|
|
|
log_error("Couldn't find window with ID %d", window_id);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
gui_window_destroy(type);
|
|
|
|
}
|
|
|
|
|
2024-06-16 19:22:40 -04:00
|
|
|
bool gui_init() {
|
2024-10-03 19:24:03 -04:00
|
|
|
memset(gui.window_types_open, false, sizeof(bool) * WINDOW_TYPE_MAX);
|
|
|
|
memset(gui.window_types_ref, 0, sizeof(void *) * WINDOW_TYPE_MAX);
|
|
|
|
|
2024-06-16 19:22:40 -04:00
|
|
|
TTF_Init();
|
2024-07-10 22:34:14 -04:00
|
|
|
gui.font = TTF_OpenFont("./nintendo-nes-font.ttf", 16);
|
2024-06-16 19:22:40 -04:00
|
|
|
if (gui.font == NULL) {
|
|
|
|
log_error("Failed to open TTF font");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-10-03 19:24:03 -04:00
|
|
|
memset(gui.window_types_ids, -1, (WINDOW_TYPE_MAX + 1) * sizeof(*gui.window_types_ids));
|
|
|
|
gui_window_create(WINDOW_TYPE_MAIN);
|
2024-07-25 22:08:08 -04:00
|
|
|
|
2024-06-16 19:22:40 -04:00
|
|
|
return true;
|
2024-05-17 11:40:02 -04:00
|
|
|
}
|
2024-05-17 00:33:37 -04:00
|
|
|
|
2024-10-03 19:24:03 -04:00
|
|
|
void gui_free() {
|
|
|
|
for (int i = 0; i < WINDOW_TYPE_MAX; i++) {
|
|
|
|
gui_window_destroy(i);
|
|
|
|
}
|
2024-06-16 19:22:40 -04:00
|
|
|
|
|
|
|
TTF_CloseFont(gui.font);
|
|
|
|
}
|
|
|
|
|
2024-08-20 20:43:42 -04:00
|
|
|
bool lctrl = false;
|
|
|
|
|
2024-05-17 00:33:37 -04:00
|
|
|
int gui_input() {
|
2024-10-03 19:24:03 -04:00
|
|
|
assert(gui.window_types_open[WINDOW_TYPE_MAIN]);
|
2024-05-17 00:33:37 -04:00
|
|
|
SDL_Event event;
|
|
|
|
|
2024-08-20 20:43:42 -04:00
|
|
|
PPUDebugFlags *ppu_debug = &ppu_get_state()->debug;
|
|
|
|
|
2024-05-17 00:33:37 -04:00
|
|
|
while (SDL_PollEvent(&event)) {
|
2024-05-17 11:40:02 -04:00
|
|
|
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE) {
|
2024-10-03 19:24:03 -04:00
|
|
|
Uint32 window_id = event.window.windowID;
|
|
|
|
for (int type = 0; type <= WINDOW_TYPE_MAX; type++) {
|
|
|
|
bool is_main_window = gui.window_types_ids[WINDOW_TYPE_MAIN] == window_id;
|
|
|
|
|
|
|
|
gui_window_destroy_by_id(window_id);
|
|
|
|
|
|
|
|
if (is_main_window) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2024-05-17 00:33:37 -04:00
|
|
|
}
|
2024-08-03 21:51:31 -04:00
|
|
|
|
2024-08-20 20:43:42 -04:00
|
|
|
if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_LCTRL) {
|
|
|
|
lctrl = true;
|
|
|
|
}
|
|
|
|
|
2024-08-06 17:30:57 -04:00
|
|
|
if (event.type == SDL_KEYUP) {
|
2024-08-20 20:43:42 -04:00
|
|
|
switch (event.key.keysym.sym) {
|
|
|
|
case SDLK_LCTRL:
|
|
|
|
lctrl = false;
|
|
|
|
break;
|
|
|
|
case SDLK_p:
|
|
|
|
system_toggle_pause(lctrl);
|
|
|
|
break;
|
2024-10-03 19:24:03 -04:00
|
|
|
case SDLK_t:
|
|
|
|
ppu_debug->flags.tile_debugger = !ppu_debug->flags.tile_debugger;
|
|
|
|
break;
|
|
|
|
case SDLK_n:
|
|
|
|
ppu_debug->flags.tile_debugger_pattern_half = (ppu_debug->flags.tile_debugger_pattern_half + 1) % 3;
|
|
|
|
break;
|
2024-09-01 15:54:41 -04:00
|
|
|
default:
|
2024-10-03 19:24:03 -04:00
|
|
|
if (gui.window_types_open[WINDOW_TYPE_PATTERN_TABLE]) {
|
|
|
|
pattern_window_key_up(gui.window_types_ref[WINDOW_TYPE_PATTERN_TABLE], event.key.keysym.sym);
|
|
|
|
}
|
2024-09-01 15:54:41 -04:00
|
|
|
break;
|
2024-08-06 17:30:57 -04:00
|
|
|
}
|
2024-08-03 21:51:31 -04:00
|
|
|
}
|
2024-09-01 15:54:41 -04:00
|
|
|
|
2024-10-03 19:24:03 -04:00
|
|
|
void *main_window_ref = gui.window_types_ref[WINDOW_TYPE_MAIN];
|
2024-09-01 15:54:41 -04:00
|
|
|
if (event.type == SDL_MOUSEMOTION) {
|
|
|
|
int x = event.motion.x;
|
|
|
|
int y = event.motion.y;
|
|
|
|
|
2024-10-03 19:24:03 -04:00
|
|
|
if (gui.window_types_ids[WINDOW_TYPE_MAIN] == event.window.windowID) {
|
|
|
|
main_window_mouse_motion(main_window_ref, x, y);
|
2024-09-01 15:54:41 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-03 19:24:03 -04:00
|
|
|
if (event.type == SDL_MOUSEBUTTONUP && gui.window_types_ids[WINDOW_TYPE_MAIN] == event.window.windowID) {
|
|
|
|
main_window_mouse_click(main_window_ref);
|
2024-09-01 15:54:41 -04:00
|
|
|
}
|
2024-05-17 00:33:37 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2024-10-03 19:24:03 -04:00
|
|
|
#define GUI_WINDOW_RENDER(window_type, prefix) GUI_WINDOW_ACTION_BASE(window_type, prefix ## _window_render)
|
|
|
|
|
2024-05-17 00:33:37 -04:00
|
|
|
void gui_render() {
|
2024-10-03 19:24:03 -04:00
|
|
|
assert(gui.window_types_open[WINDOW_TYPE_MAIN]);
|
|
|
|
main_window_render(gui.window_types_ref[WINDOW_TYPE_MAIN], ppu_get_state()->pixels);
|
2024-08-20 20:43:42 -04:00
|
|
|
|
2024-10-03 19:24:03 -04:00
|
|
|
// Update the nametable
|
|
|
|
GUI_WINDOW_ACTION_BASE(WINDOW_TYPE_NAMETABLE, nametable_window_update);
|
|
|
|
GUI_WINDOW_RENDER(WINDOW_TYPE_NAMETABLE, nametable);
|
2024-07-21 16:41:38 -04:00
|
|
|
|
2024-10-03 19:24:03 -04:00
|
|
|
// Update the pattern table
|
|
|
|
GUI_WINDOW_ACTION_BASE(WINDOW_TYPE_PATTERN_TABLE, pattern_window_update);
|
|
|
|
GUI_WINDOW_RENDER(WINDOW_TYPE_PATTERN_TABLE, pattern)
|
2024-07-21 16:41:38 -04:00
|
|
|
|
|
|
|
gui.tick++;
|
2024-05-17 00:33:37 -04:00
|
|
|
}
|
|
|
|
|
2024-05-17 13:16:21 -04:00
|
|
|
void gui_delay() {
|
2024-06-16 19:22:40 -04:00
|
|
|
Uint32 tick_now = SDL_GetTicks();
|
|
|
|
gui.frame_delay = tick_now - gui.last_frame_tick;
|
2024-05-17 13:16:21 -04:00
|
|
|
|
2024-06-16 19:22:40 -04:00
|
|
|
if (gui.frame_delay < 16) {
|
|
|
|
Uint32 additional_delay = 16 - gui.frame_delay;
|
|
|
|
SDL_Delay(additional_delay);
|
|
|
|
gui.frame_delay += additional_delay;
|
2024-05-17 11:40:02 -04:00
|
|
|
}
|
2024-05-17 00:33:37 -04:00
|
|
|
|
2024-06-16 19:22:40 -04:00
|
|
|
gui.last_frame_tick = SDL_GetTicks();
|
|
|
|
}
|
|
|
|
|
2024-09-01 15:54:41 -04:00
|
|
|
TTF_Font *gui_get_font() {
|
|
|
|
return gui.font;
|
2024-05-17 00:33:37 -04:00
|
|
|
}
|