diff options
Diffstat (limited to 'gearboy/platforms/desktop-shared/application.cpp')
| -rw-r--r-- | gearboy/platforms/desktop-shared/application.cpp | 531 |
1 files changed, 531 insertions, 0 deletions
diff --git a/gearboy/platforms/desktop-shared/application.cpp b/gearboy/platforms/desktop-shared/application.cpp new file mode 100644 index 00000000..d39cf934 --- /dev/null +++ b/gearboy/platforms/desktop-shared/application.cpp @@ -0,0 +1,531 @@ +/* + * Gearboy - Nintendo Game Boy Emulator + * Copyright (C) 2012 Ignacio Sanchez + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ + * + */ + +#include <SDL.h> +#include "imgui/imgui.h" +#include "imgui/imgui_impl_sdl.h" +#include "emu.h" +#include "gui.h" +#include "config.h" +#include "renderer.h" + +#define APPLICATION_IMPORT +#include "application.h" + +static SDL_Window* sdl_window; +static SDL_GLContext gl_context; +static bool running = true; +static bool paused_when_focus_lost = false; +static Uint64 frame_time_start; +static Uint64 frame_time_end; + +static int sdl_init(void); +static void sdl_destroy(void); +static void sdl_events(void); +static void sdl_events_emu(const SDL_Event* event); +static void sdl_shortcuts_gui(const SDL_Event* event); +static void run_emulator(void); +static void render(void); +static void frame_throttle(void); + +int application_init(const char* arg) +{ + Log ("<·> %s %s Desktop App <·>", GEARBOY_TITLE, GEARBOY_VERSION); + + if (IsValidPointer(arg) && (strlen(arg) > 0)) + { + Log ("Loading with argv: %s"); + } + + int ret = sdl_init(); + + application_fullscreen = false; + + config_init(); + config_read(); + + emu_init(); + + strcpy(emu_savefiles_path, config_emulator.savefiles_path.c_str()); + strcpy(emu_savestates_path, config_emulator.savestates_path.c_str()); + emu_savefiles_dir_option = config_emulator.savefiles_dir_option; + emu_savestates_dir_option = config_emulator.savestates_dir_option; + + gui_init(); + + ImGui_ImplSDL2_InitForOpenGL(sdl_window, gl_context); + + renderer_init(); + + SDL_GL_SetSwapInterval(config_video.sync ? 1 : 0); + + if (IsValidPointer(arg) && (strlen(arg) > 0)) + { + gui_load_rom(arg); + } + + return ret; +} + +void application_destroy(void) +{ + config_write(); + config_destroy(); + renderer_destroy(); + gui_destroy(); + emu_destroy(); + sdl_destroy(); +} + +void application_mainloop(void) +{ + while (running) + { + frame_time_start = SDL_GetPerformanceCounter(); + sdl_events(); + run_emulator(); + render(); + frame_time_end = SDL_GetPerformanceCounter(); + frame_throttle(); + } +} + +void application_trigger_quit(void) +{ + SDL_Event event; + event.type = SDL_QUIT; + SDL_PushEvent(&event); +} + +void application_trigger_fullscreen(bool fullscreen) +{ + SDL_SetWindowFullscreen(sdl_window, fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); +} + +static int sdl_init(void) +{ + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) + { + Log("Error: %s\n", SDL_GetError()); + return -1; + } + + SDL_VERSION(&application_sdl_build_version); + SDL_GetVersion(&application_sdl_link_version); + + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); + SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); + sdl_window = SDL_CreateWindow(GEARBOY_TITLE " " GEARBOY_VERSION, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 700, window_flags); + gl_context = SDL_GL_CreateContext(sdl_window); + SDL_GL_MakeCurrent(sdl_window, gl_context); + SDL_GL_SetSwapInterval(0); + + SDL_SetWindowMinimumSize(sdl_window, 644, 602); + + application_gamepad_mappings = SDL_GameControllerAddMappingsFromRW(SDL_RWFromFile("gamecontrollerdb.txt", "rb"), 1); + + if (application_gamepad_mappings > 0) + { + Log("Succesfuly loaded %d game controller mappings", application_gamepad_mappings); + } + else + { + Log("Game controller database not found!"); + } + + for (int i = 0; i < SDL_NumJoysticks(); ++i) + { + if (SDL_IsGameController(i)) + { + application_gamepad = SDL_GameControllerOpen(i); + if(!application_gamepad) + { + Log("Warning: Unable to open game controller! SDL Error: %s\n", SDL_GetError()); + } + else + { + Log("Game controller %d correctly detected", i); + } + + break; + } + } + + int w, h; + int display_w, display_h; + SDL_GetWindowSize(sdl_window, &w, &h); + SDL_GL_GetDrawableSize(sdl_window, &display_w, &display_h); + + if (w > 0 && h > 0) + { + float scale_w = (float)display_w / w; + float scale_h = (float)display_h / h; + + application_display_scale = (scale_w > scale_h) ? scale_w : scale_h; + } + + SDL_EventState(SDL_DROPFILE, SDL_ENABLE); + + return 0; +} + +static void sdl_destroy(void) +{ + SDL_GameControllerClose(application_gamepad); + ImGui_ImplSDL2_Shutdown(); + SDL_GL_DeleteContext(gl_context); + SDL_DestroyWindow(sdl_window); + SDL_Quit(); +} + +static void sdl_events(void) +{ + SDL_Event event; + + while (SDL_PollEvent(&event)) + { + if (event.type == SDL_QUIT) + { + running = false; + break; + } + + ImGui_ImplSDL2_ProcessEvent(&event); + + if (!gui_in_use) + { + sdl_events_emu(&event); + sdl_shortcuts_gui(&event); + } + } +} + +static void sdl_events_emu(const SDL_Event* event) +{ + switch(event->type) + { + case (SDL_DROPFILE): + { + char* dropped_filedir = event->drop.file; + gui_load_rom(dropped_filedir); + SDL_free(dropped_filedir); // Free dropped_filedir memory + break; + } + case SDL_WINDOWEVENT: + { + switch (event->window.event) + { + case SDL_WINDOWEVENT_FOCUS_GAINED: + { + if (!paused_when_focus_lost) + emu_resume(); + } + break; + + case SDL_WINDOWEVENT_FOCUS_LOST: + { + paused_when_focus_lost = emu_is_paused(); + emu_pause(); + } + break; + } + } + break; + + case SDL_CONTROLLERBUTTONDOWN: + { + if (!config_input.gamepad) + break; + + if (event->cbutton.button == config_input.gamepad_b) + emu_key_pressed(B_Key); + else if (event->cbutton.button == config_input.gamepad_a) + emu_key_pressed(A_Key); + else if (event->cbutton.button == config_input.gamepad_select) + emu_key_pressed(Select_Key); + else if (event->cbutton.button == config_input.gamepad_start) + emu_key_pressed(Start_Key); + + if (config_input.gamepad_directional == 1) + break; + + if (event->cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + emu_key_pressed(Up_Key); + else if (event->cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + emu_key_pressed(Down_Key); + else if (event->cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) + emu_key_pressed(Left_Key); + else if (event->cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + emu_key_pressed(Right_Key); + } + break; + + case SDL_CONTROLLERBUTTONUP: + { + if (!config_input.gamepad) + break; + + if (event->cbutton.button == config_input.gamepad_b) + emu_key_released(B_Key); + else if (event->cbutton.button == config_input.gamepad_a) + emu_key_released(A_Key); + else if (event->cbutton.button == config_input.gamepad_select) + emu_key_released(Select_Key); + else if (event->cbutton.button == config_input.gamepad_start) + emu_key_released(Start_Key); + + if (config_input.gamepad_directional == 1) + break; + + if (event->cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + emu_key_released(Up_Key); + else if (event->cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + emu_key_released(Down_Key); + else if (event->cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) + emu_key_released(Left_Key); + else if (event->cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + emu_key_released(Right_Key); + } + break; + + case SDL_CONTROLLERAXISMOTION: + { + if (!config_input.gamepad) + break; + + if (config_input.gamepad_directional == 0) + break; + + const int STICK_DEAD_ZONE = 8000; + + if(event->caxis.axis == config_input.gamepad_x_axis) + { + int x_motion = event->caxis.value * (config_input.gamepad_invert_x_axis ? -1 : 1); + + if (x_motion < -STICK_DEAD_ZONE) + emu_key_pressed(Left_Key); + else if (x_motion > STICK_DEAD_ZONE) + emu_key_pressed(Right_Key); + else + { + emu_key_released(Left_Key); + emu_key_released(Right_Key); + } + } + else if(event->caxis.axis == config_input.gamepad_y_axis) + { + int y_motion = event->caxis.value * (config_input.gamepad_invert_y_axis ? -1 : 1); + + if (y_motion < -STICK_DEAD_ZONE) + emu_key_pressed(Up_Key); + else if (y_motion > STICK_DEAD_ZONE) + emu_key_pressed(Down_Key); + else + { + emu_key_released(Up_Key); + emu_key_released(Down_Key); + } + } + } + break; + + case SDL_KEYDOWN: + { + if (event->key.keysym.mod & KMOD_CTRL) + break; + + int key = event->key.keysym.scancode; + + if (key == SDL_SCANCODE_ESCAPE) + { + application_trigger_quit(); + break; + } + + if (key == SDL_SCANCODE_F11) + { + application_fullscreen = !application_fullscreen; + application_trigger_fullscreen(application_fullscreen); + break; + } + + if (key == config_input.key_left) + emu_key_pressed(Left_Key); + else if (key == config_input.key_right) + emu_key_pressed(Right_Key); + else if (key == config_input.key_up) + emu_key_pressed(Up_Key); + else if (key == config_input.key_down) + emu_key_pressed(Down_Key); + else if (key == config_input.key_b) + emu_key_pressed(B_Key); + else if (key == config_input.key_a) + emu_key_pressed(A_Key); + else if (key == config_input.key_select) + emu_key_pressed(Select_Key); + else if (key == config_input.key_start) + emu_key_pressed(Start_Key); + } + break; + + case SDL_KEYUP: + { + int key = event->key.keysym.scancode; + + if (key == config_input.key_left) + emu_key_released(Left_Key); + else if (key == config_input.key_right) + emu_key_released(Right_Key); + else if (key == config_input.key_up) + emu_key_released(Up_Key); + else if (key == config_input.key_down) + emu_key_released(Down_Key); + else if (key == config_input.key_b) + emu_key_released(B_Key); + else if (key == config_input.key_a) + emu_key_released(A_Key); + else if (key == config_input.key_select) + emu_key_released(Select_Key); + else if (key == config_input.key_start) + emu_key_released(Start_Key); + } + break; + } +} + +static void sdl_shortcuts_gui(const SDL_Event* event) +{ + if ((event->type == SDL_KEYDOWN) && (event->key.keysym.mod & KMOD_CTRL)) + { + int key = event->key.keysym.scancode; + + switch (key) + { + case SDL_SCANCODE_O: + gui_shortcut(gui_ShortcutOpenROM); + break; + case SDL_SCANCODE_R: + gui_shortcut(gui_ShortcutReset); + break; + case SDL_SCANCODE_P: + gui_shortcut(gui_ShortcutPause); + break; + case SDL_SCANCODE_F: + gui_shortcut(gui_ShortcutFFWD); + break; + case SDL_SCANCODE_L: + gui_shortcut(gui_ShortcutLoadState); + break; + case SDL_SCANCODE_S: + gui_shortcut(gui_ShortcutSaveState); + break; + case SDL_SCANCODE_M: + gui_shortcut(gui_ShortcutShowMainMenu); + break; + case SDL_SCANCODE_F5: + gui_shortcut(gui_ShortcutDebugContinue); + break; + case SDL_SCANCODE_F6: + gui_shortcut(gui_ShortcutDebugNextFrame); + break; + case SDL_SCANCODE_F8: + gui_shortcut(gui_ShortcutDebugRuntocursor); + break; + case SDL_SCANCODE_F9: + gui_shortcut(gui_ShortcutDebugBreakpoint); + break; + case SDL_SCANCODE_F10: + gui_shortcut(gui_ShortcutDebugStep); + break; + case SDL_SCANCODE_BACKSPACE: + gui_shortcut(gui_ShortcutDebugGoBack); + break; + } + } +} + +static void run_emulator(void) +{ + if (!emu_is_empty()) + { + static int i = 0; + i++; + + if (i > 20) + { + i = 0; + + char title[256]; + sprintf(title, "%s %s - %s", GEARBOY_TITLE, GEARBOY_VERSION, emu_get_core()->GetCartridge()->GetFileName()); + SDL_SetWindowTitle(sdl_window, title); + } + } + config_emulator.paused = emu_is_paused(); + emu_audio_sync = config_audio.sync; + emu_update(); +} + +static void render(void) +{ + renderer_begin_render(); + ImGui_ImplSDL2_NewFrame(sdl_window); + gui_render(); + renderer_render(); + renderer_end_render(); + + SDL_GL_SwapWindow(sdl_window); +} + +static void frame_throttle(void) +{ + if (emu_is_empty() || emu_is_paused() || config_emulator.ffwd) + { + float elapsed = (float)((frame_time_end - frame_time_start) * 1000) / SDL_GetPerformanceFrequency(); + + float min = 16.666f; + + if (config_emulator.ffwd) + { + switch (config_emulator.ffwd_speed) + { + case 0: + min = 16.666f / 1.5f; + break; + case 1: + min = 16.666f / 2.0f; + break; + case 2: + min = 16.666f / 2.5f; + break; + case 3: + min = 16.666f / 3.0f; + break; + default: + min = 0.0f; + } + } + + if (elapsed < min) + SDL_Delay((Uint32)(min - elapsed)); + } +} |
