cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

gui.cpp (46455B)


      1/*
      2 * Gearboy - Nintendo Game Boy Emulator
      3 * Copyright (C) 2012  Ignacio Sanchez
      4
      5 * This program is free software: you can redistribute it and/or modify
      6 * it under the terms of the GNU General Public License as published by
      7 * the Free Software Foundation, either version 3 of the License, or
      8 * any later version.
      9
     10 * This program is distributed in the hope that it will be useful,
     11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     13 * GNU General Public License for more details.
     14
     15 * You should have received a copy of the GNU General Public License
     16 * along with this program.  If not, see http://www.gnu.org/licenses/
     17 *
     18 */
     19
     20#include "imgui/imgui.h"
     21#include "imgui/imgui_memory_editor.h"
     22#include "imgui/fonts/RobotoMedium.h"
     23#include "FileBrowser/ImGuiFileBrowser.h"
     24#include "config.h"
     25#include "emu.h"
     26#include "../../src/gearboy.h"
     27#include "renderer.h"
     28#include "application.h"
     29#include "license.h"
     30#include "backers.h"
     31#include "gui_debug.h"
     32
     33#define GUI_IMPORT
     34#include "gui.h"
     35
     36static imgui_addons::ImGuiFileBrowser file_dialog;
     37static int main_menu_height;
     38static bool dialog_in_use = false;
     39static SDL_Scancode* configured_key;
     40static int* configured_button;
     41static ImVec4 custom_palette[config_max_custom_palettes][4];
     42static std::list<std::string> cheat_list;
     43static bool shortcut_open_rom = false;
     44static ImFont* default_font[4];
     45static char dmg_bootrom_path[4096] = "";
     46static char gbc_bootrom_path[4096] = "";
     47static char savefiles_path[4096] = "";
     48static char savestates_path[4096] = "";
     49static bool show_main_menu = true;
     50
     51static void main_menu(void);
     52static void main_window(void);
     53static void file_dialog_open_rom(void);
     54static void file_dialog_load_ram(void);
     55static void file_dialog_save_ram(void);
     56static void file_dialog_load_state(void);
     57static void file_dialog_save_state(void);
     58static void file_dialog_choose_save_file_path(void);
     59static void file_dialog_choose_savestate_path(void);
     60static void file_dialog_load_dmg_bootrom(void);
     61static void file_dialog_load_gbc_bootrom(void);
     62static void file_dialog_load_symbols(void);
     63static void keyboard_configuration_item(const char* text, SDL_Scancode* key);
     64static void gamepad_configuration_item(const char* text, int* button);
     65static void popup_modal_keyboard(void);
     66static void popup_modal_gamepad(void);
     67static void popup_modal_about(void);
     68static GB_Color color_float_to_int(ImVec4 color);
     69static ImVec4 color_int_to_float(GB_Color color);
     70static void update_palette(void);
     71static void push_recent_rom(std::string path);
     72static void menu_reset(void);
     73static void menu_pause(void);
     74static void menu_ffwd(void);
     75static void show_info(void);
     76static void show_fps(void);
     77static Cartridge::CartridgeTypes get_mbc(int index);
     78
     79void gui_init(void)
     80{
     81    IMGUI_CHECKVERSION();
     82    ImGui::CreateContext();
     83    ImGui::StyleColorsDark();
     84    ImGuiIO& io = ImGui::GetIO();
     85
     86    io.IniFilename = config_imgui_file_path;
     87
     88    io.FontGlobalScale /= application_display_scale;
     89
     90    gui_roboto_font = io.Fonts->AddFontFromMemoryCompressedTTF(RobotoMedium_compressed_data, RobotoMedium_compressed_size, 17.0f * application_display_scale, NULL, io.Fonts->GetGlyphRangesCyrillic());
     91
     92    ImFontConfig font_cfg;
     93
     94    for (int i = 0; i < 4; i++)
     95    {
     96        font_cfg.SizePixels = (13.0f + (i * 3)) * application_display_scale;
     97        default_font[i] = io.Fonts->AddFontDefault(&font_cfg);
     98    }
     99
    100    gui_default_font = default_font[config_debug.font_size];
    101
    102    update_palette();
    103
    104    emu_audio_volume(config_audio.enable ? 1.0f: 0.0f);
    105    emu_color_correction(config_video.color_correction);
    106
    107    strcpy(dmg_bootrom_path, config_emulator.dmg_bootrom_path.c_str());
    108    strcpy(gbc_bootrom_path, config_emulator.gbc_bootrom_path.c_str());
    109    strcpy(savefiles_path, config_emulator.savefiles_path.c_str());
    110    strcpy(savestates_path, config_emulator.savestates_path.c_str());
    111
    112    if (strlen(dmg_bootrom_path) > 0)
    113        emu_load_bootrom_dmg(dmg_bootrom_path);
    114    if (strlen(gbc_bootrom_path) > 0)
    115        emu_load_bootrom_gbc(gbc_bootrom_path);
    116
    117    emu_enable_bootrom_dmg(config_emulator.dmg_bootrom);
    118    emu_enable_bootrom_gbc(config_emulator.gbc_bootrom);
    119}
    120
    121void gui_destroy(void)
    122{
    123    ImGui::DestroyContext();
    124}
    125
    126void gui_render(void)
    127{
    128    ImGui::NewFrame();
    129
    130    gui_in_use = dialog_in_use;
    131
    132    main_menu();
    133
    134    if((!config_debug.debug && !emu_is_empty()) || (config_debug.debug && config_debug.show_gameboy))
    135        main_window();
    136
    137    gui_debug_windows();
    138
    139    ImGui::Render();
    140}
    141
    142void gui_shortcut(gui_ShortCutEvent event)
    143{
    144    switch (event)
    145    {  
    146    case gui_ShortcutOpenROM:
    147        shortcut_open_rom = true;
    148        break;
    149    case gui_ShortcutReset:
    150        menu_reset();
    151        break;
    152    case gui_ShortcutPause:
    153        menu_pause();
    154        break;
    155    case gui_ShortcutFFWD:
    156        config_emulator.ffwd = !config_emulator.ffwd;
    157        menu_ffwd();
    158        break;
    159    case gui_ShortcutSaveState:
    160        emu_save_state_slot(config_emulator.save_slot + 1);
    161        break;
    162    case gui_ShortcutLoadState:
    163        emu_load_state_slot(config_emulator.save_slot + 1);
    164        break;
    165    case gui_ShortcutDebugStep:
    166        if (config_debug.debug)
    167            emu_debug_step();
    168        break;
    169    case gui_ShortcutDebugContinue:
    170        if (config_debug.debug)
    171            emu_debug_continue();
    172        break;
    173    case gui_ShortcutDebugNextFrame:
    174        if (config_debug.debug)
    175            emu_debug_next_frame();
    176        break;
    177    case gui_ShortcutDebugBreakpoint:
    178        if (config_debug.debug)
    179            gui_debug_toggle_breakpoint();
    180        break;
    181    case gui_ShortcutDebugRuntocursor:
    182        if (config_debug.debug)
    183            gui_debug_runtocursor();
    184        break;
    185    case gui_ShortcutDebugGoBack:
    186        if (config_debug.debug)
    187            gui_debug_go_back();
    188        break;
    189    case gui_ShortcutShowMainMenu:
    190        show_main_menu = !show_main_menu;
    191        break;
    192    default:
    193        break;
    194    }
    195}
    196
    197void gui_load_rom(const char* path)
    198{
    199    push_recent_rom(path);
    200    emu_resume();
    201    emu_load_rom(path, config_emulator.force_dmg, get_mbc(config_emulator.mbc), config_emulator.force_gba);
    202    cheat_list.clear();
    203    emu_clear_cheats();
    204
    205    gui_debug_reset();
    206
    207    std::string str(path);
    208    str = str.substr(0, str.find_last_of("."));
    209    str += ".sym";
    210    gui_debug_load_symbols_file(str.c_str());
    211
    212    if (config_emulator.start_paused)
    213    {
    214        emu_pause();
    215        
    216        for (int i=0; i < (GAMEBOY_WIDTH * GAMEBOY_HEIGHT); i++)
    217        {
    218            emu_frame_buffer[i].red = 0;
    219            emu_frame_buffer[i].green = 0;
    220            emu_frame_buffer[i].blue = 0;
    221        }
    222    }
    223}
    224
    225static void main_menu(void)
    226{
    227    bool open_rom = false;
    228    bool open_ram = false;
    229    bool save_ram = false;
    230    bool open_state = false;
    231    bool save_state = false;
    232    bool open_about = false;
    233    bool open_symbols = false;
    234    bool choose_save_file_path = false;
    235    bool choose_savestates_path = false;
    236    bool open_dmg_bootrom = false;
    237    bool open_gbc_bootrom = false;
    238
    239    for (int i = 0; i < config_max_custom_palettes; i++)
    240        for (int c = 0; c < 4; c++)
    241            custom_palette[i][c] = color_int_to_float(config_video.color[i][c]);
    242    
    243    if (show_main_menu && ImGui::BeginMainMenuBar())
    244    {
    245        if (ImGui::BeginMenu(GEARBOY_TITLE))
    246        {
    247            gui_in_use = true;
    248
    249            if (ImGui::MenuItem("Open ROM...", "Ctrl+O"))
    250            {
    251                open_rom = true;
    252            }
    253
    254            if (ImGui::BeginMenu("Open Recent"))
    255            {
    256                for (int i = 0; i < config_max_recent_roms; i++)
    257                {
    258                    if (config_emulator.recent_roms[i].length() > 0)
    259                    {
    260                        if (ImGui::MenuItem(config_emulator.recent_roms[i].c_str()))
    261                        {
    262                            char rom_path[4096];
    263                            strcpy(rom_path, config_emulator.recent_roms[i].c_str());
    264                            gui_load_rom(rom_path);
    265                        }
    266                    }
    267                }
    268
    269                ImGui::EndMenu();
    270            }
    271
    272            ImGui::Separator();
    273            
    274            if (ImGui::MenuItem("Reset", "Ctrl+R"))
    275            {
    276                menu_reset();
    277            }
    278
    279            if (ImGui::MenuItem("Pause", "Ctrl+P", &config_emulator.paused))
    280            {
    281                menu_pause();
    282            }
    283
    284            ImGui::Separator();
    285
    286            if (ImGui::MenuItem("Fast Forward", "Ctrl+F", &config_emulator.ffwd))
    287            {
    288                menu_ffwd();
    289            }
    290
    291            if (ImGui::BeginMenu("Fast Forward Speed"))
    292            {
    293                ImGui::PushItemWidth(100.0f);
    294                ImGui::Combo("##fwd", &config_emulator.ffwd_speed, "X 1.5\0X 2\0X 2.5\0X 3\0Unlimited\0\0");
    295                ImGui::PopItemWidth();
    296                ImGui::EndMenu();
    297            }
    298
    299            ImGui::Separator();
    300
    301            if (ImGui::MenuItem("Save RAM As...")) 
    302            {
    303                save_ram = true;
    304            }
    305
    306            if (ImGui::MenuItem("Load RAM From..."))
    307            {
    308                open_ram = true;
    309            }
    310
    311            ImGui::Separator();
    312
    313            if (ImGui::MenuItem("Save State As...")) 
    314            {
    315                save_state = true;
    316            }
    317
    318            if (ImGui::MenuItem("Load State From..."))
    319            {
    320                open_state = true;
    321            }
    322
    323            ImGui::Separator();
    324           
    325            if (ImGui::BeginMenu("Save State Slot"))
    326            {
    327                ImGui::PushItemWidth(100.0f);
    328                ImGui::Combo("##slot", &config_emulator.save_slot, "Slot 1\0Slot 2\0Slot 3\0Slot 4\0Slot 5\0\0");
    329                ImGui::PopItemWidth();
    330                ImGui::EndMenu();
    331            }
    332
    333            if (ImGui::MenuItem("Save State", "Ctrl+S")) 
    334            {
    335                emu_save_state_slot(config_emulator.save_slot + 1);
    336            }
    337
    338            if (ImGui::MenuItem("Load State", "Ctrl+L"))
    339            {
    340                emu_load_state_slot(config_emulator.save_slot + 1);
    341            }
    342
    343            ImGui::Separator();
    344
    345            if (ImGui::MenuItem("Quit", "ESC"))
    346            {
    347                application_trigger_quit();
    348            }
    349
    350            ImGui::EndMenu();
    351        }
    352
    353        if (ImGui::BeginMenu("Emulator"))
    354        {
    355            gui_in_use = true;
    356
    357            if (ImGui::MenuItem("Force Game Boy (DMG)", "", &config_emulator.force_dmg))
    358            {
    359                if (config_emulator.force_dmg)
    360                    config_emulator.force_gba = false;
    361            }
    362
    363            if (ImGui::MenuItem("Force Game Boy Advance", "", &config_emulator.force_gba))
    364            {
    365                if (config_emulator.force_gba)
    366                    config_emulator.force_dmg = false;
    367            }
    368
    369            if (ImGui::BeginMenu("Memory Bank Controller"))
    370            {
    371                ImGui::PushItemWidth(140.0f);
    372                ImGui::Combo("##mbc", &config_emulator.mbc, "Auto\0ROM Only\0MBC 1\0MBC 2\0MBC 3\0MBC 5\0MBC 1 Multicart\0\0");
    373                ImGui::PopItemWidth();
    374                ImGui::EndMenu();
    375            }
    376
    377            ImGui::Separator();
    378
    379            if (ImGui::BeginMenu("DMG Bootrom"))
    380            {
    381                if (ImGui::MenuItem("Enable", "", &config_emulator.dmg_bootrom))
    382                {
    383                    emu_enable_bootrom_dmg(config_emulator.dmg_bootrom);
    384                }
    385                if (ImGui::IsItemHovered())
    386                    ImGui::SetTooltip("When the bootrom is enabled it will execute as in original hardware,\ncausing invalid roms to lock or forcing hardware like GB Pocket or GBA.");
    387                if (ImGui::MenuItem("Load Bootrom...")) 
    388                {
    389                    open_dmg_bootrom = true;
    390                }
    391                ImGui::PushItemWidth(350);
    392                if (ImGui::InputText("##dmg_bootrom_path", dmg_bootrom_path, IM_ARRAYSIZE(dmg_bootrom_path), ImGuiInputTextFlags_AutoSelectAll))
    393                {
    394                    config_emulator.dmg_bootrom_path.assign(dmg_bootrom_path);
    395                    emu_load_bootrom_dmg(dmg_bootrom_path);
    396                }
    397                ImGui::PopItemWidth();
    398                ImGui::EndMenu();
    399            }
    400
    401            if (ImGui::BeginMenu("GBC Bootrom"))
    402            {
    403                if (ImGui::MenuItem("Enable", "", &config_emulator.gbc_bootrom))
    404                {
    405                    emu_enable_bootrom_gbc(config_emulator.gbc_bootrom);
    406                }
    407                if (ImGui::IsItemHovered())
    408                    ImGui::SetTooltip("When the bootrom is enabled it will execute as in original hardware,\ncausing invalid roms to lock or forcing hardware like GB Pocket or GBA.");
    409                if (ImGui::MenuItem("Load Bootrom...")) 
    410                {
    411                    open_gbc_bootrom = true;
    412                }
    413                ImGui::PushItemWidth(350);
    414                if (ImGui::InputText("##gbc_bootrom_path", gbc_bootrom_path, IM_ARRAYSIZE(gbc_bootrom_path), ImGuiInputTextFlags_AutoSelectAll))
    415                {
    416                    config_emulator.gbc_bootrom_path.assign(gbc_bootrom_path);
    417                    emu_load_bootrom_gbc(gbc_bootrom_path);
    418                }
    419                ImGui::PopItemWidth();
    420                ImGui::EndMenu();
    421            }
    422
    423            ImGui::Separator();
    424
    425            ImGui::MenuItem("Start Paused", "", &config_emulator.start_paused);
    426
    427            ImGui::Separator();
    428
    429            if (ImGui::BeginMenu("Save File Location"))
    430            {
    431                ImGui::PushItemWidth(220.0f);
    432                if (ImGui::Combo("##savefile_option", &config_emulator.savefiles_dir_option, "Save Files In Custom Folder\0Save Files In ROM Folder\0\0"))
    433                {
    434                    emu_savefiles_dir_option = config_emulator.savefiles_dir_option;
    435                }
    436
    437                if (config_emulator.savefiles_dir_option == 0)
    438                {
    439                    if (ImGui::MenuItem("Choose Save File Folder..."))
    440                    {
    441                        choose_save_file_path = true;
    442                    }
    443
    444                    ImGui::PushItemWidth(350);
    445                    if (ImGui::InputText("##savefile_path", savefiles_path, IM_ARRAYSIZE(savefiles_path), ImGuiInputTextFlags_AutoSelectAll))
    446                    {
    447                        config_emulator.savefiles_path.assign(savefiles_path);
    448                        strcpy(emu_savefiles_path, savefiles_path);
    449                    }
    450                    ImGui::PopItemWidth();
    451                }
    452
    453                ImGui::EndMenu();
    454            }
    455
    456            if (ImGui::BeginMenu("Save State Location"))
    457            {
    458                ImGui::PushItemWidth(220.0f);
    459                if (ImGui::Combo("##savestate_option", &config_emulator.savestates_dir_option, "Savestates In Custom Folder\0Savestates In ROM Folder\0\0"))
    460                {
    461                    emu_savestates_dir_option = config_emulator.savestates_dir_option;
    462                }
    463
    464                if (config_emulator.savestates_dir_option == 0)
    465                {
    466                    if (ImGui::MenuItem("Choose Savestate Folder..."))
    467                    {
    468                        choose_savestates_path = true;
    469                    }
    470
    471                    ImGui::PushItemWidth(350);
    472                    if (ImGui::InputText("##savestate_path", savestates_path, IM_ARRAYSIZE(savestates_path), ImGuiInputTextFlags_AutoSelectAll))
    473                    {
    474                        config_emulator.savestates_path.assign(savestates_path);
    475                        strcpy(emu_savestates_path, savestates_path);
    476                    }
    477                    ImGui::PopItemWidth();
    478                }
    479
    480                ImGui::EndMenu();
    481            }
    482
    483            ImGui::Separator();
    484
    485            ImGui::MenuItem("Show ROM info", "", &config_emulator.show_info);
    486
    487            ImGui::Separator();
    488            
    489            ImGui::SetNextWindowSizeConstraints({300.0f, 200.0f}, {300.0f, 500.0f});
    490            if (ImGui::BeginMenu("Cheats"))
    491            {
    492                ImGui::Text("Game Genie or GameShark codes\n(one code per line):");
    493
    494                ImGui::Columns(2, "cheats", false);
    495
    496                static char cheat_buffer[20*50] = "";
    497                ImGui::PushItemWidth(150);
    498                ImGui::InputTextMultiline("", cheat_buffer, IM_ARRAYSIZE(cheat_buffer));
    499                ImGui::PopItemWidth();
    500
    501                ImGui::NextColumn();
    502
    503                if (ImGui::Button("Add Cheat Codes"))
    504                {
    505                    std::string cheats = cheat_buffer;
    506                    std::istringstream ss(cheats);
    507                    std::string cheat;
    508
    509                    while (getline(ss, cheat))
    510                    {
    511                        if ((cheat_list.size() < 50) && ((cheat.length() == 7) || (cheat.length() == 8) || (cheat.length() == 11)))
    512                        {
    513                            cheat_list.push_back(cheat);
    514                            emu_add_cheat(cheat.c_str());
    515                            cheat_buffer[0] = 0;
    516                        }
    517                    }
    518                }
    519
    520                if (cheat_list.size() > 0)
    521                {
    522                    if (ImGui::Button("Clear All"))
    523                    {
    524                        cheat_list.clear();
    525                        emu_clear_cheats();
    526                    }
    527                }
    528
    529                ImGui::Columns(1);
    530
    531                std::list<std::string>::iterator it;
    532
    533                for (it = cheat_list.begin(); it != cheat_list.end(); it++)
    534                {
    535                    if ((it->length() == 7) || (it->length() == 11))
    536                        ImGui::Text("Game Genie: %s", it->c_str());
    537                    else
    538                        ImGui::Text("GameShark: %s", it->c_str());
    539                }                
    540
    541                ImGui::EndMenu();
    542            }
    543
    544            ImGui::EndMenu();
    545        }
    546
    547        if (ImGui::BeginMenu("Video"))
    548        {
    549            gui_in_use = true;
    550
    551            if (ImGui::MenuItem("Full Screen", "F11", &application_fullscreen))
    552            {
    553                application_trigger_fullscreen(application_fullscreen);
    554            }
    555
    556            ImGui::MenuItem("Show Menu", "CTRL+M", &show_main_menu);
    557
    558            ImGui::Separator();
    559
    560            if (ImGui::BeginMenu("Scale"))
    561            {
    562                ImGui::PushItemWidth(100.0f);
    563                ImGui::Combo("##scale", &config_video.scale, "Auto\0Zoom X1\0Zoom X2\0Zoom X3\0Zoom X4\0\0");
    564                ImGui::PopItemWidth();
    565                ImGui::EndMenu();
    566            }
    567
    568            if (ImGui::BeginMenu("Aspect Ratio"))
    569            {
    570                ImGui::PushItemWidth(130.0f);
    571                ImGui::Combo("##ratio", &config_video.ratio, "Game Boy\0Standard (4:3)\0Wide (16:9)\0Fit Window\0\0");
    572                ImGui::PopItemWidth();
    573                ImGui::EndMenu();
    574            }
    575
    576            ImGui::Separator();
    577
    578            if (ImGui::MenuItem("Vertical Sync", "", &config_video.sync))
    579            {
    580                SDL_GL_SetSwapInterval(config_video.sync ? 1 : 0);
    581
    582                if (config_video.sync)
    583                {
    584                    config_audio.sync = true;
    585                    emu_audio_reset();
    586                }
    587            }
    588
    589            ImGui::MenuItem("Show FPS", "", &config_video.fps);
    590
    591            ImGui::Separator();
    592
    593            ImGui::MenuItem("Bilinear Filtering", "", &config_video.bilinear);
    594
    595            if (ImGui::MenuItem("Color Correction (GBC)", "", &config_video.color_correction))
    596            {
    597                emu_color_correction(config_video.color_correction);
    598            }
    599
    600            if (ImGui::BeginMenu("Screen Ghosting"))
    601            {
    602                ImGui::MenuItem("Enable Screen Ghosting", "", &config_video.mix_frames);
    603                ImGui::SliderFloat("##screen_ghosting", &config_video.mix_frames_intensity, 0.0f, 1.0f, "Intensity = %.2f");
    604                ImGui::EndMenu();
    605            }
    606
    607            if (ImGui::BeginMenu("Dot Matrix"))
    608            {
    609                ImGui::MenuItem("Enable Dot Matrix", "", &config_video.matrix);
    610                ImGui::SliderFloat("##dot_matrix", &config_video.matrix_intensity, 0.0f, 1.0f, "Intensity = %.2f");
    611                ImGui::EndMenu();
    612            }
    613            
    614            ImGui::Separator();
    615
    616            if (ImGui::BeginMenu("Palette"))
    617            {
    618                ImGui::PushItemWidth(130.0f);
    619                if (ImGui::Combo("##palette", &config_video.palette, "Original\0Sharp\0Black & White\0Autumn\0Soft\0Slime\0Custom 1\0Custom 2\0Custom 3\0Custom 4\0Custom 5\0\0", 11))
    620                {
    621                    update_palette();
    622                }
    623                ImGui::PopItemWidth();
    624                ImGui::EndMenu();
    625            }
    626
    627            if (ImGui::BeginMenu("Custom Palettes"))
    628            {
    629
    630            for (int i = 0; i < config_max_custom_palettes; i++)
    631            {
    632                char menu_label[256];
    633                sprintf(menu_label, "Palette %i", i + 1);
    634
    635                if (ImGui::BeginMenu(menu_label))
    636                {
    637                    if (ImGui::ColorEdit3("Color #1", (float*)&custom_palette[i][0], ImGuiColorEditFlags_NoInputs))
    638                    {
    639                        update_palette();
    640                    }
    641                    if (ImGui::ColorEdit3("Color #2", (float*)&custom_palette[i][1], ImGuiColorEditFlags_NoInputs))
    642                    {
    643                        update_palette();
    644                    }
    645                    if (ImGui::ColorEdit3("Color #3", (float*)&custom_palette[i][2], ImGuiColorEditFlags_NoInputs))
    646                    {
    647                        update_palette();
    648                    }
    649                    if (ImGui::ColorEdit3("Color #4", (float*)&custom_palette[i][3], ImGuiColorEditFlags_NoInputs))
    650                    {
    651                        update_palette();
    652                    }
    653                    ImGui::EndMenu();
    654                }
    655            }
    656
    657            ImGui::EndMenu();
    658            }
    659
    660            ImGui::EndMenu();
    661        }
    662
    663        if (ImGui::BeginMenu("Input"))
    664        {
    665            gui_in_use = true;
    666
    667            if (ImGui::BeginMenu("Keyboard Configuration"))
    668            {
    669                keyboard_configuration_item("Left:", &config_input.key_left);
    670                keyboard_configuration_item("Right:", &config_input.key_right);
    671                keyboard_configuration_item("Up:", &config_input.key_up);
    672                keyboard_configuration_item("Down:", &config_input.key_down);
    673                keyboard_configuration_item("A:", &config_input.key_a);
    674                keyboard_configuration_item("B:", &config_input.key_b);
    675                keyboard_configuration_item("Start:", &config_input.key_start);
    676                keyboard_configuration_item("Select:", &config_input.key_select);
    677
    678                popup_modal_keyboard();                 
    679                
    680                ImGui::EndMenu();
    681            }
    682
    683            ImGui::Separator();
    684
    685            if (ImGui::BeginMenu("Gamepad"))
    686            {
    687                ImGui::MenuItem("Enable Gamepad", "", &config_input.gamepad);
    688
    689                if (ImGui::BeginMenu("Directional Controls"))
    690                {
    691                    ImGui::PushItemWidth(150.0f);
    692                    ImGui::Combo("##directional", &config_input.gamepad_directional, "D-pad\0Left Analog Stick\0\0");
    693                    ImGui::PopItemWidth();
    694                    ImGui::EndMenu();
    695                }
    696                
    697                if (ImGui::BeginMenu("Button Configuration"))
    698                {
    699                    gamepad_configuration_item("A:", &config_input.gamepad_a);
    700                    gamepad_configuration_item("B:", &config_input.gamepad_b);
    701                    gamepad_configuration_item("START:", &config_input.gamepad_start);
    702                    gamepad_configuration_item("SELECT:", &config_input.gamepad_select);
    703
    704                    popup_modal_gamepad();                 
    705
    706                    ImGui::EndMenu();
    707                }
    708                ImGui::EndMenu();
    709            }
    710
    711            ImGui::EndMenu();
    712        }
    713
    714        if (ImGui::BeginMenu("Audio"))
    715        {
    716            gui_in_use = true;
    717
    718            if (ImGui::MenuItem("Enable Audio", "", &config_audio.enable))
    719            {
    720                emu_audio_volume(config_audio.enable ? 1.0f: 0.0f);
    721            }
    722
    723            if (ImGui::MenuItem("Sync With Emulator", "", &config_audio.sync))
    724            {
    725                config_emulator.ffwd = false;
    726
    727                if (!config_audio.sync)
    728                {
    729                    config_video.sync = false;
    730                    SDL_GL_SetSwapInterval(0);
    731                }
    732            }
    733
    734            ImGui::EndMenu();
    735        }
    736
    737        if (ImGui::BeginMenu("Debug"))
    738        {
    739            gui_in_use = true;
    740
    741            if (ImGui::MenuItem("Enable", "", &config_debug.debug))
    742            {
    743                if (config_debug.debug)
    744                    emu_debug_step();
    745                else
    746                    emu_debug_continue();
    747            }
    748
    749            ImGui::Separator();
    750
    751            if (ImGui::MenuItem("Step Over", "CTRL + F10", (void*)0, config_debug.debug))
    752            {
    753                emu_debug_step();
    754            }
    755
    756            if (ImGui::MenuItem("Step Frame", "CTRL + F6", (void*)0, config_debug.debug))
    757            {
    758                emu_debug_next_frame();
    759            }
    760
    761            if (ImGui::MenuItem("Continue", "CTRL + F5", (void*)0, config_debug.debug))
    762            {
    763                emu_debug_continue();
    764            }
    765
    766            if (ImGui::MenuItem("Run To Cursor", "CTRL + F8", (void*)0, config_debug.debug))
    767            {
    768                gui_debug_runtocursor();
    769            }
    770
    771            ImGui::Separator();
    772
    773            if (ImGui::MenuItem("Go Back", "CTRL + BACKSPACE", (void*)0, config_debug.debug))
    774            {
    775                gui_debug_go_back();
    776            }
    777
    778            ImGui::Separator();
    779
    780            if (ImGui::MenuItem("Toggle Breakpoint", "CTRL + F9", (void*)0, config_debug.debug))
    781            {
    782                gui_debug_toggle_breakpoint();
    783            }
    784
    785            if (ImGui::MenuItem("Clear All Processor Breakpoints", 0, (void*)0, config_debug.debug))
    786            {
    787                gui_debug_reset_breakpoints_cpu();
    788            }
    789
    790            if (ImGui::MenuItem("Clear All Memory Breakpoints", 0, (void*)0, config_debug.debug))
    791            {
    792                gui_debug_reset_breakpoints_mem();
    793            }
    794
    795            ImGui::MenuItem("Disable All Processor Breakpoints", 0, &emu_debug_disable_breakpoints_cpu, config_debug.debug);
    796
    797            ImGui::MenuItem("Disable All Memory Breakpoints", 0, &emu_debug_disable_breakpoints_mem, config_debug.debug);
    798
    799            ImGui::Separator();
    800
    801            if (ImGui::BeginMenu("Font Size", config_debug.debug))
    802            {
    803                ImGui::PushItemWidth(110.0f);
    804                if (ImGui::Combo("##font", &config_debug.font_size, "Very Small\0Small\0Medium\0Large\0\0"))
    805                {
    806                    gui_default_font = default_font[config_debug.font_size];
    807                }
    808                ImGui::PopItemWidth();
    809                ImGui::EndMenu();
    810            }
    811
    812            ImGui::Separator();
    813
    814            ImGui::MenuItem("Show Game Boy Screen", "", &config_debug.show_gameboy, config_debug.debug);
    815
    816            ImGui::MenuItem("Show Disassembler", "", &config_debug.show_disassembler, config_debug.debug);
    817
    818            ImGui::MenuItem("Show Processor Status", "", &config_debug.show_processor, config_debug.debug);
    819
    820            ImGui::MenuItem("Show Memory Editor", "", &config_debug.show_memory, config_debug.debug);
    821
    822            ImGui::MenuItem("Show IO Map", "", &config_debug.show_iomap, config_debug.debug);
    823
    824            ImGui::MenuItem("Show VRAM Viewer", "", &config_debug.show_video, config_debug.debug);
    825
    826            ImGui::MenuItem("Show Sound Registers", "", &config_debug.show_audio, config_debug.debug);
    827
    828            ImGui::Separator();
    829
    830            if (ImGui::MenuItem("Load Symbols...", "", (void*)0, config_debug.debug))
    831            {
    832                open_symbols = true;
    833            }
    834
    835            if (ImGui::MenuItem("Clear Symbols", "", (void*)0, config_debug.debug))
    836            {
    837                gui_debug_reset_symbols();
    838            }
    839
    840            ImGui::EndMenu();
    841        }
    842
    843        if (ImGui::BeginMenu("About"))
    844        {
    845            gui_in_use = true;
    846
    847            if (ImGui::MenuItem("About " GEARBOY_TITLE " " GEARBOY_VERSION " ..."))
    848            {
    849               open_about = true;
    850            }
    851            ImGui::EndMenu();
    852        }
    853
    854        main_menu_height = (int)ImGui::GetWindowSize().y;
    855
    856        ImGui::EndMainMenuBar();       
    857    }
    858
    859    if (open_rom || shortcut_open_rom)
    860    {
    861        shortcut_open_rom = false;
    862        ImGui::OpenPopup("Open ROM...");
    863    }
    864
    865    if (open_ram)
    866        ImGui::OpenPopup("Load RAM From...");
    867
    868    if (save_ram)
    869        ImGui::OpenPopup("Save RAM As...");
    870
    871    if (open_state)
    872        ImGui::OpenPopup("Load State From...");
    873    
    874    if (save_state)
    875        ImGui::OpenPopup("Save State As...");
    876
    877    if (choose_save_file_path)
    878        ImGui::OpenPopup("Choose Save File Folder...");
    879
    880    if (choose_savestates_path)
    881        ImGui::OpenPopup("Choose Savestate Folder...");
    882
    883    if (open_dmg_bootrom)
    884        ImGui::OpenPopup("Load DMG Bootrom From...");
    885    
    886    if (open_gbc_bootrom)
    887        ImGui::OpenPopup("Load GBC Bootrom From...");
    888
    889    if (open_symbols)
    890        ImGui::OpenPopup("Load Symbols File...");
    891
    892    if (open_about)
    893    {
    894        dialog_in_use = true;
    895        ImGui::OpenPopup("About " GEARBOY_TITLE);
    896    }
    897    
    898    popup_modal_about();
    899    file_dialog_open_rom();
    900    file_dialog_load_ram();
    901    file_dialog_save_ram();
    902    file_dialog_load_state();
    903    file_dialog_save_state();
    904    file_dialog_choose_save_file_path();
    905    file_dialog_choose_savestate_path();
    906    file_dialog_load_dmg_bootrom();
    907    file_dialog_load_gbc_bootrom();
    908    file_dialog_load_symbols();
    909
    910    for (int i = 0; i < config_max_custom_palettes; i++)
    911        for (int c = 0; c < 4; c++)
    912            config_video.color[i][c] = color_float_to_int(custom_palette[i][c]);
    913}
    914
    915static void main_window(void)
    916{
    917    int w = (int)ImGui::GetIO().DisplaySize.x;
    918    int h = (int)ImGui::GetIO().DisplaySize.y - (show_main_menu ? main_menu_height : 0);
    919
    920    int selected_ratio = config_debug.debug ? 0 : config_video.ratio;
    921    float ratio = (float)GAMEBOY_WIDTH / (float)GAMEBOY_HEIGHT;
    922
    923    switch (selected_ratio)
    924    {
    925        case 0:
    926            ratio = (float)GAMEBOY_WIDTH / (float)GAMEBOY_HEIGHT;
    927            break;
    928        case 1:
    929            ratio = 4.0f / 3.0f;
    930            break;
    931        case 2:
    932            ratio = 16.0f / 9.0f;
    933            break;
    934        case 3:
    935            ratio = (float)w / (float)h;
    936            break;
    937        default:
    938            ratio = (float)GAMEBOY_WIDTH / (float)GAMEBOY_HEIGHT;
    939    }
    940
    941    int w_corrected = (int)(selected_ratio == 3 ? w : GAMEBOY_HEIGHT * ratio);
    942    int h_corrected = selected_ratio == 3 ? h : GAMEBOY_HEIGHT;
    943
    944    int factor = 0;
    945
    946    if (config_video.scale > 0)
    947    {
    948        factor = config_video.scale;
    949    }
    950    else if (config_debug.debug)
    951    {
    952        factor = 1;
    953    }
    954    else
    955    {
    956        int factor_w = w / w_corrected;
    957        int factor_h = h / h_corrected;
    958        factor = (factor_w < factor_h) ? factor_w : factor_h;
    959    }
    960
    961    int main_window_width = w_corrected * factor;
    962    int main_window_height = h_corrected * factor;
    963
    964    int window_x = (w - (w_corrected * factor)) / 2;
    965    int window_y = ((h - (h_corrected * factor)) / 2) + (show_main_menu ? main_menu_height : 0);
    966
    967    ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
    968    ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
    969
    970    ImGuiWindowFlags flags = ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar;
    971    
    972    if (config_debug.debug)
    973    {
    974        flags |= ImGuiWindowFlags_AlwaysAutoResize;
    975
    976        ImGui::SetNextWindowPos(ImVec2(7, 32), ImGuiCond_FirstUseEver);
    977
    978        ImGui::Begin(emu_is_cgb() ? "Game Boy Color###debug_output" : "Game Boy###debug_output", &config_debug.show_gameboy, flags);
    979    }
    980    else
    981    {
    982        ImGui::SetNextWindowSize(ImVec2((float)main_window_width, (float)main_window_height));
    983        ImGui::SetNextWindowPos(ImVec2((float)window_x, (float)window_y));
    984        ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
    985
    986        flags |= ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoNav;
    987
    988        ImGui::Begin(GEARBOY_TITLE, 0, flags);
    989    }
    990
    991    ImGui::Image((void*)(intptr_t)renderer_emu_texture, ImVec2((float)main_window_width, (float)main_window_height));
    992
    993    if (config_video.fps)
    994        show_fps();
    995
    996    if (config_emulator.show_info)
    997        show_info();
    998
    999    ImGui::End();
   1000
   1001    ImGui::PopStyleVar();
   1002    ImGui::PopStyleVar();
   1003
   1004    if (!config_debug.debug)
   1005    {
   1006        
   1007        ImGui::PopStyleVar();
   1008    }
   1009}
   1010
   1011static void file_dialog_open_rom(void)
   1012{
   1013    if(file_dialog.showFileDialog("Open ROM...", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ImVec2(700, 400), "*.*,.gb,.gbc,.cgb,.sgb,.dmg,.rom,.zip", &dialog_in_use))
   1014    {
   1015        gui_load_rom(file_dialog.selected_path.c_str());
   1016    }
   1017}
   1018
   1019static void file_dialog_load_ram(void)
   1020{
   1021    if(file_dialog.showFileDialog("Load RAM From...", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ImVec2(700, 310), ".sav,*.*", &dialog_in_use))
   1022    {
   1023        emu_load_ram(file_dialog.selected_path.c_str(), config_emulator.force_dmg, get_mbc(config_emulator.mbc), config_emulator.force_gba);
   1024    }
   1025}
   1026
   1027static void file_dialog_save_ram(void)
   1028{
   1029    if(file_dialog.showFileDialog("Save RAM As...", imgui_addons::ImGuiFileBrowser::DialogMode::SAVE, ImVec2(700, 310), ".sav", &dialog_in_use))
   1030    {
   1031        std::string save_path = file_dialog.selected_path;
   1032
   1033        if (save_path.rfind(file_dialog.ext) != (save_path.size()-file_dialog.ext.size()))
   1034        {
   1035            save_path += file_dialog.ext;
   1036        }
   1037
   1038        emu_save_ram(save_path.c_str());
   1039    }
   1040}
   1041
   1042static void file_dialog_load_state(void)
   1043{
   1044    if(file_dialog.showFileDialog("Load State From...", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ImVec2(700, 310), ".state,*.*", &dialog_in_use))
   1045    {
   1046        emu_load_state_file(file_dialog.selected_path.c_str());
   1047    }
   1048}
   1049
   1050static void file_dialog_save_state(void)
   1051{
   1052    if(file_dialog.showFileDialog("Save State As...", imgui_addons::ImGuiFileBrowser::DialogMode::SAVE, ImVec2(700, 310), ".state", &dialog_in_use))
   1053    {
   1054        std::string state_path = file_dialog.selected_path;
   1055
   1056        if (state_path.rfind(file_dialog.ext) != (state_path.size()-file_dialog.ext.size()))
   1057        {
   1058            state_path += file_dialog.ext;
   1059        }
   1060
   1061        emu_save_state_file(state_path.c_str());
   1062    }
   1063}
   1064
   1065static void file_dialog_choose_save_file_path(void)
   1066{
   1067    if(file_dialog.showFileDialog("Choose Save File Folder...", imgui_addons::ImGuiFileBrowser::DialogMode::SELECT, ImVec2(700, 310), "*.*", &dialog_in_use))
   1068    {
   1069        strcpy(savefiles_path, file_dialog.selected_path.c_str());
   1070        config_emulator.savefiles_path.assign(file_dialog.selected_path);
   1071    }
   1072}
   1073
   1074static void file_dialog_choose_savestate_path(void)
   1075{
   1076    if(file_dialog.showFileDialog("Choose Savestate Folder...", imgui_addons::ImGuiFileBrowser::DialogMode::SELECT, ImVec2(700, 310), "*.*", &dialog_in_use))
   1077    {
   1078        strcpy(savestates_path, file_dialog.selected_path.c_str());
   1079        config_emulator.savestates_path.assign(file_dialog.selected_path);
   1080    }
   1081}
   1082
   1083static void file_dialog_load_dmg_bootrom(void)
   1084{
   1085    if(file_dialog.showFileDialog("Load DMG Bootrom From...", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ImVec2(700, 310), ".bin,.gb,*.*", &dialog_in_use))
   1086    {
   1087        strcpy(dmg_bootrom_path, file_dialog.selected_path.c_str());
   1088        config_emulator.dmg_bootrom_path.assign(file_dialog.selected_path);
   1089
   1090        emu_load_bootrom_dmg(dmg_bootrom_path);
   1091    }
   1092}
   1093
   1094static void file_dialog_load_gbc_bootrom(void)
   1095{
   1096    if(file_dialog.showFileDialog("Load GBC Bootrom From...", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ImVec2(700, 310), ".bin,.gbc,*.*", &dialog_in_use))
   1097    {
   1098        strcpy(gbc_bootrom_path, file_dialog.selected_path.c_str());
   1099        config_emulator.gbc_bootrom_path.assign(file_dialog.selected_path);
   1100
   1101        emu_load_bootrom_gbc(gbc_bootrom_path);
   1102    }
   1103}
   1104
   1105static void file_dialog_load_symbols(void)
   1106{
   1107    if(file_dialog.showFileDialog("Load Symbols File...", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ImVec2(700, 400), ".sym,*.*", &dialog_in_use))
   1108    {
   1109        gui_debug_reset_symbols();
   1110        gui_debug_load_symbols_file(file_dialog.selected_path.c_str());
   1111    }
   1112}
   1113
   1114static void keyboard_configuration_item(const char* text, SDL_Scancode* key)
   1115{
   1116    ImGui::Text("%s", text);
   1117    ImGui::SameLine(90);
   1118
   1119    char button_label[256];
   1120    sprintf(button_label, "%s##%s", SDL_GetScancodeName(*key), text);
   1121
   1122    if (ImGui::Button(button_label, ImVec2(70,0)))
   1123    {
   1124        configured_key = key;
   1125        ImGui::OpenPopup("Keyboard Configuration");
   1126    }
   1127}
   1128
   1129static void gamepad_configuration_item(const char* text, int* button)
   1130{
   1131    ImGui::Text("%s", text);
   1132    ImGui::SameLine(70);
   1133
   1134    static const char* gamepad_names[16] = {"A", "B", "X" ,"Y", "BACK", "GUID", "START", "L3", "R3", "L1", "R1", "UP", "DOWN", "LEFT", "RIGHT", "15"};
   1135
   1136    char button_label[256];
   1137    sprintf(button_label, "%s##%s", gamepad_names[*button], text);
   1138
   1139    if (ImGui::Button(button_label, ImVec2(70,0)))
   1140    {
   1141        configured_button = button;
   1142        ImGui::OpenPopup("Gamepad Configuration");
   1143    }
   1144}
   1145
   1146static void popup_modal_keyboard(void)
   1147{
   1148    if (ImGui::BeginPopupModal("Keyboard Configuration", NULL, ImGuiWindowFlags_AlwaysAutoResize))
   1149    {
   1150        ImGui::Text("Press any key...\n\n");
   1151        ImGui::Separator();
   1152
   1153        for (int i = 0; i < IM_ARRAYSIZE(ImGui::GetIO().KeysDown); i++)
   1154        {
   1155            if (ImGui::IsKeyPressed(i))
   1156            {
   1157                SDL_Scancode key = (SDL_Scancode)i;
   1158
   1159                if ((key != SDL_SCANCODE_LCTRL) && (key != SDL_SCANCODE_RCTRL) && (key != SDL_SCANCODE_CAPSLOCK))
   1160                {
   1161                    *configured_key = key;
   1162                    ImGui::CloseCurrentPopup();
   1163                    break;
   1164                }
   1165            }
   1166        }
   1167
   1168        if (ImGui::Button("Cancel", ImVec2(120, 0)))
   1169        {
   1170            ImGui::CloseCurrentPopup();
   1171        }
   1172        ImGui::EndPopup();
   1173    }
   1174}
   1175
   1176static void popup_modal_gamepad(void)
   1177{
   1178    if (ImGui::BeginPopupModal("Gamepad Configuration", NULL, ImGuiWindowFlags_AlwaysAutoResize))
   1179    {
   1180        ImGui::Text("Press any button in your gamepad...\n\n");
   1181        ImGui::Separator();
   1182
   1183        for (int i = 0; i < SDL_CONTROLLER_BUTTON_MAX; i++)
   1184        {
   1185            if (SDL_GameControllerGetButton(application_gamepad, (SDL_GameControllerButton)i))
   1186            {
   1187                *configured_button = i;
   1188                ImGui::CloseCurrentPopup();
   1189                break;
   1190            }
   1191        }
   1192
   1193        if (ImGui::Button("Cancel", ImVec2(120, 0)))
   1194        {
   1195            ImGui::CloseCurrentPopup();
   1196        }
   1197        ImGui::EndPopup();
   1198    }
   1199}
   1200
   1201static void popup_modal_about(void)
   1202{
   1203    if (ImGui::BeginPopupModal("About " GEARBOY_TITLE, NULL, ImGuiWindowFlags_AlwaysAutoResize))
   1204    {
   1205        ImGui::Text("%s %s", GEARBOY_TITLE, GEARBOY_VERSION);
   1206        ImGui::Text("Build: %s", EMULATOR_BUILD);
   1207
   1208        ImGui::Separator();
   1209
   1210        ImGui::Text("By Ignacio Sánchez (twitter.com/drhelius)");
   1211        ImGui::Text("%s is licensed under the GPL-3.0 License, see LICENSE for more information.", GEARBOY_TITLE);
   1212
   1213        ImGui::Separator();
   1214
   1215        if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None))
   1216        {
   1217            if (ImGui::BeginTabItem("Special thanks to"))
   1218            {
   1219                ImGui::BeginChild("backers", ImVec2(0, 100), false, ImGuiWindowFlags_AlwaysVerticalScrollbar);
   1220                ImGui::Text("%s", BACKERS_STR);
   1221                ImGui::EndChild();
   1222                ImGui::EndTabItem();
   1223            }
   1224            if (ImGui::BeginTabItem("LICENSE"))
   1225            {
   1226                ImGui::BeginChild("license", ImVec2(0, 100), false, ImGuiWindowFlags_AlwaysVerticalScrollbar);
   1227                ImGui::TextUnformatted(GPL_LICENSE_STR);
   1228                ImGui::EndChild();
   1229                ImGui::EndTabItem();
   1230            }
   1231            ImGui::EndTabBar();
   1232        }
   1233
   1234        ImGui::Separator();
   1235        
   1236        #ifdef _WIN64
   1237        ImGui::Text("Windows 64 bit build");
   1238        #elif defined(_WIN32)
   1239        ImGui::Text("Windows 32 bit build");
   1240        #endif
   1241        #ifdef __linux__
   1242        ImGui::Text("Linux build");
   1243        #endif
   1244        #ifdef __APPLE__
   1245        ImGui::Text("macOS build");
   1246        #endif
   1247        #ifdef _MSC_VER
   1248        ImGui::Text("Microsoft C++ %d.", _MSC_VER);
   1249        #endif
   1250        #ifdef __MINGW32__
   1251        ImGui::Text("MinGW 32 bit (%d.%d)", __MINGW32_MAJOR_VERSION, __MINGW32_MINOR_VERSION);
   1252        #endif
   1253        #ifdef __MINGW64__
   1254        ImGui::Text("MinGW 64 bit (%d.%d)", __MINGW64_VERSION_MAJOR, __MINGW64_VERSION_MINOR);
   1255        #endif
   1256        #if defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER)
   1257        ImGui::Text("GCC %d.%d.%d", (int)__GNUC__, (int)__GNUC_MINOR__, (int)__GNUC_PATCHLEVEL__);
   1258        #endif
   1259        #ifdef __clang_version__
   1260        ImGui::Text("Clang %s", __clang_version__);
   1261        #endif
   1262
   1263        ImGui::Separator();
   1264
   1265        #ifdef DEBUG
   1266        ImGui::Text("define: DEBUG");
   1267        #endif
   1268        #ifdef DEBUG_GEARBOY
   1269        ImGui::Text("define: DEBUG_GEARBOY");
   1270        #endif
   1271        #ifdef __cplusplus
   1272        ImGui::Text("define: __cplusplus = %d", (int)__cplusplus);
   1273        #endif
   1274        #ifdef __STDC__
   1275        ImGui::Text("define: __STDC__ = %d", (int)__STDC__);
   1276        #endif
   1277        #ifdef __STDC_VERSION__
   1278        ImGui::Text("define: __STDC_VERSION__ = %d", (int)__STDC_VERSION__);
   1279        #endif
   1280        
   1281        ImGui::Separator();
   1282
   1283        ImGui::Text("SDL %d.%d.%d (build)", application_sdl_build_version.major, application_sdl_build_version.minor, application_sdl_build_version.patch);
   1284        ImGui::Text("SDL %d.%d.%d (link) ", application_sdl_link_version.major, application_sdl_link_version.minor, application_sdl_link_version.patch);
   1285        ImGui::Text("OpenGL %s", renderer_opengl_version);
   1286        #ifndef __APPLE__
   1287        ImGui::Text("GLEW %s", renderer_glew_version);
   1288        #endif
   1289        ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
   1290
   1291        ImGui::Separator();
   1292
   1293        if (application_gamepad)
   1294            ImGui::Text("Gamepad detected");
   1295        else
   1296            ImGui::Text("No gamepad detected");
   1297
   1298        if (application_gamepad_mappings > 0)
   1299            ImGui::Text("%d gamepad mappings loaded", application_gamepad_mappings);
   1300        else
   1301            ImGui::Text("Gamepad database not found");
   1302
   1303        ImGui::Separator();
   1304
   1305        if (ImGui::Button("OK", ImVec2(120, 0))) 
   1306        {
   1307            ImGui::CloseCurrentPopup();
   1308            dialog_in_use = false;
   1309        }
   1310        ImGui::SetItemDefaultFocus();
   1311
   1312        ImGui::EndPopup();
   1313    }
   1314}
   1315
   1316static GB_Color color_float_to_int(ImVec4 color)
   1317{
   1318    GB_Color ret;
   1319    ret.red = (u8)floor(color.x >= 1.0 ? 255.0 : color.x * 256.0);
   1320    ret.green = (u8)floor(color.y >= 1.0 ? 255.0 : color.y * 256.0);
   1321    ret.blue = (u8)floor(color.z >= 1.0 ? 255.0 : color.z * 256.0);
   1322    return ret;
   1323}
   1324
   1325static ImVec4 color_int_to_float(GB_Color color)
   1326{
   1327    ImVec4 ret;
   1328    ret.w = 0;
   1329    ret.x = (1.0f / 255.0f) * color.red;
   1330    ret.y = (1.0f / 255.0f) * color.green;
   1331    ret.z = (1.0f / 255.0f) * color.blue;
   1332    return ret;
   1333}
   1334
   1335static void update_palette(void)
   1336{
   1337    if (config_video.palette > 5)
   1338    {
   1339        int palette = config_video.palette - 6;
   1340        emu_dmg_palette(config_video.color[palette][0], config_video.color[palette][1], config_video.color[palette][2], config_video.color[palette][3]);
   1341    }
   1342    else
   1343        emu_dmg_predefined_palette(config_video.palette);
   1344}
   1345
   1346static void push_recent_rom(std::string path)
   1347{
   1348    int slot = 0;
   1349    for (slot = 0; slot < config_max_recent_roms; slot++)
   1350    {
   1351        if (config_emulator.recent_roms[slot].compare(path) == 0)
   1352        {
   1353            break;
   1354        }
   1355    }
   1356
   1357    slot = std::min(slot, config_max_recent_roms - 1);
   1358
   1359    for (int i = slot; i > 0; i--)
   1360    {
   1361        config_emulator.recent_roms[i] = config_emulator.recent_roms[i - 1];
   1362    }
   1363
   1364    config_emulator.recent_roms[0] = path;
   1365}
   1366
   1367static void menu_reset(void)
   1368{
   1369    emu_resume();
   1370    emu_reset(config_emulator.force_dmg, get_mbc(config_emulator.mbc), config_emulator.force_gba);
   1371
   1372    if (config_emulator.start_paused)
   1373    {
   1374        emu_pause();
   1375        
   1376        for (int i=0; i < (GAMEBOY_WIDTH * GAMEBOY_HEIGHT); i++)
   1377        {
   1378            emu_frame_buffer[i].red = 0;
   1379            emu_frame_buffer[i].green = 0;
   1380            emu_frame_buffer[i].blue = 0;
   1381        }
   1382    }
   1383}
   1384
   1385static void menu_pause(void)
   1386{
   1387    if (emu_is_paused())
   1388        emu_resume();
   1389    else
   1390        emu_pause();
   1391}
   1392
   1393static void menu_ffwd(void)
   1394{
   1395    config_audio.sync = !config_emulator.ffwd;
   1396
   1397    if (config_emulator.ffwd)
   1398        SDL_GL_SetSwapInterval(0);
   1399    else
   1400    {
   1401        SDL_GL_SetSwapInterval(config_video.sync ? 1 : 0);
   1402        emu_audio_reset();
   1403    }
   1404}
   1405
   1406static void show_info(void)
   1407{
   1408    if (config_video.fps)
   1409        ImGui::SetCursorPosX(5.0f);
   1410    else
   1411        ImGui::SetCursorPos(ImVec2(5.0f, config_debug.debug ? 25.0f : 5.0f));
   1412
   1413    static char info[512];
   1414
   1415    emu_get_info(info);
   1416    ImGui::Text("%s", info);
   1417}
   1418
   1419static void show_fps(void)
   1420{
   1421    ImGui::SetCursorPos(ImVec2(5.0f, config_debug.debug ? 25.0f : 5.0f ));
   1422    ImGui::Text("Frame Rate: %.2f FPS\nFrame Time: %.2f ms", ImGui::GetIO().Framerate, 1000.0f / ImGui::GetIO().Framerate);
   1423}
   1424
   1425static Cartridge::CartridgeTypes get_mbc(int index)
   1426{
   1427    switch (index)
   1428    {
   1429        case 0:
   1430            return Cartridge::CartridgeNotSupported;
   1431        case 1:
   1432            return Cartridge::CartridgeNoMBC;
   1433        case 2:
   1434            return Cartridge::CartridgeMBC1;
   1435        case 3:
   1436            return Cartridge::CartridgeMBC2;
   1437        case 4:
   1438            return Cartridge::CartridgeMBC3;
   1439        case 5:
   1440            return Cartridge::CartridgeMBC5;
   1441        case 6:
   1442            return Cartridge::CartridgeMBC1Multi;
   1443        default:
   1444            return Cartridge::CartridgeNotSupported;
   1445    }
   1446}