diff --git a/testdir/testgame.smc b/snes/testgame.smc similarity index 100% rename from testdir/testgame.smc rename to snes/testgame.smc diff --git a/src/GameData.cpp b/src/GameData.cpp index 6ec029afc..29ba78ba7 100644 --- a/src/GameData.cpp +++ b/src/GameData.cpp @@ -1,4 +1,5 @@ #include "GameData.h" +#include GameData::GameData(SystemData* system, std::string path, std::string name) { @@ -11,3 +12,21 @@ std::string GameData::getName() { return mName; } + + + +std::string GameData::getValidPath() +{ + //a quick and dirty way to insert a backslash before spaces + std::string path = mPath; + for(unsigned int i = 0; i < path.length(); i++) + { + if(path[i] == *" ") + { + path.insert(i, "\\"); + i++; + } + } + + return path; +} diff --git a/src/GameData.h b/src/GameData.h index 301679e26..51987f250 100644 --- a/src/GameData.h +++ b/src/GameData.h @@ -10,6 +10,8 @@ public: GameData(SystemData* system, std::string path, std::string name); std::string getName(); + std::string getValidPath(); + private: SystemData* mSystem; std::string mPath; diff --git a/src/InputManager.cpp b/src/InputManager.cpp index 1e006fafa..ef0bb9a38 100644 --- a/src/InputManager.cpp +++ b/src/InputManager.cpp @@ -27,8 +27,6 @@ void InputManager::processEvent(SDL_Event* event) if(event->key.state == SDL_PRESSED) keyDown = true; - std::cout << "Processing keyboard event\n"; - //get InputButton from the event InputButton button; switch(event->key.keysym.sym) @@ -45,7 +43,7 @@ void InputManager::processEvent(SDL_Event* event) case SDLK_DOWN: button = DOWN; break; - case SDLK_SPACE: + case SDLK_RETURN: button = BUTTON1; break; diff --git a/src/Renderer_draw.cpp b/src/Renderer_draw.cpp index 3b2faa76b..421820b77 100644 --- a/src/Renderer_draw.cpp +++ b/src/Renderer_draw.cpp @@ -15,7 +15,7 @@ void Renderer::drawRect(int x, int y, int h, int w, int color) void Renderer::loadFonts() { - font = TTF_OpenFont("LinLibertine_R.ttf", 48); + font = TTF_OpenFont("LinLibertine_R.ttf", 36); if(!font) { std::cerr << "Error - could not load font!\n"; diff --git a/src/SystemData.cpp b/src/SystemData.cpp index 295a65660..f26f54311 100644 --- a/src/SystemData.cpp +++ b/src/SystemData.cpp @@ -1,32 +1,65 @@ #include "SystemData.h" #include "GameData.h" #include +#include +#include namespace fs = boost::filesystem; -SystemData::SystemData(std::string name, std::string startPath, std::string extension) +SystemData::SystemData(std::string name, std::string startPath, std::string extension, std::string command) { mName = name; mStartPath = startPath; mSearchExtension = extension; + mLaunchCommand = command; buildGameList(); } SystemData::~SystemData() +{ + deleteGames(); +} + +std::string strreplace(std::string& str, std::string replace, std::string with) +{ + size_t pos = str.find(replace); + + return str.replace(pos, replace.length(), with.c_str(), with.length()); +} + +void SystemData::launchGame(unsigned int i) +{ + std::cout << "Attempting to launch game...\n"; + + std::string command = mLaunchCommand; + GameData* game = mGameVector.at(i); + + command = strreplace(command, "%ROM%", game->getValidPath()); + + std::cout << " " << command << "\n"; + std::cout << "=====================================================\n"; + system(command.c_str()); + std::cout << "=====================================================\n"; + + std::cout << "...launch terminated!\n"; +} + +void SystemData::deleteGames() { for(unsigned int i = 0; i < mGameVector.size(); i++) { delete mGameVector.at(i); } + mGameVector.clear(); } - - void SystemData::buildGameList() { std::cout << "System " << mName << " building game list...\n"; + deleteGames(); + if(!fs::is_directory(mStartPath)) { std::cout << "Error - system \"" << mName << "\"'s start path does not exist!\n"; @@ -35,7 +68,7 @@ void SystemData::buildGameList() for(fs::recursive_directory_iterator end, dir(mStartPath); dir != end; ++dir) { - std::cout << "File found: " << *dir << "\n"; + //std::cout << "File found: " << *dir << "\n"; fs::path path = (*dir).path(); @@ -45,12 +78,10 @@ void SystemData::buildGameList() std::string name = path.stem().string(); std::string extension = path.extension().string(); - std::cout << "detected name as \"" << name <<"\", extension as \"" << extension << "\"\n"; - if(extension == mSearchExtension) { mGameVector.push_back(new GameData(this, path.string(), name)); - std::cout << "Added game \"" << name << "\"\n"; + std::cout << " Added game \"" << name << "\"\n"; } } @@ -71,3 +102,74 @@ std::string SystemData::getName() { return mName; } + +//creates system files from information located in a config file +std::vector SystemData::loadConfig(std::string path) +{ + std::cout << "Loading system config file \"" << path << "\"...\n"; + + std::vector returnVec; + + std::ifstream file(path.c_str()); + + if(file.is_open()) + { + std::string line; + std::string sysName, sysPath, sysExtension, sysCommand; + while(file.good()) + { + std::getline(file, line); + + //skip blank lines + if(line.empty()) + continue; + + //find the name (left of the equals sign) and the value (right of the equals sign) + bool lineValid = false; + std::string varName, varValue; + for(unsigned int i = 0; i < line.length(); i++) + { + if(line[i] == *"=") + { + lineValid = true; + varName = line.substr(0, i); + varValue = line.substr(i + 1, line.length() - 1); + std::cout << " " << varName << " = " << varValue << "\n"; + break; + } + } + + if(lineValid) + { + if(varName == "NAME") + sysName = varValue; + else if(varName == "PATH") + sysPath = varValue; + else if(varName == "EXTENSION") + sysExtension = varValue; + else if(varName == "COMMAND") + sysCommand = varValue; + else + std::cerr << "Error reading config file - unknown variable name \"" << varName << "\"!\n"; + + //we have all our variables - create the system object + if(!sysName.empty() && !sysPath.empty() &&!sysExtension.empty() && !sysCommand.empty()) + { + returnVec.push_back(new SystemData(sysName, sysPath, sysExtension, sysCommand)); + + //reset the variables for the next block (should there be one) + sysName = ""; sysPath = ""; sysExtension = ""; + } + }else{ + std::cerr << "Error reading config file \"" << path << "\" - no equals sign found on line \"" << line << "\"!\n"; + return returnVec; + } + } + }else{ + std::cerr << "Error - could not load config file \"" << path << "\"!\n"; + return returnVec; + } + + std::cout << "Finished loading config file - created " << returnVec.size() << " systems.\n"; + return returnVec; +} diff --git a/src/SystemData.h b/src/SystemData.h index 5c48556b3..dd954a4e9 100644 --- a/src/SystemData.h +++ b/src/SystemData.h @@ -9,18 +9,25 @@ class GameData; class SystemData { public: - SystemData(std::string name, std::string startPath, std::string extension); + SystemData(std::string name, std::string startPath, std::string extension, std::string command); ~SystemData(); unsigned int getGameCount(); GameData* getGame(unsigned int i); std::string getName(); + + void buildGameList(); + void launchGame(unsigned int i); + static std::vector loadConfig(std::string path); private: std::string mName; std::string mStartPath; std::string mSearchExtension; + std::string mLaunchCommand; + std::vector mGameVector; - void buildGameList(); + + void deleteGames(); }; #endif diff --git a/src/components/GuiGameList.cpp b/src/components/GuiGameList.cpp index 181a30518..0fbc50184 100644 --- a/src/components/GuiGameList.cpp +++ b/src/components/GuiGameList.cpp @@ -1,4 +1,5 @@ #include "GuiGameList.h" +#include "../InputManager.h" #include GuiGameList::GuiGameList(SystemData* system) @@ -11,6 +12,13 @@ GuiGameList::GuiGameList(SystemData* system) addChild(mList); Renderer::registerComponent(this); + InputManager::registerComponent(this); +} + +GuiGameList::~GuiGameList() +{ + Renderer::unregisterComponent(this); + InputManager::unregisterComponent(this); } void GuiGameList::onRender() @@ -21,6 +29,14 @@ void GuiGameList::onRender() Renderer::drawCenteredText(mSystem->getName(), 2, color); } +void GuiGameList::onInput(InputManager::InputButton button, bool keyDown) +{ + if(button == InputManager::BUTTON1 && keyDown) + { + mSystem->launchGame(mList->getSelection()); + } +} + void GuiGameList::updateList() { mList->clear(); diff --git a/src/components/GuiGameList.h b/src/components/GuiGameList.h index 39aaebab7..78aa357d9 100644 --- a/src/components/GuiGameList.h +++ b/src/components/GuiGameList.h @@ -11,9 +11,12 @@ class GuiGameList : GuiComponent { public: GuiGameList(SystemData* system); + ~GuiGameList(); + void updateList(); void onRender(); + void onInput(InputManager::InputButton button, bool keyDown); private: SystemData* mSystem; GuiList* mList; diff --git a/src/components/GuiList.cpp b/src/components/GuiList.cpp index 7e236a43e..1e3ac5a86 100644 --- a/src/components/GuiList.cpp +++ b/src/components/GuiList.cpp @@ -1,19 +1,56 @@ #include "GuiList.h" #include +#include GuiList::GuiList() { mSelection = 0; + InputManager::registerComponent(this); +} + +GuiList::~GuiList() +{ + InputManager::unregisterComponent(this); } void GuiList::onRender() { int y = 40; SDL_Color color = {0, 0, 255}; + + if(mNameVector.size() == 0) + { + Renderer::drawCenteredText("The list is empty.", y, color); + return; + } + for(unsigned int i = 0; i < mNameVector.size(); i++) { + if(mSelection == (int)i) + { + Renderer::drawRect(0, y, Renderer::getScreenWidth(), 52, 0x000000); + } + Renderer::drawCenteredText(mNameVector.at(i), y, color); - y += 35; + y += 40; + } +} + +void GuiList::onInput(InputManager::InputButton button, bool keyDown) +{ + if(mNameVector.size() > 0 && keyDown) + { + if(button == InputManager::DOWN) + mSelection++; + + if(button == InputManager::UP) + mSelection--; + + if(mSelection < 0) + mSelection += mNameVector.size(); + + if(mSelection >= (int)mNameVector.size()) + mSelection -= mNameVector.size(); } } @@ -38,3 +75,8 @@ void* GuiList::getSelectedObject() { return mPointerVector.at(mSelection); } + +int GuiList::getSelection() +{ + return mSelection; +} diff --git a/src/components/GuiList.h b/src/components/GuiList.h index 0edb7d1c1..ef313d52b 100644 --- a/src/components/GuiList.h +++ b/src/components/GuiList.h @@ -3,6 +3,7 @@ #include "../Renderer.h" #include "../GuiComponent.h" +#include "../InputManager.h" #include #include @@ -10,18 +11,21 @@ class GuiList : public GuiComponent { public: GuiList(); + ~GuiList(); void onRender(); + void onInput(InputManager::InputButton button, bool keyDown); void addObject(std::string name, void* obj); void clear(); std::string getSelectedName(); void* getSelectedObject(); + int getSelection(); private: std::vector mNameVector; std::vector mPointerVector; - unsigned int mSelection; + int mSelection; }; #endif diff --git a/src/main.cpp b/src/main.cpp index 91e8c4094..bd7e15a5a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,11 +10,14 @@ int main() if(SDL_Init(SDL_INIT_EVERYTHING) != 0) { std::cerr << "Error - could not initialize SDL!\n"; + std::cerr << " " << SDL_GetError() << "\n"; + std::cerr << "\nAre you in the 'video', 'audio', and 'input' groups?\n"; return 1; } if(TTF_Init() != 0) { std::cerr << "Error - could not initialize SDL_ttf!\n"; + std::cerr << " " << TTF_GetError() << "\n"; return 1; } @@ -22,15 +25,17 @@ int main() if(Renderer::screen == NULL) { std::cerr << "Error - could not set video mode!\n"; + std::cerr << " " << SDL_GetError() << "\n"; return 1; } SDL_ShowCursor(false); + SDL_EnableKeyRepeat(500, 100); //GuiTitleScreen* testGui = new GuiTitleScreen(); //test systemData - SystemData* testSystem = new SystemData("Test", "./testdir/", ".smc"); + SystemData* testSystem = SystemData::loadConfig("./systems.cfg").at(0); //= new SystemData("Test", "./testdir/", ".smc"); GuiGameList* testGui = new GuiGameList(testSystem); diff --git a/systems.cfg b/systems.cfg new file mode 100644 index 000000000..c7730a411 --- /dev/null +++ b/systems.cfg @@ -0,0 +1,4 @@ +NAME=Super Nintendo Entertainment System +PATH=./snes/ +EXTENSION=.smc +COMMAND=retroarch -L ~/libretro-pocketsnes.so %ROM%