File browser.
This commit is contained in:
parent
b36e315265
commit
b39d0c28b4
6 changed files with 110 additions and 22 deletions
|
@ -1,4 +1,5 @@
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include "cpu.hpp"
|
||||||
#include "mappers/mapper0.hpp"
|
#include "mappers/mapper0.hpp"
|
||||||
#include "mappers/mapper1.hpp"
|
#include "mappers/mapper1.hpp"
|
||||||
#include "mappers/mapper4.hpp"
|
#include "mappers/mapper4.hpp"
|
||||||
|
@ -7,7 +8,7 @@
|
||||||
namespace Cartridge {
|
namespace Cartridge {
|
||||||
|
|
||||||
|
|
||||||
Mapper* mapper; // Mapper chip.
|
Mapper* mapper = nullptr; // Mapper chip.
|
||||||
|
|
||||||
/* PRG-ROM access */
|
/* PRG-ROM access */
|
||||||
template <bool wr> u8 access(u16 addr, u8 v)
|
template <bool wr> u8 access(u16 addr, u8 v)
|
||||||
|
@ -50,6 +51,13 @@ void load(const char* fileName)
|
||||||
case 1: mapper = new Mapper1(rom); break;
|
case 1: mapper = new Mapper1(rom); break;
|
||||||
case 4: mapper = new Mapper4(rom); break;
|
case 4: mapper = new Mapper4(rom); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CPU::power();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool loaded()
|
||||||
|
{
|
||||||
|
return mapper != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ template <bool wr> u8 access(u16 addr, u8 v = 0);
|
||||||
template <bool wr> u8 chr_access(u16 addr, u8 v = 0);
|
template <bool wr> u8 chr_access(u16 addr, u8 v = 0);
|
||||||
void signal_scanline();
|
void signal_scanline();
|
||||||
void load(const char* fname);
|
void load(const char* fname);
|
||||||
|
bool loaded();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
39
src/gui.cpp
39
src/gui.cpp
|
@ -1,5 +1,6 @@
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
#include <SDL2/SDL_ttf.h>
|
#include <SDL2/SDL_ttf.h>
|
||||||
|
#include "cartridge.hpp"
|
||||||
#include "cpu.hpp"
|
#include "cpu.hpp"
|
||||||
#include "menu.hpp"
|
#include "menu.hpp"
|
||||||
#include "gui.hpp"
|
#include "gui.hpp"
|
||||||
|
@ -14,16 +15,22 @@ SDL_Texture* gameTexture;
|
||||||
TTF_Font* font;
|
TTF_Font* font;
|
||||||
u8 const* keys;
|
u8 const* keys;
|
||||||
|
|
||||||
// Status:
|
// Menus:
|
||||||
bool pause = false;
|
|
||||||
Menu* menu;
|
Menu* menu;
|
||||||
|
Menu mainMenu;
|
||||||
|
Menu settingsMenu;
|
||||||
|
FileMenu* fileMenu;
|
||||||
|
|
||||||
|
bool pause = true;
|
||||||
|
|
||||||
/* Initialize GUI */
|
/* Initialize GUI */
|
||||||
void init()
|
void init()
|
||||||
{
|
{
|
||||||
|
// Initialize graphics system:
|
||||||
SDL_Init(SDL_INIT_VIDEO);
|
SDL_Init(SDL_INIT_VIDEO);
|
||||||
TTF_Init();
|
TTF_Init();
|
||||||
|
|
||||||
|
// Initialize graphics structures:
|
||||||
window = SDL_CreateWindow ("LaiNES",
|
window = SDL_CreateWindow ("LaiNES",
|
||||||
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||||
width, height, 0);
|
width, height, 0);
|
||||||
|
@ -38,11 +45,17 @@ void init()
|
||||||
font = TTF_OpenFont("res/font.ttf", fontPt);
|
font = TTF_OpenFont("res/font.ttf", fontPt);
|
||||||
|
|
||||||
keys = SDL_GetKeyboardState(0);
|
keys = SDL_GetKeyboardState(0);
|
||||||
signal(SIGINT, SIG_DFL);
|
signal(SIGINT, SIG_DFL); // CTRL+C kills the application.
|
||||||
|
|
||||||
menu = new Menu({ "Load ROM",
|
// Menus:
|
||||||
"Settings",
|
mainMenu.add("Load ROM", []{ menu = fileMenu->reset(); });
|
||||||
"Exit" });
|
mainMenu.add("Settings", []{ menu = settingsMenu.reset(); });
|
||||||
|
mainMenu.add("Exit" , []{ exit(0); });
|
||||||
|
settingsMenu.add("<-", []{ menu = mainMenu.reset(); });
|
||||||
|
settingsMenu.add("Controls");
|
||||||
|
settingsMenu.add("Video");
|
||||||
|
fileMenu = new FileMenu;
|
||||||
|
menu = &mainMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Render a texture on screen (-1 to center on an axis) */
|
/* Render a texture on screen (-1 to center on an axis) */
|
||||||
|
@ -109,6 +122,12 @@ void render()
|
||||||
SDL_RenderPresent(renderer);
|
SDL_RenderPresent(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void toggle_pause()
|
||||||
|
{
|
||||||
|
pause = not pause;
|
||||||
|
menu = mainMenu.reset();
|
||||||
|
}
|
||||||
|
|
||||||
/* Run the emulator */
|
/* Run the emulator */
|
||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
|
@ -129,11 +148,13 @@ void run()
|
||||||
{
|
{
|
||||||
case SDL_QUIT: return;
|
case SDL_QUIT: return;
|
||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
if (keys[SDL_SCANCODE_ESCAPE])
|
if (keys[SDL_SCANCODE_ESCAPE] and Cartridge::loaded())
|
||||||
pause = not pause;
|
toggle_pause();
|
||||||
else if (pause) menu->update(keys);
|
else if (pause)
|
||||||
|
menu->update(keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (not pause) CPU::run_frame();
|
if (not pause) CPU::run_frame();
|
||||||
render();
|
render();
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ const unsigned height = 240;
|
||||||
const unsigned fontPt = 16; // Font size.
|
const unsigned fontPt = 16; // Font size.
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
void toggle_pause();
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
SDL_Texture* gen_text(std::string text, SDL_Color color);
|
SDL_Texture* gen_text(std::string text, SDL_Color color);
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
#include "cartridge.hpp"
|
|
||||||
#include "cpu.hpp"
|
|
||||||
#include "gui.hpp"
|
#include "gui.hpp"
|
||||||
#include "ppu.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
GUI::init();
|
GUI::init();
|
||||||
Cartridge::load(argv[1]);
|
|
||||||
CPU::power();
|
|
||||||
|
|
||||||
GUI::run();
|
GUI::run();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
75
src/menu.hpp
75
src/menu.hpp
|
@ -1,37 +1,53 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <functional>
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include "cartridge.hpp"
|
||||||
#include "gui.hpp"
|
#include "gui.hpp"
|
||||||
|
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
struct MenuEntry
|
struct MenuEntry
|
||||||
{
|
{
|
||||||
SDL_Color white = { 255, 255, 255 };
|
SDL_Color white = { 255, 255, 255 };
|
||||||
SDL_Color red = { 255, 0, 0 };
|
SDL_Color red = { 255, 0, 0 };
|
||||||
|
|
||||||
std::string label;
|
string label;
|
||||||
|
function<void()> callback;
|
||||||
|
|
||||||
SDL_Texture* selected;
|
SDL_Texture* selected;
|
||||||
SDL_Texture* unselected;
|
SDL_Texture* unselected;
|
||||||
|
|
||||||
MenuEntry(std::string label)
|
MenuEntry(string label, function<void()> callback = []{})
|
||||||
{
|
{
|
||||||
this->label = label;
|
this->label = label;
|
||||||
|
this->callback = callback;
|
||||||
unselected = gen_text(label, white);
|
unselected = gen_text(label, white);
|
||||||
selected = gen_text(label, red);
|
selected = gen_text(label, red);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~MenuEntry()
|
||||||
|
{
|
||||||
|
SDL_DestroyTexture(selected);
|
||||||
|
SDL_DestroyTexture(unselected);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Menu
|
class Menu
|
||||||
{
|
{
|
||||||
std::vector<MenuEntry*> entries;
|
protected:
|
||||||
|
vector<MenuEntry*> entries;
|
||||||
int cursor = 0;
|
int cursor = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Menu(std::vector<std::string> labels)
|
void add(string label, function<void()> callback = []{})
|
||||||
{
|
{
|
||||||
for (auto label : labels)
|
entries.push_back(new MenuEntry(label, callback));
|
||||||
entries.push_back(new MenuEntry(label));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void update(u8 const* keys)
|
void update(u8 const* keys)
|
||||||
|
@ -40,6 +56,8 @@ class Menu
|
||||||
cursor++;
|
cursor++;
|
||||||
else if (keys[SDL_SCANCODE_UP] and cursor > 0)
|
else if (keys[SDL_SCANCODE_UP] and cursor > 0)
|
||||||
cursor--;
|
cursor--;
|
||||||
|
else if (keys[SDL_SCANCODE_RETURN])
|
||||||
|
entries[cursor]->callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
void render()
|
void render()
|
||||||
|
@ -48,6 +66,51 @@ class Menu
|
||||||
render_texture(entries[i]->unselected, -1, i * fontPt);
|
render_texture(entries[i]->unselected, -1, i * fontPt);
|
||||||
render_texture(entries[cursor]->selected, -1, cursor * fontPt);
|
render_texture(entries[cursor]->selected, -1, cursor * fontPt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual Menu* reset()
|
||||||
|
{
|
||||||
|
cursor = 0;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class FileMenu : public Menu
|
||||||
|
{
|
||||||
|
void change_dir(string dir)
|
||||||
|
{
|
||||||
|
for (auto entry : entries)
|
||||||
|
delete entry;
|
||||||
|
entries.clear();
|
||||||
|
cursor = 0;
|
||||||
|
|
||||||
|
struct dirent* dirp;
|
||||||
|
DIR* dp = opendir(dir.c_str());
|
||||||
|
|
||||||
|
while ((dirp = readdir(dp)) != NULL)
|
||||||
|
{
|
||||||
|
string name = dirp->d_name;
|
||||||
|
string path = dir + "/" + name;
|
||||||
|
|
||||||
|
if (name[0] == '.' and name != "..") continue;
|
||||||
|
if (dirp->d_type == DT_DIR)
|
||||||
|
add(name + "/", [=]{ change_dir(path); });
|
||||||
|
else
|
||||||
|
add(name, [=]{ Cartridge::load(path.c_str()); toggle_pause(); });
|
||||||
|
}
|
||||||
|
closedir(dp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Menu* reset()
|
||||||
|
{
|
||||||
|
change_dir(getwd(NULL));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileMenu()
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Reference in a new issue