From f34e25dfc78f9bf61969497e4a40a2215398bc5b Mon Sep 17 00:00:00 2001 From: Bart Trzynadlowski Date: Mon, 27 Mar 2017 03:19:15 +0000 Subject: [PATCH] Massive internal change: removed CConfig object and replaced it with a hierarchical config object system (Util::Config::Node). Games are now defined in an XML file. Hopefully I didn't break too many things :/ --- Makefiles/Makefile.SDL.Win32.GCC | 17 +- Src/BlockFile.cpp | 100 +- Src/BlockFile.h | 32 +- Src/Config.cpp | 31 - Src/Config.h | 71 - Src/Debugger/SupermodelDebugger.cpp | 8 +- Src/Graphics/Legacy3D/Legacy3D.cpp | 27 +- Src/Graphics/Legacy3D/Legacy3D.h | 44 +- Src/Graphics/New3D/New3D.cpp | 4 +- Src/Graphics/New3D/New3D.h | 8 +- Src/Graphics/New3D/R3DScrollFog.cpp | 2 +- Src/Graphics/New3D/R3DShader.cpp | 2 +- Src/Graphics/Render2D.cpp | 2 +- Src/Graphics/Shader.cpp | 14 +- Src/Graphics/Shader.h | 5 +- Src/Inputs/Input.cpp | 78 +- Src/Inputs/Input.h | 17 +- Src/Inputs/InputSystem.cpp | 4011 +++++++++++++------------ Src/Inputs/InputSystem.h | 1415 ++++----- Src/Inputs/Inputs.cpp | 399 +-- Src/Inputs/Inputs.h | 19 +- Src/Model3/DSB.cpp | 16 +- Src/Model3/DSB.h | 91 +- Src/Model3/DriveBoard.cpp | 1291 ++++---- Src/Model3/DriveBoard.h | 506 ++-- Src/Model3/IEmulator.h | 30 +- Src/Model3/Model3.cpp | 418 +-- Src/Model3/Model3.h | 70 +- Src/Model3/Model3GraphicsState.h | 9 +- Src/Model3/Real3D.cpp | 43 +- Src/Model3/Real3D.h | 20 +- Src/Model3/SoundBoard.cpp | 9 +- Src/Model3/SoundBoard.h | 55 +- Src/Model3/TileGen.cpp | 24 +- Src/Model3/TileGen.h | 13 +- Src/OSD/Audio.h | 2 +- Src/OSD/Outputs.cpp | 4 +- Src/OSD/Outputs.h | 106 +- Src/OSD/SDL/Audio.cpp | 8 +- Src/OSD/SDL/Main.cpp | 1163 +++---- Src/OSD/SDL/OSDConfig.h | 174 -- Src/OSD/SDL/SDLInputSystem.cpp | 8 +- Src/OSD/Windows/DirectInputSystem.cpp | 59 +- Src/OSD/Windows/DirectInputSystem.h | 4 +- Src/OSD/Windows/WinOutputs.cpp | 14 +- Src/Sound/SCSP.cpp | 39 +- Src/Sound/SCSP.h | 2 +- Src/Supermodel.h | 4 - 48 files changed, 5106 insertions(+), 5382 deletions(-) delete mode 100644 Src/Config.cpp delete mode 100644 Src/Config.h delete mode 100644 Src/OSD/SDL/OSDConfig.h diff --git a/Makefiles/Makefile.SDL.Win32.GCC b/Makefiles/Makefile.SDL.Win32.GCC index 62c9b88..a3725ff 100644 --- a/Makefiles/Makefile.SDL.Win32.GCC +++ b/Makefiles/Makefile.SDL.Win32.GCC @@ -38,7 +38,7 @@ BITS = 64 # # Include console-based debugger in emulator ('yes' or 'no') # -ENABLE_DEBUGGER = no +ENABLE_DEBUGGER = yes ############################################################################### @@ -58,7 +58,7 @@ BOOST_INCLUDEPATH = /mingw64/boost_1_55_0 ifeq ($(strip $(BITS)),64) SDL_LIBPATH = /mingw64/lib64 #SDL_INCLUDEPATH = /mingw64/x86_64-w64-mingw32/include/SDL - SDL_INCLUDEPATH = /mingw64/SDL-1.2.15/include + SDL_INCLUDEPATH = c:\tdm-gcc-64\include\SDL else SDL_LIBPATH = /mingw/lib SDL_INCLUDEPATH = /mingw/include/SDL @@ -100,7 +100,7 @@ LD = g++ COMPILER_FLAGS = -I$(SDL_INCLUDEPATH) -ISrc/ -ISrc/OSD/ -ISrc/OSD/SDL/ -ISrc/OSD/Windows/ -c -Wall -DSUPERMODEL_WIN32 -DGLEW_STATIC -O3 CFLAGS = $(COMPILER_FLAGS) CPPFLAGS = $(COMPILER_FLAGS) -I$(BOOST_INCLUDEPATH) -std=c++11 -LFLAGS = -o $(OUTFILE) $(OBJ) -L$(SDL_LIBPATH) -lmingw32 -lSDLmain -lSDL -lopengl32 -lglu32 -ldinput8 -ldxguid -lole32 -loleaut32 -lwbemuuid -lz -s #-l:$(WINSDK_LIBPATH)/WbemUuid.lib -s +LFLAGS = -o $(OUTFILE) $(OBJ) -L$(SDL_LIBPATH) -lmingw32 -lSDLmain -lSDL -lopengl32 -lglu32 -ldinput8 -ldxguid -lole32 -loleaut32 -lwbemuuid -lz -s # -l:$(WINSDK_LIBPATH)/WbemUuid.lib -s # # Build options... @@ -119,11 +119,11 @@ endif # # Objects and Dependencies # -OBJ = $(OBJ_DIR)/Format.o $(OBJ_DIR)/NewConfig.o \ - $(OBJ_DIR)/PPCDisasm.o $(OBJ_DIR)/Games.o $(OBJ_DIR)/Config.o $(OBJ_DIR)/INIFile.o $(OBJ_DIR)/BlockFile.o $(OBJ_DIR)/93C46.o \ +OBJ = $(OBJ_DIR)/PPCDisasm.o $(OBJ_DIR)/Games.o $(OBJ_DIR)/INIFile.o $(OBJ_DIR)/BlockFile.o $(OBJ_DIR)/93C46.o \ $(OBJ_DIR)/ROMLoad.o $(OBJ_DIR)/unzip.o $(OBJ_DIR)/ioapi.o $(OBJ_DIR)/Error.o $(OBJ_DIR)/glew.o $(OBJ_DIR)/Shader.o \ $(OBJ_DIR)/Real3D.o $(OBJ_DIR)/Legacy3D.o $(OBJ_DIR)/Models.o $(OBJ_DIR)/TextureRefs.o \ $(OBJ_DIR)/New3D.o $(OBJ_DIR)/Mat4.o $(OBJ_DIR)/Model.o $(OBJ_DIR)/PolyHeader.o $(OBJ_DIR)/Texture.o $(OBJ_DIR)/TextureSheet.o $(OBJ_DIR)/VBO.o $(OBJ_DIR)/Vec.o $(OBJ_DIR)/R3DShader.o $(OBJ_DIR)/R3DFloat.o \ + $(OBJ_DIR)/R3DScrollFog.o \ $(OBJ_DIR)/Render2D.o $(OBJ_DIR)/TileGen.o \ $(OBJ_DIR)/Model3.o $(OBJ_DIR)/ppc.o $(OBJ_DIR)/Main.o $(OBJ_DIR)/Audio.o $(OBJ_DIR)/Thread.o $(OBJ_DIR)/SoundBoard.o \ $(OBJ_DIR)/SCSP.o $(OBJ_DIR)/SCSPDSP.o $(OBJ_DIR)/68K.o $(OBJ_DIR)/m68kcpu.o $(OBJ_DIR)/m68kopnz.o $(OBJ_DIR)/m68kopdm.o \ @@ -137,7 +137,8 @@ OBJ = $(OBJ_DIR)/Format.o $(OBJ_DIR)/NewConfig.o \ $(OBJ_DIR)/amp_util.o \ $(OBJ_DIR)/Crypto.o \ $(OBJ_DIR)/Logger.o \ - $(OBJ_DIR)/tinyxml2.o + $(OBJ_DIR)/tinyxml2.o \ + $(OBJ_DIR)/ByteSwap.o $(OBJ_DIR)/Format.o $(OBJ_DIR)/NewConfig.o $(OBJ_DIR)/ConfigBuilders.o $(OBJ_DIR)/GameLoader.o # If built-in debugger enabled, include all debugging classes @@ -159,9 +160,9 @@ ppcd: $(BIN_DIR) $(OBJ_DIR) $(CXX) Src/CPU/PowerPC/PPCDisasm.cpp $(CPPFLAGS) -DSTANDALONE -o $(OBJ_DIR)/ppcd.o $(LD) -o $(BIN_DIR)/ppcd.exe -mconsole $(OBJ_DIR)/ppcd.o -tests: $(BIN_DIR) $(OBJ_DIR) $(OBJ) Src/Util/Test_Config.cpp Src/Pkgs/tinyxml2.cpp +tests: $(BIN_DIR) $(OBJ_DIR) $(OBJ_DIR)/NewConfig.o $(OBJ_DIR)/ConfigBuilders.o Src/Util/Test_Config.cpp Src/Pkgs/tinyxml2.cpp $(CXX) Src/Util/Test_Config.cpp $(CPPFLAGS) -o $(OBJ_DIR)/Test_Config.o - $(LD) -o $(BIN_DIR)/test_config.exe -mconsole $(OBJ_DIR)/Test_Config.o $(OBJ_DIR)/Format.o $(OBJ_DIR)/NewConfig.o $(OBJ_DIR)/Logger.o $(OBJ_DIR)/tinyxml2.o + $(LD) -o $(BIN_DIR)/test_config.exe -mconsole $(OBJ_DIR)/Test_Config.o $(OBJ_DIR)/Format.o $(OBJ_DIR)/NewConfig.o $(OBJ_DIR)/ConfigBuilders.o $(OBJ_DIR)/Logger.o $(OBJ_DIR)/tinyxml2.o $(BIN_DIR): mkdir $(BIN_DIR) diff --git a/Src/BlockFile.cpp b/Src/BlockFile.cpp index 7b18cf9..24b5c4e 100644 --- a/Src/BlockFile.cpp +++ b/Src/BlockFile.cpp @@ -35,17 +35,28 @@ Output Functions ******************************************************************************/ -void CBlockFile::ReadString(char *str, unsigned strLen, unsigned maxLen) +void CBlockFile::ReadString(std::string *str, uint32_t length) { if (NULL == fp) return; - if (strLen>maxLen) - strLen = maxLen; - fread(str, sizeof(char), strLen, fp); - str[strLen] = '\0'; + str->clear(); + //TODO: use fstream to get rid of this ugly hack + bool keep_loading = true; + for (size_t i = 0; i < length; i++) + { + char c; + fread(&c, sizeof(char), 1, fp); + if (keep_loading) + { + if (!c) + keep_loading = false; + else + *str += c; + } + } } -unsigned CBlockFile::ReadBytes(void *data, unsigned numBytes) +unsigned CBlockFile::ReadBytes(void *data, uint32_t numBytes) { if (NULL == fp) return 0; @@ -90,7 +101,7 @@ void CBlockFile::WriteDWord(uint32_t data) UpdateBlockSize(); } -void CBlockFile::WriteBytes(const void *data, unsigned numBytes) +void CBlockFile::WriteBytes(const void *data, uint32_t numBytes) { if (NULL == fp) return; @@ -98,24 +109,11 @@ void CBlockFile::WriteBytes(const void *data, unsigned numBytes) UpdateBlockSize(); } -void CBlockFile::WriteBlockHeader(const char *name, const char *comment) +void CBlockFile::WriteBlockHeader(const std::string &name, const std::string &comment) { - unsigned nameLen, commentLen; - const char nullComment[1] = {'\0'}; - if (NULL == fp) return; - - if (comment == NULL) - comment = nullComment; - - nameLen = strlen(name); - commentLen = strlen(comment); - if (nameLen > 1024) - nameLen = 1024; - if (commentLen > 1024) - commentLen = 1024; - + // Record current block starting position blockStartPos = ftell(fp); @@ -123,12 +121,10 @@ void CBlockFile::WriteBlockHeader(const char *name, const char *comment) WriteDWord(0); // will be automatically updated as we write the file // Write name and comment lengths - WriteDWord(nameLen+1); - WriteDWord(commentLen+1); - WriteBytes(name, nameLen); - WriteByte(0); - WriteBytes(comment, commentLen); - WriteByte(0); + WriteDWord(name.size() + 1); + WriteDWord(comment.size() + 1); + Write(name); + Write(comment); // Record the start of the current data section dataStartPos = ftell(fp); @@ -151,66 +147,74 @@ void CBlockFile::WriteBlockHeader(const char *name, const char *comment) data ... Raw data (blockLength - total header size). ******************************************************************************/ -unsigned CBlockFile::Read(void *data, unsigned numBytes) +unsigned CBlockFile::Read(void *data, uint32_t numBytes) { if (mode == 'r') return ReadBytes(data, numBytes); return 0; } -void CBlockFile::Write(const void *data, unsigned numBytes) +void CBlockFile::Write(const void *data, uint32_t numBytes) { if (mode == 'w') WriteBytes(data, numBytes); } -void CBlockFile::NewBlock(const char *name, const char *comment) +void CBlockFile::Write(const std::string &str) +{ + if (mode == 'w') + WriteBytes(str.c_str(), str.length() + 1); +} + +void CBlockFile::NewBlock(const std::string &name, const std::string &comment) { if (mode == 'w') WriteBlockHeader(name, comment); } -bool CBlockFile::FindBlock(const char *name) +bool CBlockFile::FindBlock(const std::string &name) { - long int curPos = 0; - unsigned blockLen, nameLen, commentLen; - if (mode != 'r') return FAIL; fseek(fp, 0, SEEK_SET); + long int curPos = 0; while (curPos < fileSize) { blockStartPos = curPos; // Read header - curPos += ReadDWord(&blockLen); - curPos += ReadDWord(&nameLen); - curPos += ReadDWord(&commentLen); - ReadString(strBuf,nameLen,1025); + uint32_t block_length; + uint32_t name_length; + uint32_t comment_length; + curPos += ReadDWord(&block_length); + curPos += ReadDWord(&name_length); + curPos += ReadDWord(&comment_length); + std::string block_name; + ReadString(&block_name, name_length); // Is this the block we want? - if (!strcmp(strBuf,name)) + if (block_name == name) { - fseek(fp, blockStartPos+12+nameLen+commentLen, SEEK_SET); // move to beginning of data + fseek(fp, blockStartPos + 12 + name_length + comment_length, SEEK_SET); // move to beginning of data dataStartPos = ftell(fp); return OKAY; } // Move to next block - fseek(fp, blockStartPos+blockLen, SEEK_SET); - curPos = blockStartPos+blockLen; - if (blockLen == 0) // this would never advance + fseek(fp, blockStartPos + block_length, SEEK_SET); + curPos = blockStartPos + block_length; + if (block_length == 0) // this would never advance break; } return FAIL; } -bool CBlockFile::Create(const char *file, const char *headerName, const char *comment) +bool CBlockFile::Create(const std::string &file, const std::string &headerName, const std::string &comment) { - fp = fopen(file, "wb"); + fp = fopen(file.c_str(), "wb"); if (NULL == fp) return FAIL; mode = 'w'; @@ -218,9 +222,9 @@ bool CBlockFile::Create(const char *file, const char *headerName, const char *co return OKAY; } -bool CBlockFile::Load(const char *file) +bool CBlockFile::Load(const std::string &file) { - fp = fopen(file, "rb"); + fp = fopen(file.c_str(), "rb"); if (NULL == fp) return FAIL; mode = 'r'; diff --git a/Src/BlockFile.h b/Src/BlockFile.h index 641b80e..9e1e633 100644 --- a/Src/BlockFile.h +++ b/Src/BlockFile.h @@ -57,7 +57,7 @@ public: * Number of bytes read. If not the same as numBytes, an error * occurred. */ - unsigned Read(void *data, unsigned numBytes); + unsigned Read(void *data, uint32_t numBytes); /* * FindBlock(name): @@ -71,7 +71,7 @@ public: * Returns: * OKAY if found, FAIL if unable to locate. */ - bool FindBlock(const char *name); + bool FindBlock(const std::string &name); /* * Write(data, numBytes): @@ -83,7 +83,18 @@ public: * data Data to write. * numBytes Number of bytes to write. */ - void Write(const void *data, unsigned numBytes); + void Write(const void *data, uint32_t numBytes); + + /* + * Write(str): + * + * Outputs string (including null terminator) at the current file pointer + * position. Updates the block header appropriately. + * + * Parameters: + * str String to write. + */ + void Write(const std::string &str); /* * NewBlock(name, comment): @@ -95,7 +106,7 @@ public: * name Block name. Must be unique and not NULL. * comment Comment string to embed in the block header. */ - void NewBlock(const char *title, const char *comment); + void NewBlock(const std::string &title, const std::string &comment); /* * Create(file, headerName, comment): @@ -113,7 +124,7 @@ public: * Returns: * OKAY if successfully opened, otherwise FAIL. */ - bool Create(const char *file, const char *headerName, const char *comment); + bool Create(const std::string &file, const std::string &headerName, const std::string &comment); /* * Load(file): @@ -129,7 +140,7 @@ public: * subsequent operations will be silently ignored (reads will return * 0's). Write commands will be ignored. */ - bool Load(const char *file); + bool Load(const std::string &file); /* * Close(void): @@ -149,17 +160,16 @@ public: private: // Helper functions - void ReadString(char *str, unsigned strLen, unsigned maxLen); - unsigned ReadBytes(void *data, unsigned numBytes); + void ReadString(std::string *str, uint32_t length); + unsigned ReadBytes(void *data, uint32_t numBytes); unsigned ReadDWord(uint32_t *data); void UpdateBlockSize(void); void WriteByte(uint8_t data); void WriteDWord(uint32_t data); - void WriteBytes(const void *data, unsigned numBytes); - void WriteBlockHeader(const char *name, const char *comment); + void WriteBytes(const void *data, uint32_t numBytes); + void WriteBlockHeader(const std::string &name, const std::string &comment); // File state data - char strBuf[1026]; // buffers up to a 1024-character string, its terminator, and an extra terminator (just in case) FILE *fp; int mode; // 'r' for read, 'w' for write long int fileSize; // size of file in bytes diff --git a/Src/Config.cpp b/Src/Config.cpp deleted file mode 100644 index 7937195..0000000 --- a/Src/Config.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/** - ** Supermodel - ** A Sega Model 3 Arcade Emulator. - ** Copyright 2011 Bart Trzynadlowski, Nik Henson - ** - ** This file is part of Supermodel. - ** - ** Supermodel 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 (at your option) - ** any later version. - ** - ** Supermodel 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 Supermodel. If not, see . - **/ - -/* - * Config.cpp - * - * Program-wide configuration settings. - */ - -#include "Config.h" - - -CConfig g_Config; diff --git a/Src/Config.h b/Src/Config.h deleted file mode 100644 index 9afdca8..0000000 --- a/Src/Config.h +++ /dev/null @@ -1,71 +0,0 @@ -/** - ** Supermodel - ** A Sega Model 3 Arcade Emulator. - ** Copyright 2011 Bart Trzynadlowski, Nik Henson - ** - ** This file is part of Supermodel. - ** - ** Supermodel 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 (at your option) - ** any later version. - ** - ** Supermodel 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 Supermodel. If not, see . - **/ - -/* - * Config.h - * - * Header file for program-wide configuration settings. - */ - -#ifndef INCLUDED_CONFIG_H -#define INCLUDED_CONFIG_H - - -#include "Supermodel.h" - - -/* - * CConfig: - * - * Class defining all configuration settings. Inherits settings from classes - * defined throughout the program. - * - * Conventions - * ----------- - * - Modules and classes should only use the members of their own configuration - * class, so long as this is practical. This is left to programmer - * discretion. The intent is that one class, CReal3D for example, should not - * need information from another unrelated class, CModel3, unless explicitly - * passed to it. On the other hand, the OSD layer may have a legitimate - * need to use the renderer's video settings rather than maintaining its own. - * - Member variables that have a limited range of allowable values must be - * private and accessed through accessor members (SetVar(), GetVar()). The - * accessors must ensure that a value outside the allowable range is never - * returned and must clamp or reset to a default when an invalid setting - * is passed. Warnings may be printed. - * - Strings should be copied and retained locally. - * - Constructors must be defined and must initialize to the program default. - * - User-tunable settings should be stored here, not necessarily every - * concievable parameter a class initializer might take. - */ -class CConfig: public COSDConfig, public Legacy3D::CLegacy3DConfig, public CModel3Config, public CSoundBoardConfig, public CDSBConfig, public CDriveBoardConfig -{ -}; - -/* - * g_Config: - * - * Program-wide configuration settings object. - */ -extern CConfig g_Config; - - -#endif // INCLUDED_CONFIG_H \ No newline at end of file diff --git a/Src/Debugger/SupermodelDebugger.cpp b/Src/Debugger/SupermodelDebugger.cpp index 1583f63..d5a9290 100644 --- a/Src/Debugger/SupermodelDebugger.cpp +++ b/Src/Debugger/SupermodelDebugger.cpp @@ -514,7 +514,7 @@ namespace Debugger } else if (CheckToken(token, "caip", "configallinputs")) // configallinputs { - m_inputs->ConfigureInputs(m_model3->GetGameInfo()); + m_inputs->ConfigureInputs(&m_model3->GetGame()); return false; } // @@ -544,7 +544,7 @@ namespace Debugger bool CSupermodelDebugger::InputIsValid(::CInput *input) { - return input->IsUIInput() || (input->gameFlags & m_model3->GetGameInfo()->inputFlags); + return input->IsUIInput() || (input->gameFlags & m_model3->GetGame().inputs); } void CSupermodelDebugger::ListInputs() @@ -599,14 +599,14 @@ namespace Debugger CConsoleDebugger::Attached(); char fileName[25]; - sprintf(fileName, "Debug/%s.ds", m_model3->GetGameInfo()->id); + sprintf(fileName, "Debug/%s.ds", m_model3->GetGame().name.c_str()); LoadState(fileName); } void CSupermodelDebugger::Detaching() { char fileName[25]; - sprintf(fileName, "Debug/%s.ds", m_model3->GetGameInfo()->id); + sprintf(fileName, "Debug/%s.ds", m_model3->GetGame().name.c_str()); SaveState(fileName); CConsoleDebugger::Detaching(); diff --git a/Src/Graphics/Legacy3D/Legacy3D.cpp b/Src/Graphics/Legacy3D/Legacy3D.cpp index 1628e9f..360b181 100644 --- a/Src/Graphics/Legacy3D/Legacy3D.cpp +++ b/Src/Graphics/Legacy3D/Legacy3D.cpp @@ -799,7 +799,7 @@ void CLegacy3D::DescendNodePtr(UINT32 nodeAddr) } // Draws viewports of the given priority -void CLegacy3D::RenderViewport(UINT32 addr, int pri) +void CLegacy3D::RenderViewport(UINT32 addr, int pri, bool wideScreen) { static const GLfloat color[8][3] = { { 0.0, 0.0, 0.0 }, // off @@ -823,7 +823,7 @@ void CLegacy3D::RenderViewport(UINT32 addr, int pri) if (nextAddr == 0) // memory probably hasn't been set up yet, abort return; if (nextAddr != 0x01000000) - RenderViewport(nextAddr, pri); + RenderViewport(nextAddr, pri, wideScreen); // Skip disabled viewports //if ((vpnode[0] & 0x20) != 0) @@ -849,7 +849,7 @@ void CLegacy3D::RenderViewport(UINT32 addr, int pri) // Set up viewport and projection (TO-DO: near and far clipping) glMatrixMode(GL_PROJECTION); glLoadIdentity(); - if (g_Config.wideScreen && (vpX==0) && (vpWidth>=495) && (vpY==0) && (vpHeight >= 383)) // only expand viewports that occupy whole screen + if (wideScreen && (vpX==0) && (vpWidth>=495) && (vpY==0) && (vpHeight >= 383)) // only expand viewports that occupy whole screen { // Wide screen hack only modifies X axis and not the Y FOV viewportX = 0; @@ -958,6 +958,8 @@ void CLegacy3D::RenderViewport(UINT32 addr, int pri) void CLegacy3D::RenderFrame(void) { + bool wideScreen = m_config["WideScreen"].ValueAs(); + // Begin frame ClearErrors(); // must be cleared each frame @@ -1009,7 +1011,7 @@ void CLegacy3D::RenderFrame(void) //ClearModelCache(&PolyCache); ClearDisplayList(&PolyCache); ClearDisplayList(&VROMCache); - RenderViewport(0x800000,pri); + RenderViewport(0x800000,pri,wideScreen); DrawDisplayList(&VROMCache, POLY_STATE_NORMAL); DrawDisplayList(&PolyCache, POLY_STATE_NORMAL); DrawDisplayList(&VROMCache, POLY_STATE_ALPHA); @@ -1058,9 +1060,9 @@ void CLegacy3D::AttachMemory(const UINT32 *cullingRAMLoPtr, const UINT32 *cullin DebugLog("Legacy3D attached Real3D memory regions\n"); } -void CLegacy3D::SetStep(int stepID) +void CLegacy3D::SetStepping(int stepping) { - step = stepID; + step = stepping; if ((step!=0x10) && (step!=0x15) && (step!=0x20) && (step!=0x21)) { @@ -1124,12 +1126,12 @@ bool CLegacy3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned // Get upper limit for number of texture maps to use from max number of texture units supported by video card GLint glMaxTexUnits; glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &glMaxTexUnits); - int maxTexMaps = std::max(1, std::min(g_Config.maxTexMaps, glMaxTexUnits)); + int maxTexMaps = std::max(1, std::min(m_config["MaxTexMaps"].ValueAsDefault(9), glMaxTexUnits)); // Get upper limit for extent of texture maps to use from max texture size supported by video card GLint maxTexSize; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize); - int mapExtent = std::max(1, std::min(g_Config.maxTexMapExtent, maxTexSize / 2048)); + int mapExtent = std::max(1, std::min(m_config["MaxTexMapExtent"].ValueAsDefault(4), maxTexSize / 2048)); int mapSize = 2048 * mapExtent; while (mapExtent > 1) { @@ -1147,10 +1149,8 @@ bool CLegacy3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned } // Load shaders, using multi-sheet shader if requested. - const char *vsFile = g_Config.vertexShaderFile.size() ? g_Config.vertexShaderFile.c_str() : NULL; - const char *fsFile = g_Config.fragmentShaderFile.size() ? g_Config.fragmentShaderFile.c_str() : NULL; - const char *fragmentShaderSource = (g_Config.multiTexture ? fragmentShaderMultiSheetSource : fragmentShaderSingleSheetSource); // single texture shader - if (OKAY != LoadShaderProgram(&shaderProgram,&vertexShader,&fragmentShader,vsFile,fsFile,vertexShaderSource,fragmentShaderSource)) + const char *fragmentShaderSource = (m_config["MultiTexture"].ValueAs() ? fragmentShaderMultiSheetSource : fragmentShaderSingleSheetSource); // single texture shader + if (OKAY != LoadShaderProgram(&shaderProgram,&vertexShader,&fragmentShader,m_config["VertexShader"].ValueAs(),m_config["FragmentShader"].ValueAs(),vertexShaderSource,fragmentShaderSource)) return FAIL; // Try locating default "textureMap" uniform in shader program @@ -1291,7 +1291,8 @@ bool CLegacy3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned return OKAY; } -CLegacy3D::CLegacy3D(void) +CLegacy3D::CLegacy3D(const Util::Config::Node &config) + : m_config(config) { cullingRAMLo = NULL; cullingRAMHi = NULL; diff --git a/Src/Graphics/Legacy3D/Legacy3D.h b/Src/Graphics/Legacy3D/Legacy3D.h index c7aed61..0e113e1 100644 --- a/Src/Graphics/Legacy3D/Legacy3D.h +++ b/Src/Graphics/Legacy3D/Legacy3D.h @@ -31,6 +31,7 @@ #include "Graphics/IRender3D.h" #include "Pkgs/glew.h" +#include "Util/NewConfig.h" namespace Legacy3D { @@ -223,30 +224,6 @@ struct TexSheet CLegacy3D Classes ******************************************************************************/ -/* - * CLegacy3DConfig: - * - * Settings used by CLegacy3D. - */ -class CLegacy3DConfig -{ -public: - string vertexShaderFile; // path to vertex shader or "" to use internal shader - string fragmentShaderFile; // fragment shader - unsigned maxTexMaps; // maximum number of texture maps to use (1-9) - unsigned maxTexMapExtent; // maximum extent of texture maps (where num of tex sheets per map = extent ^ 2) - bool multiTexture; // if enabled and no external fragment shader, select internal shader w/ multiple texture sheet support - - // Defaults - CLegacy3DConfig(void) - { - // strings will be clear to begin with - maxTexMaps = 9; - maxTexMapExtent = 4; - multiTexture = false; - } -}; - /* * CLegacy3D: * @@ -314,17 +291,17 @@ public: const UINT32 *vromPtr, const UINT16 *textureRAMPtr); /* - * SetStep(stepID): + * SetStepping(stepping): * * Sets the Model 3 hardware stepping, which also determines the Real3D * functionality. The default is Step 1.0. This should be called prior to * any other emulation functions and after Init(). * * Parameters: - * stepID 0x10 for Step 1.0, 0x15 for Step 1.5, 0x20 for Step 2.0, - * or 0x21 for Step 2.1. Anything else defaults to 1.0. + * stepping 0x10 for Step 1.0, 0x15 for Step 1.5, 0x20 for Step 2.0, or + * 0x21 for Step 2.1. Anything else defaults to 1.0. */ - void SetStep(int stepID); + void SetStepping(int stepping); /* * Init(xOffset, yOffset, xRes, yRes, totalXRes, totalYRes): @@ -355,16 +332,19 @@ public: * CLegacy3D(void): * ~CLegacy3D(void): * + * Parameters: + * config Configuration object. + * * Constructor and destructor. */ - CLegacy3D(void); + CLegacy3D(const Util::Config::Node &config); ~CLegacy3D(void); private: /* * Private Members */ - + // Real3D address translation const UINT32 *TranslateCullingAddress(UINT32 addr); const UINT32 *TranslateModelAddress(UINT32 addr); @@ -397,7 +377,7 @@ private: void DescendCullingNode(UINT32 addr); void DescendPointerList(UINT32 addr); void DescendNodePtr(UINT32 nodeAddr); - void RenderViewport(UINT32 addr, int pri); + void RenderViewport(UINT32 addr, int pri, bool wideScreen); // In-frame error reporting bool ErrorLocalVertexOverflow(void); @@ -407,6 +387,8 @@ private: /* * Data */ + + const Util::Config::Node &m_config; // Stepping int step; diff --git a/Src/Graphics/New3D/New3D.cpp b/Src/Graphics/New3D/New3D.cpp index db27d2d..4ca5129 100644 --- a/Src/Graphics/New3D/New3D.cpp +++ b/Src/Graphics/New3D/New3D.cpp @@ -35,9 +35,9 @@ void CNew3D::AttachMemory(const UINT32 *cullingRAMLoPtr, const UINT32 *cullingRA m_textureRAM = textureRAMPtr; } -void CNew3D::SetStep(int stepID) +void CNew3D::SetStepping(int stepping) { - m_step = stepID; + m_step = stepping; if ((m_step != 0x10) && (m_step != 0x15) && (m_step != 0x20) && (m_step != 0x21)) { m_step = 0x10; diff --git a/Src/Graphics/New3D/New3D.h b/Src/Graphics/New3D/New3D.h index 933d30a..50889c2 100644 --- a/Src/Graphics/New3D/New3D.h +++ b/Src/Graphics/New3D/New3D.h @@ -104,17 +104,17 @@ public: const UINT32 *vromPtr, const UINT16 *textureRAMPtr); /* - * SetStep(stepID): + * SetStepping(stepping): * * Sets the Model 3 hardware stepping, which also determines the Real3D * functionality. The default is Step 1.0. This should be called prior to * any other emulation functions and after Init(). * * Parameters: - * stepID 0x10 for Step 1.0, 0x15 for Step 1.5, 0x20 for Step 2.0, - * or 0x21 for Step 2.1. Anything else defaults to 1.0. + * stepping 0x10 for Step 1.0, 0x15 for Step 1.5, 0x20 for Step 2.0, or + * 0x21 for Step 2.1. Anything else defaults to 1.0. */ - void SetStep(int stepID); + void SetStepping(int stepping); /* * Init(xOffset, yOffset, xRes, yRes, totalXRes, totalYRes): diff --git a/Src/Graphics/New3D/R3DScrollFog.cpp b/Src/Graphics/New3D/R3DScrollFog.cpp index e926bab..9519a13 100644 --- a/Src/Graphics/New3D/R3DScrollFog.cpp +++ b/Src/Graphics/New3D/R3DScrollFog.cpp @@ -80,7 +80,7 @@ void R3DScrollFog::DrawScrollFog(float r, float g, float b, float a) void R3DScrollFog::AllocResources() { - bool success = LoadShaderProgram(&m_shaderProgram, &m_vertexShader, &m_fragmentShader, nullptr, nullptr, vertexShaderFog, fragmentShaderFog); + bool success = LoadShaderProgram(&m_shaderProgram, &m_vertexShader, &m_fragmentShader, std::string(), std::string(), vertexShaderFog, fragmentShaderFog); m_locMVP = glGetUniformLocation(m_shaderProgram, "mvp"); m_locFogColour = glGetUniformLocation(m_shaderProgram, "fogColour"); diff --git a/Src/Graphics/New3D/R3DShader.cpp b/Src/Graphics/New3D/R3DShader.cpp index 5c2560c..b84d5a8 100644 --- a/Src/Graphics/New3D/R3DShader.cpp +++ b/Src/Graphics/New3D/R3DShader.cpp @@ -195,7 +195,7 @@ bool R3DShader::LoadShader(const char* vertexShader, const char* fragmentShader) fShader = fragmentShaderBasic; } - success = LoadShaderProgram(&m_shaderProgram, &m_vertexShader, &m_fragmentShader, nullptr, nullptr, vShader, fShader); + success = LoadShaderProgram(&m_shaderProgram, &m_vertexShader, &m_fragmentShader, std::string(), std::string(), vShader, fShader); m_locTexture1 = glGetUniformLocation(m_shaderProgram, "tex1"); m_locTexture2 = glGetUniformLocation(m_shaderProgram, "tex2"); diff --git a/Src/Graphics/Render2D.cpp b/Src/Graphics/Render2D.cpp index 2c3b10f..1d66291 100644 --- a/Src/Graphics/Render2D.cpp +++ b/Src/Graphics/Render2D.cpp @@ -638,7 +638,7 @@ void CRender2D::AttachVRAM(const uint8_t *vramPtr) bool CRender2D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXRes, unsigned totalYRes) { // Load shaders - if (OKAY != LoadShaderProgram(&m_shaderProgram, &m_vertexShader, &m_fragmentShader, 0, 0, s_vertexShaderSource, s_fragmentShaderSource)) + if (OKAY != LoadShaderProgram(&m_shaderProgram, &m_vertexShader, &m_fragmentShader, std::string(), std::string(), s_vertexShaderSource, s_fragmentShaderSource)) return FAIL; // Get locations of the uniforms diff --git a/Src/Graphics/Shader.cpp b/Src/Graphics/Shader.cpp index 45d6722..5880e6e 100644 --- a/Src/Graphics/Shader.cpp +++ b/Src/Graphics/Shader.cpp @@ -82,7 +82,7 @@ static char *LoadShaderSource(const char *file) return buf; } -bool LoadShaderProgram(GLuint *shaderProgramPtr, GLuint *vertexShaderPtr, GLuint *fragmentShaderPtr, const char *vsFile, const char *fsFile, const char *vsString, const char *fsString) +bool LoadShaderProgram(GLuint *shaderProgramPtr, GLuint *vertexShaderPtr, GLuint *fragmentShaderPtr, std::string vsFile, std::string fsFile, const char *vsString, const char *fsString) { char infoLog[2048]; const char *vsSource, *fsSource; // source code @@ -91,12 +91,12 @@ bool LoadShaderProgram(GLuint *shaderProgramPtr, GLuint *vertexShaderPtr, GLuint bool ret = OKAY; // Load shaders from files if specified - if (vsFile != NULL) - vsSource = LoadShaderSource(vsFile); + if (!vsFile.empty()) + vsSource = LoadShaderSource(vsFile.c_str()); else vsSource = vsString; - if (fsFile != NULL) - fsSource = LoadShaderSource(fsFile); + if (!fsFile.empty()) + fsSource = LoadShaderSource(fsFile.c_str()); else fsSource = fsString; if (vsSource == NULL || fsSource == NULL) @@ -161,9 +161,9 @@ bool LoadShaderProgram(GLuint *shaderProgramPtr, GLuint *vertexShaderPtr, GLuint // Clean up and quit Quit: - if ((vsSource != NULL) && (vsFile != NULL)) // loaded from file, must delete + if ((vsSource != NULL) && !vsFile.empty()) // loaded from file, must delete delete [] vsSource; - if ((fsSource != NULL) && (fsFile != NULL)) // "" + if ((fsSource != NULL) && !fsFile.empty()) // "" delete [] fsSource; return ret; } diff --git a/Src/Graphics/Shader.h b/Src/Graphics/Shader.h index 60a00f2..7b0ece6 100644 --- a/Src/Graphics/Shader.h +++ b/Src/Graphics/Shader.h @@ -29,6 +29,7 @@ #define INCLUDED_SHADER_H #include "Pkgs/glew.h" +#include /* * LoadShaderProgram(shaderProgramPtr, vertexShaderPtr, fragmentShaderPtr, @@ -52,8 +53,8 @@ * OKAY is successfully loaded, otherwise FAIL. Prints own error messages. */ extern bool LoadShaderProgram(GLuint *shaderProgramPtr, GLuint *vertexShaderPtr, - GLuint *fragmentShaderPtr, const char *vsFile, - const char *fsFile, const char *vsString, + GLuint *fragmentShaderPtr, std::string vsFile, + std::string fsFile, const char *vsString, const char *fsString); /* diff --git a/Src/Inputs/Input.cpp b/Src/Inputs/Input.cpp index 954d62e..fcfed33 100644 --- a/Src/Inputs/Input.cpp +++ b/Src/Inputs/Input.cpp @@ -83,29 +83,29 @@ const char* CInput::GetInputGroup() { switch (gameFlags) { - case GAME_INPUT_UI: return "User Interface Controls"; - case GAME_INPUT_COMMON: return "Common Controls"; - case GAME_INPUT_JOYSTICK1: // Fall through to below - case GAME_INPUT_JOYSTICK2: return "4-Way Joysticks"; - case GAME_INPUT_FIGHTING: return "Fighting Game Buttons"; - case GAME_INPUT_SPIKEOUT: return "Spikeout Buttons"; - case GAME_INPUT_SOCCER: return "Virtua Striker Buttons"; - case GAME_INPUT_VEHICLE: return "Racing Game Steering Controls"; - case GAME_INPUT_SHIFT4: return "Racing Game Gear 4-Way Shift"; - case GAME_INPUT_SHIFTUPDOWN: return "Racing Game Gear Up/Down Shift"; - case GAME_INPUT_VR4: return "Racing Game 4 VR View Buttons"; - case GAME_INPUT_VIEWCHANGE: return "Racing Game View Change"; - case GAME_INPUT_HANDBRAKE: return "Racing Game Handbrake"; - case GAME_INPUT_HARLEY: return "Harley Davidson Controls"; - case GAME_INPUT_TWIN_JOYSTICKS: return "Virtual On Controls"; - case GAME_INPUT_ANALOG_JOYSTICK: return "Analog Joystick"; - case GAME_INPUT_GUN1: // Fall through to below - case GAME_INPUT_GUN2: return "Light Guns"; - case GAME_INPUT_ANALOG_GUN1: // Fall through to below - case GAME_INPUT_ANALOG_GUN2: return "Analog Guns"; - case GAME_INPUT_SKI: return "Ski Controls"; - case GAME_INPUT_MAGTRUCK: return "Magical Truck Controls"; - case GAME_INPUT_FISHING: return "Fishing Controls"; + case Game::INPUT_UI: return "User Interface Controls"; + case Game::INPUT_COMMON: return "Common Controls"; + case Game::INPUT_JOYSTICK1: // Fall through to below + case Game::INPUT_JOYSTICK2: return "4-Way Joysticks"; + case Game::INPUT_FIGHTING: return "Fighting Game Buttons"; + case Game::INPUT_SPIKEOUT: return "Spikeout Buttons"; + case Game::INPUT_SOCCER: return "Virtua Striker Buttons"; + case Game::INPUT_VEHICLE: return "Racing Game Steering Controls"; + case Game::INPUT_SHIFT4: return "Racing Game Gear 4-Way Shift"; + case Game::INPUT_SHIFTUPDOWN: return "Racing Game Gear Up/Down Shift"; + case Game::INPUT_VR4: return "Racing Game 4 VR View Buttons"; + case Game::INPUT_VIEWCHANGE: return "Racing Game View Change"; + case Game::INPUT_HANDBRAKE: return "Racing Game Handbrake"; + case Game::INPUT_HARLEY: return "Harley Davidson Controls"; + case Game::INPUT_TWIN_JOYSTICKS: return "Virtual On Controls"; + case Game::INPUT_ANALOG_JOYSTICK: return "Analog Joystick"; + case Game::INPUT_GUN1: // Fall through to below + case Game::INPUT_GUN2: return "Light Guns"; + case Game::INPUT_ANALOG_GUN1: // Fall through to below + case Game::INPUT_ANALOG_GUN2: return "Analog Guns"; + case Game::INPUT_SKI: return "Ski Controls"; + case Game::INPUT_MAGTRUCK: return "Magical Truck Controls"; + case Game::INPUT_FISHING: return "Fishing Controls"; default: return "Misc"; } } @@ -147,6 +147,38 @@ void CInput::ResetToDefaultMapping() SetMapping(m_defaultMapping); } +void CInput::LoadFromConfig(const Util::Config::Node &config) +{ + // See if input is configurable + if (IsConfigurable()) + { + // If so, check INI file for mapping string + string key("Input"); + key.append(id); + string mapping; + auto *node = config.TryGet(key); + if (node) + { + // If found, then set mapping string + mapping = node->ValueAs(); + SetMapping(mapping.c_str()); + return; + } + } + + // If input has not been configured, then force recreation of source anyway since input system settings may have changed + CreateSource(); +} + +void CInput::StoreToConfig(Util::Config::Node *config) +{ + if (!IsConfigurable()) + return; + string key("Input"); + key.append(id); + config->Set(key, m_mapping); +} + void CInput::ReadFromINIFile(CINIFile *ini, const char *section) { // See if input is configurable diff --git a/Src/Inputs/Input.h b/Src/Inputs/Input.h index 1babc6e..ee0d199 100644 --- a/Src/Inputs/Input.h +++ b/Src/Inputs/Input.h @@ -23,21 +23,20 @@ * Input.h * * Header file for base input class, CInput, defining an input source. Also - * defines GAME_INPUT_UI. + * defines Game::INPUT_UI. */ #ifndef INCLUDED_INPUT_H #define INCLUDED_INPUT_H #include "Types.h" +#include "Game.h" +#include "Util/NewConfig.h" class CInputSource; class CInputSystem; class CINIFile; -// Special game input flag for UI controls -#define GAME_INPUT_UI 0 - // Flags for inputs #define INPUT_FLAGS_SWITCH 0x0001 #define INPUT_FLAGS_ANALOG 0x0002 @@ -152,13 +151,15 @@ public: void ResetToDefaultMapping(); /* - * Reads the input's mapping(s) from the given INI file, as well as any other settings. + * Loads the input's mapping(s) from the given config object, as well as any other settings. */ + virtual void LoadFromConfig(const Util::Config::Node &config); virtual void ReadFromINIFile(CINIFile *ini, const char *section); /* - * Writes the current input mapping(s) to the given INI file, as well as any other settings. + * Stores the current input mapping(s) to the given config object, as well as any other settings. */ + virtual void StoreToConfig(Util::Config::Node *config); virtual void WriteToINIFile(CINIFile *ini, const char *section); void InputSystemChanged(); @@ -207,13 +208,13 @@ public: inline bool CInput::IsUIInput() { - return gameFlags == GAME_INPUT_UI; + return gameFlags == Game::INPUT_UI; } inline bool CInput::IsConfigurable() { // All inputs except UI and virtual ones can be configured by the user - return (gameFlags != GAME_INPUT_UI) && !(flags & INPUT_FLAGS_VIRTUAL); + return (gameFlags != Game::INPUT_UI) && !(flags & INPUT_FLAGS_VIRTUAL); } inline bool CInput::IsVirtual() diff --git a/Src/Inputs/InputSystem.cpp b/Src/Inputs/InputSystem.cpp index 8285266..337d1a2 100644 --- a/Src/Inputs/InputSystem.cpp +++ b/Src/Inputs/InputSystem.cpp @@ -48,359 +48,359 @@ unsigned CInputSystem::totalSrcsReleased = 0; const char *CInputSystem::s_validKeyNames[] = { - // General keys - "BACKSPACE", - "TAB", - "CLEAR", - "RETURN", - "PAUSE", - "ESCAPE", - "SPACE", - "EXCLAIM", - "DBLQUOTE", - "HASH", - "DOLLAR", - "AMPERSAND", - "QUOTE", - "LEFTPAREN", - "RIGHTPAREN", - "ASTERISK", - "PLUS", - "COMMA", - "MINUS", - "PERIOD", - "SLASH", - "0", - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "COLON", - "SEMICOLON", - "LESS", - "EQUALS", - "GREATER", - "QUESTION", - "AT", - "LEFTBRACKET", - "BACKSLASH", - "RIGHTBRACKET", - "CARET", - "UNDERSCORE", - "BACKQUOTE", - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - "I", - "J", - "K", - "L", - "M", - "N", - "O", - "P", - "Q", - "R", - "S", - "T", - "U", - "V", - "W", - "X", - "Y", - "Z", - "DEL", - - // Keypad - "KEYPAD0", - "KEYPAD1", - "KEYPAD2", - "KEYPAD3", - "KEYPAD4", - "KEYPAD5", - "KEYPAD6", - "KEYPAD7", - "KEYPAD8", - "KEYPAD9", - "KEYPADPERIOD", - "KEYPADDIVIDE", - "KEYPADMULTIPLY", - "KEYPADMINUS", - "KEYPADPLUS", - "KEYPADENTER", - "KEYPADEQUALS", - - // Arrows + Home/End Pad - "UP", - "DOWN", - "RIGHT", - "LEFT", - "INSERT", - "HOME", - "END", - "PGUP", - "PGDN", + // General keys + "BACKSPACE", + "TAB", + "CLEAR", + "RETURN", + "PAUSE", + "ESCAPE", + "SPACE", + "EXCLAIM", + "DBLQUOTE", + "HASH", + "DOLLAR", + "AMPERSAND", + "QUOTE", + "LEFTPAREN", + "RIGHTPAREN", + "ASTERISK", + "PLUS", + "COMMA", + "MINUS", + "PERIOD", + "SLASH", + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "COLON", + "SEMICOLON", + "LESS", + "EQUALS", + "GREATER", + "QUESTION", + "AT", + "LEFTBRACKET", + "BACKSLASH", + "RIGHTBRACKET", + "CARET", + "UNDERSCORE", + "BACKQUOTE", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "DEL", + + // Keypad + "KEYPAD0", + "KEYPAD1", + "KEYPAD2", + "KEYPAD3", + "KEYPAD4", + "KEYPAD5", + "KEYPAD6", + "KEYPAD7", + "KEYPAD8", + "KEYPAD9", + "KEYPADPERIOD", + "KEYPADDIVIDE", + "KEYPADMULTIPLY", + "KEYPADMINUS", + "KEYPADPLUS", + "KEYPADENTER", + "KEYPADEQUALS", + + // Arrows + Home/End Pad + "UP", + "DOWN", + "RIGHT", + "LEFT", + "INSERT", + "HOME", + "END", + "PGUP", + "PGDN", - // Function Key - "F1", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - "F8", - "F9", - "F10", - "F11", - "F12", - "F13", - "F14", - "F15", + // Function Key + "F1", + "F2", + "F3", + "F4", + "F5", + "F6", + "F7", + "F8", + "F9", + "F10", + "F11", + "F12", + "F13", + "F14", + "F15", - // Modifier Keys - "NUMLOCK", - "CAPSLOCK", - "SCROLLLOCK", - "SHIFT", - "RIGHTSHIFT", - "LEFTSHIFT", - "CTRL", - "RIGHTCTRL", - "LEFTCTRL", - "ALT", - "RIGHTALT", - "LEFTALT", - "RIGHTMETA", - "LEFTMETA", - "RIGHTWINDOWS", - "LEFTWINDOWS", - "ALTGR", - "COMPOSE", + // Modifier Keys + "NUMLOCK", + "CAPSLOCK", + "SCROLLLOCK", + "SHIFT", + "RIGHTSHIFT", + "LEFTSHIFT", + "CTRL", + "RIGHTCTRL", + "LEFTCTRL", + "ALT", + "RIGHTALT", + "LEFTALT", + "RIGHTMETA", + "LEFTMETA", + "RIGHTWINDOWS", + "LEFTWINDOWS", + "ALTGR", + "COMPOSE", - // Other - "HELP", - "PRINT", - "SYSREQ", - "BREAK", - "MENU", - "POWER", - "EURO", - "UNDO" + // Other + "HELP", + "PRINT", + "SYSREQ", + "BREAK", + "MENU", + "POWER", + "EURO", + "UNDO" }; MousePartsStruct CInputSystem::s_mseParts[] = { - // X Axis (Axis 1) - { "XAXIS", MouseXAxis }, - { "XAXIS_INV", MouseXAxisInv }, - { "XAXIS_POS", MouseXAxisPos }, - { "XAXIS_NEG", MouseXAxisNeg }, - { "RIGHT", MouseXAxisPos }, - { "LEFT", MouseXAxisNeg }, - { "AXIS1", MouseXAxis }, - { "AXIS1_INV", MouseXAxisInv }, - { "AXIS1_POS", MouseXAxisPos }, - { "AXIS1_NEG", MouseXAxisNeg }, - - // Y Axis (Axis 2) - { "YAXIS", MouseYAxis }, - { "YAXIS_INV", MouseYAxisInv }, - { "YAXIS_POS", MouseYAxisPos }, - { "YAXIS_NEG", MouseYAxisNeg }, - { "DOWN", MouseYAxisPos }, - { "UP", MouseYAxisNeg }, - { "AXIS2", MouseYAxis }, - { "AXIS2_INV", MouseYAxisInv }, - { "AXIS2_POS", MouseYAxisPos }, - { "AXIS2_NEG", MouseYAxisNeg }, + // X Axis (Axis 1) + { "XAXIS", MouseXAxis }, + { "XAXIS_INV", MouseXAxisInv }, + { "XAXIS_POS", MouseXAxisPos }, + { "XAXIS_NEG", MouseXAxisNeg }, + { "RIGHT", MouseXAxisPos }, + { "LEFT", MouseXAxisNeg }, + { "AXIS1", MouseXAxis }, + { "AXIS1_INV", MouseXAxisInv }, + { "AXIS1_POS", MouseXAxisPos }, + { "AXIS1_NEG", MouseXAxisNeg }, + + // Y Axis (Axis 2) + { "YAXIS", MouseYAxis }, + { "YAXIS_INV", MouseYAxisInv }, + { "YAXIS_POS", MouseYAxisPos }, + { "YAXIS_NEG", MouseYAxisNeg }, + { "DOWN", MouseYAxisPos }, + { "UP", MouseYAxisNeg }, + { "AXIS2", MouseYAxis }, + { "AXIS2_INV", MouseYAxisInv }, + { "AXIS2_POS", MouseYAxisPos }, + { "AXIS2_NEG", MouseYAxisNeg }, - // Z/Wheel Axis (Axis 3) - { "ZAXIS", MouseZAxis }, - { "ZAXIS_INV", MouseZAxisInv }, - { "ZAXIS_POS", MouseZAxisPos }, - { "ZAXIS_NEG", MouseZAxisNeg }, - { "WHEEL_UP", MouseZAxisPos }, - { "WHEEL_DOWN", MouseZAxisNeg }, - { "AXIS3", MouseZAxis }, - { "AXIS3_INV", MouseZAxisInv }, - { "AXIS3_POS", MouseZAxisPos }, - { "AXIS3_NEG", MouseZAxisNeg }, + // Z/Wheel Axis (Axis 3) + { "ZAXIS", MouseZAxis }, + { "ZAXIS_INV", MouseZAxisInv }, + { "ZAXIS_POS", MouseZAxisPos }, + { "ZAXIS_NEG", MouseZAxisNeg }, + { "WHEEL_UP", MouseZAxisPos }, + { "WHEEL_DOWN", MouseZAxisNeg }, + { "AXIS3", MouseZAxis }, + { "AXIS3_INV", MouseZAxisInv }, + { "AXIS3_POS", MouseZAxisPos }, + { "AXIS3_NEG", MouseZAxisNeg }, - // Left/Middle/Right Buttons (Buttons 1-3) - { "LEFT_BUTTON", MouseButtonLeft }, - { "BUTTON1", MouseButtonLeft }, - { "MIDDLE_BUTTON", MouseButtonMiddle }, - { "BUTTON2", MouseButtonMiddle }, - { "RIGHT_BUTTON", MouseButtonRight }, - { "BUTTON3", MouseButtonRight }, + // Left/Middle/Right Buttons (Buttons 1-3) + { "LEFT_BUTTON", MouseButtonLeft }, + { "BUTTON1", MouseButtonLeft }, + { "MIDDLE_BUTTON", MouseButtonMiddle }, + { "BUTTON2", MouseButtonMiddle }, + { "RIGHT_BUTTON", MouseButtonRight }, + { "BUTTON3", MouseButtonRight }, - // Extra Buttons (Buttons 4 & 5) - { "BUTTONX1", MouseButtonX1 }, - { "BUTTON4", MouseButtonX1 }, - { "BUTTONX2", MouseButtonX2 }, - { "BUTTON5", MouseButtonX2 }, + // Extra Buttons (Buttons 4 & 5) + { "BUTTONX1", MouseButtonX1 }, + { "BUTTON4", MouseButtonX1 }, + { "BUTTONX2", MouseButtonX2 }, + { "BUTTON5", MouseButtonX2 }, - // List terminator - { NULL, MouseUnknown } + // List terminator + { NULL, MouseUnknown } }; JoyPartsStruct CInputSystem::s_joyParts[] = { - // X-Axis (Axis 1) - { "XAXIS", JoyXAxis }, - { "XAXIS_INV", JoyXAxisInv }, - { "XAXIS_POS", JoyXAxisPos }, - { "XAXIS_NEG", JoyXAxisNeg }, - { "RIGHT", JoyXAxisPos }, - { "LEFT", JoyXAxisNeg }, - { "AXIS1", JoyXAxis }, - { "AXIS1_INV", JoyXAxisInv }, - { "AXIS1_POS", JoyXAxisPos }, - { "AXIS1_NEG", JoyXAxisNeg }, - - // Y-Axis (Axis 2) - { "YAXIS", JoyYAxis }, - { "YAXIS_INV", JoyYAxisInv }, - { "YAXIS_POS", JoyYAxisPos }, - { "YAXIS_NEG", JoyYAxisNeg }, - { "DOWN", JoyYAxisPos }, - { "UP", JoyYAxisNeg }, - { "AXIS2", JoyYAxis }, - { "AXIS2_INV", JoyYAxisInv }, - { "AXIS2_POS", JoyYAxisPos }, - { "AXIS2_NEG", JoyYAxisNeg }, - - // Z-Axis (Axis 3) - { "ZAXIS", JoyZAxis }, - { "ZAXIS_INV", JoyZAxisInv }, - { "ZAXIS_POS", JoyZAxisPos }, - { "ZAXIS_NEG", JoyZAxisNeg }, - { "AXIS3", JoyZAxis }, - { "AXIS3_INV", JoyZAxisInv }, - { "AXIS3_POS", JoyZAxisPos }, - { "AXIS3_NEG", JoyZAxisNeg }, + // X-Axis (Axis 1) + { "XAXIS", JoyXAxis }, + { "XAXIS_INV", JoyXAxisInv }, + { "XAXIS_POS", JoyXAxisPos }, + { "XAXIS_NEG", JoyXAxisNeg }, + { "RIGHT", JoyXAxisPos }, + { "LEFT", JoyXAxisNeg }, + { "AXIS1", JoyXAxis }, + { "AXIS1_INV", JoyXAxisInv }, + { "AXIS1_POS", JoyXAxisPos }, + { "AXIS1_NEG", JoyXAxisNeg }, + + // Y-Axis (Axis 2) + { "YAXIS", JoyYAxis }, + { "YAXIS_INV", JoyYAxisInv }, + { "YAXIS_POS", JoyYAxisPos }, + { "YAXIS_NEG", JoyYAxisNeg }, + { "DOWN", JoyYAxisPos }, + { "UP", JoyYAxisNeg }, + { "AXIS2", JoyYAxis }, + { "AXIS2_INV", JoyYAxisInv }, + { "AXIS2_POS", JoyYAxisPos }, + { "AXIS2_NEG", JoyYAxisNeg }, + + // Z-Axis (Axis 3) + { "ZAXIS", JoyZAxis }, + { "ZAXIS_INV", JoyZAxisInv }, + { "ZAXIS_POS", JoyZAxisPos }, + { "ZAXIS_NEG", JoyZAxisNeg }, + { "AXIS3", JoyZAxis }, + { "AXIS3_INV", JoyZAxisInv }, + { "AXIS3_POS", JoyZAxisPos }, + { "AXIS3_NEG", JoyZAxisNeg }, - // RX-Axis (Axis 4) - { "RXAXIS", JoyRXAxis }, - { "RXAXIS_INV", JoyRXAxisInv }, - { "RXAXIS_POS", JoyRXAxisPos }, - { "RXAXIS_NEG", JoyRXAxisNeg }, - { "AXIS4", JoyRXAxis }, - { "AXIS4_INV", JoyRXAxisInv }, - { "AXIS4_POS", JoyRXAxisPos }, - { "AXIS4_NEG", JoyRXAxisNeg }, + // RX-Axis (Axis 4) + { "RXAXIS", JoyRXAxis }, + { "RXAXIS_INV", JoyRXAxisInv }, + { "RXAXIS_POS", JoyRXAxisPos }, + { "RXAXIS_NEG", JoyRXAxisNeg }, + { "AXIS4", JoyRXAxis }, + { "AXIS4_INV", JoyRXAxisInv }, + { "AXIS4_POS", JoyRXAxisPos }, + { "AXIS4_NEG", JoyRXAxisNeg }, - // RY-Axis (Axis 5) - { "RYAXIS", JoyRYAxis }, - { "RYAXIS_INV", JoyRYAxisInv }, - { "RYAXIS_POS", JoyRYAxisPos }, - { "RYAXIS_NEG", JoyRYAxisNeg }, - { "AXIS5", JoyRYAxis }, - { "AXIS5_INV", JoyRYAxisInv }, - { "AXIS5_POS", JoyRYAxisPos }, - { "AXIS5_NEG", JoyRYAxisNeg }, - - // RZ-Axis (Axis 6) - { "RZAXIS", JoyRZAxis }, - { "RZAXIS_INV", JoyRZAxisInv }, - { "RZAXIS_POS", JoyRZAxisPos }, - { "RZAXIS_NEG", JoyRZAxisNeg }, - { "AXIS6", JoyRZAxis }, - { "AXIS6_INV", JoyRZAxisInv }, - { "AXIS6_POS", JoyRZAxisPos }, - { "AXIS6_NEG", JoyRZAxisNeg }, + // RY-Axis (Axis 5) + { "RYAXIS", JoyRYAxis }, + { "RYAXIS_INV", JoyRYAxisInv }, + { "RYAXIS_POS", JoyRYAxisPos }, + { "RYAXIS_NEG", JoyRYAxisNeg }, + { "AXIS5", JoyRYAxis }, + { "AXIS5_INV", JoyRYAxisInv }, + { "AXIS5_POS", JoyRYAxisPos }, + { "AXIS5_NEG", JoyRYAxisNeg }, + + // RZ-Axis (Axis 6) + { "RZAXIS", JoyRZAxis }, + { "RZAXIS_INV", JoyRZAxisInv }, + { "RZAXIS_POS", JoyRZAxisPos }, + { "RZAXIS_NEG", JoyRZAxisNeg }, + { "AXIS6", JoyRZAxis }, + { "AXIS6_INV", JoyRZAxisInv }, + { "AXIS6_POS", JoyRZAxisPos }, + { "AXIS6_NEG", JoyRZAxisNeg }, - // Slider 1 (Axis 7) - { "SLIDER1", JoyS1Axis }, - { "SLIDER1_INV", JoyS1AxisInv }, - { "SLIDER1_POS", JoyS1AxisPos }, - { "SLIDER1_NEG", JoyS1AxisNeg }, - { "AXIS7", JoyS1Axis }, - { "AXIS7_INV", JoyS1AxisInv }, - { "AXIS7_POS", JoyS1AxisPos }, - { "AXIS7_NEG", JoyS1AxisNeg }, + // Slider 1 (Axis 7) + { "SLIDER1", JoyS1Axis }, + { "SLIDER1_INV", JoyS1AxisInv }, + { "SLIDER1_POS", JoyS1AxisPos }, + { "SLIDER1_NEG", JoyS1AxisNeg }, + { "AXIS7", JoyS1Axis }, + { "AXIS7_INV", JoyS1AxisInv }, + { "AXIS7_POS", JoyS1AxisPos }, + { "AXIS7_NEG", JoyS1AxisNeg }, - // Slider 2 (Axis 8) - { "SLIDER2", JoyS1Axis }, - { "SLIDER2_INV", JoyS1AxisInv }, - { "SLIDER2_POS", JoyS1AxisPos }, - { "SLIDER2_NEG", JoyS1AxisNeg }, - { "AXIS8", JoyS1Axis }, - { "AXIS8_INV", JoyS1AxisInv }, - { "AXIS8_POS", JoyS1AxisPos }, - { "AXIS8_NEG", JoyS1AxisNeg }, + // Slider 2 (Axis 8) + { "SLIDER2", JoyS1Axis }, + { "SLIDER2_INV", JoyS1AxisInv }, + { "SLIDER2_POS", JoyS1AxisPos }, + { "SLIDER2_NEG", JoyS1AxisNeg }, + { "AXIS8", JoyS1Axis }, + { "AXIS8_INV", JoyS1AxisInv }, + { "AXIS8_POS", JoyS1AxisPos }, + { "AXIS8_NEG", JoyS1AxisNeg }, - // POV Hat 1 - { "POV1_UP", JoyPOV0Up }, - { "POV1_DOWN", JoyPOV0Down }, - { "POV1_LEFT", JoyPOV0Left }, - { "POV1_RIGHT", JoyPOV0Right }, + // POV Hat 1 + { "POV1_UP", JoyPOV0Up }, + { "POV1_DOWN", JoyPOV0Down }, + { "POV1_LEFT", JoyPOV0Left }, + { "POV1_RIGHT", JoyPOV0Right }, - // POV Hat 2 - { "POV2_UP", JoyPOV1Up }, - { "POV2_DOWN", JoyPOV1Down }, - { "POV2_LEFT", JoyPOV1Left }, - { "POV2_RIGHT", JoyPOV1Right }, + // POV Hat 2 + { "POV2_UP", JoyPOV1Up }, + { "POV2_DOWN", JoyPOV1Down }, + { "POV2_LEFT", JoyPOV1Left }, + { "POV2_RIGHT", JoyPOV1Right }, - // POV Hat 3 - { "POV3_UP", JoyPOV2Up }, - { "POV3_DOWN", JoyPOV2Down }, - { "POV3_LEFT", JoyPOV2Left }, - { "POV3_RIGHT", JoyPOV2Right }, + // POV Hat 3 + { "POV3_UP", JoyPOV2Up }, + { "POV3_DOWN", JoyPOV2Down }, + { "POV3_LEFT", JoyPOV2Left }, + { "POV3_RIGHT", JoyPOV2Right }, - // POV Hat 4 - { "POV4_UP", JoyPOV3Up }, - { "POV4_DOWN", JoyPOV3Down }, - { "POV4_LEFT", JoyPOV3Left }, - { "POV4_RIGHT", JoyPOV3Right }, + // POV Hat 4 + { "POV4_UP", JoyPOV3Up }, + { "POV4_DOWN", JoyPOV3Down }, + { "POV4_LEFT", JoyPOV3Left }, + { "POV4_RIGHT", JoyPOV3Right }, - // Buttons 1-32 - { "BUTTON1", JoyButton0 }, - { "BUTTON2", JoyButton1 }, - { "BUTTON3", JoyButton2 }, - { "BUTTON4", JoyButton3 }, - { "BUTTON5", JoyButton4 }, - { "BUTTON6", JoyButton5 }, - { "BUTTON7", JoyButton6 }, - { "BUTTON8", JoyButton7 }, - { "BUTTON9", JoyButton8 }, - { "BUTTON10", JoyButton9 }, - { "BUTTON11", JoyButton10 }, - { "BUTTON12", JoyButton11 }, - { "BUTTON13", JoyButton12 }, - { "BUTTON14", JoyButton13 }, - { "BUTTON15", JoyButton14 }, - { "BUTTON16", JoyButton15 }, - { "BUTTON17", JoyButton16 }, - { "BUTTON18", JoyButton17 }, - { "BUTTON19", JoyButton18 }, - { "BUTTON20", JoyButton19 }, - { "BUTTON21", JoyButton20 }, - { "BUTTON22", JoyButton21 }, - { "BUTTON23", JoyButton22 }, - { "BUTTON24", JoyButton23 }, - { "BUTTON25", JoyButton24 }, - { "BUTTON26", JoyButton25 }, - { "BUTTON27", JoyButton26 }, - { "BUTTON28", JoyButton27 }, - { "BUTTON29", JoyButton28 }, - { "BUTTON30", JoyButton29 }, - { "BUTTON31", JoyButton30 }, - { "BUTTON32", JoyButton31 }, + // Buttons 1-32 + { "BUTTON1", JoyButton0 }, + { "BUTTON2", JoyButton1 }, + { "BUTTON3", JoyButton2 }, + { "BUTTON4", JoyButton3 }, + { "BUTTON5", JoyButton4 }, + { "BUTTON6", JoyButton5 }, + { "BUTTON7", JoyButton6 }, + { "BUTTON8", JoyButton7 }, + { "BUTTON9", JoyButton8 }, + { "BUTTON10", JoyButton9 }, + { "BUTTON11", JoyButton10 }, + { "BUTTON12", JoyButton11 }, + { "BUTTON13", JoyButton12 }, + { "BUTTON14", JoyButton13 }, + { "BUTTON15", JoyButton14 }, + { "BUTTON16", JoyButton15 }, + { "BUTTON17", JoyButton16 }, + { "BUTTON18", JoyButton17 }, + { "BUTTON19", JoyButton18 }, + { "BUTTON20", JoyButton19 }, + { "BUTTON21", JoyButton20 }, + { "BUTTON22", JoyButton21 }, + { "BUTTON23", JoyButton22 }, + { "BUTTON24", JoyButton23 }, + { "BUTTON25", JoyButton24 }, + { "BUTTON26", JoyButton25 }, + { "BUTTON27", JoyButton26 }, + { "BUTTON28", JoyButton27 }, + { "BUTTON29", JoyButton28 }, + { "BUTTON30", JoyButton29 }, + { "BUTTON31", JoyButton30 }, + { "BUTTON32", JoyButton31 }, - // List terminator - { NULL, JoyUnknown } + // List terminator + { NULL, JoyUnknown } }; const char *CInputSystem::s_axisIds[] = { "X", "Y", "Z", "RX", "RY", "RZ", "S1", "S2" }; @@ -409,2059 +409,2284 @@ const char *CInputSystem::s_axisNames[] = { "X-Axis", "Y-Axis", "Z-Axis", "RX-Ax const char *CInputSystem::GetDefaultAxisName(int axisNum) { - return (axisNum >= 0 && axisNum < NUM_JOY_AXES ? s_axisNames[axisNum] : ""); + return (axisNum >= 0 && axisNum < NUM_JOY_AXES ? s_axisNames[axisNum] : ""); } -CInputSystem::CInputSystem(const char *systemName) : - m_dispX(0), m_dispY(0), m_dispW(0), m_dispH(0), m_grabMouse(false), name(systemName) +CInputSystem::CInputSystem(const char *systemName) + : m_dispX(0), + m_dispY(0), + m_dispW(0), + m_dispH(0), + m_grabMouse(false), + name(systemName) { - m_emptySource = new CMultiInputSource(); - m_emptySource->Acquire(); + m_emptySource = new CMultiInputSource(); + m_emptySource->Acquire(); } CInputSystem::~CInputSystem() { - m_emptySource->Release(); + m_emptySource->Release(); - ClearSettings(); - ClearSourceCache(true); + ClearSettings(); + ClearSourceCache(true); #ifdef DEBUG - if (totalSrcsAcquired != totalSrcsReleased) - printf("WARNING - number of input source acquisitions (%u) does not equal number of releases (%u)\n", totalSrcsAcquired, totalSrcsReleased); + if (totalSrcsAcquired != totalSrcsReleased) + printf("WARNING - number of input source acquisitions (%u) does not equal number of releases (%u)\n", totalSrcsAcquired, totalSrcsReleased); #endif } void CInputSystem::CreateSourceCache() { - // Create cache for key sources - m_anyKeySources = new CInputSource*[NUM_VALID_KEYS]; - memset(m_anyKeySources, 0, sizeof(CInputSource*) * NUM_VALID_KEYS); - if (m_numKbds != ANY_KEYBOARD) - { - m_keySources = new CInputSource**[m_numKbds]; - for (int kbdNum = 0; kbdNum < m_numKbds; kbdNum++) - { - m_keySources[kbdNum] = new CInputSource*[NUM_VALID_KEYS]; - memset(m_keySources[kbdNum], 0, sizeof(CInputSource*) * NUM_VALID_KEYS); - } - } + // Create cache for key sources + m_anyKeySources = new CInputSource*[NUM_VALID_KEYS]; + memset(m_anyKeySources, 0, sizeof(CInputSource*) * NUM_VALID_KEYS); + if (m_numKbds != ANY_KEYBOARD) + { + m_keySources = new CInputSource**[m_numKbds]; + for (int kbdNum = 0; kbdNum < m_numKbds; kbdNum++) + { + m_keySources[kbdNum] = new CInputSource*[NUM_VALID_KEYS]; + memset(m_keySources[kbdNum], 0, sizeof(CInputSource*) * NUM_VALID_KEYS); + } + } - // Create cache for mouse sources - m_anyMseSources = new CInputSource*[NUM_MOUSE_PARTS]; - memset(m_anyMseSources, 0, sizeof(CInputSource*) * NUM_MOUSE_PARTS); - if (m_numMice != ANY_MOUSE) - { - m_mseSources = new CInputSource**[m_numMice]; - for (int mseNum = 0; mseNum < m_numMice; mseNum++) - { - m_mseSources[mseNum] = new CInputSource*[NUM_MOUSE_PARTS]; - memset(m_mseSources[mseNum], 0, sizeof(CInputSource*) * NUM_MOUSE_PARTS); - } - } + // Create cache for mouse sources + m_anyMseSources = new CInputSource*[NUM_MOUSE_PARTS]; + memset(m_anyMseSources, 0, sizeof(CInputSource*) * NUM_MOUSE_PARTS); + if (m_numMice != ANY_MOUSE) + { + m_mseSources = new CInputSource**[m_numMice]; + for (int mseNum = 0; mseNum < m_numMice; mseNum++) + { + m_mseSources[mseNum] = new CInputSource*[NUM_MOUSE_PARTS]; + memset(m_mseSources[mseNum], 0, sizeof(CInputSource*) * NUM_MOUSE_PARTS); + } + } - // Create cache for joystick sources - m_anyJoySources = new CInputSource*[NUM_JOY_PARTS]; - memset(m_anyJoySources, 0, sizeof(CInputSource*) * NUM_JOY_PARTS); - if (m_numJoys != ANY_JOYSTICK) - { - m_joySources = new CInputSource**[m_numJoys]; - for (int joyNum = 0; joyNum < m_numJoys; joyNum++) - { - m_joySources[joyNum] = new CInputSource*[NUM_JOY_PARTS]; - memset(m_joySources[joyNum], 0, sizeof(CInputSource*) * NUM_JOY_PARTS); - } - } -} + // Create cache for joystick sources + m_anyJoySources = new CInputSource*[NUM_JOY_PARTS]; + memset(m_anyJoySources, 0, sizeof(CInputSource*) * NUM_JOY_PARTS); + if (m_numJoys != ANY_JOYSTICK) + { + m_joySources = new CInputSource**[m_numJoys]; + for (int joyNum = 0; joyNum < m_numJoys; joyNum++) + { + m_joySources[joyNum] = new CInputSource*[NUM_JOY_PARTS]; + memset(m_joySources[joyNum], 0, sizeof(CInputSource*) * NUM_JOY_PARTS); + } + } +} void CInputSystem::ClearSourceCache(bool deleteCache) { - // Clear cache of keyboard sources - if (m_anyKeySources != NULL) - { - for (size_t keyIndex = 0; keyIndex < NUM_VALID_KEYS; keyIndex++) - ReleaseSource(m_anyKeySources[keyIndex]); - if (deleteCache) - { - delete[] m_anyKeySources; - m_anyKeySources = NULL; - } - if (m_numKbds != ANY_KEYBOARD) - { - for (int kbdNum = 0; kbdNum < m_numKbds; kbdNum++) - { - for (size_t keyIndex = 0; keyIndex < NUM_VALID_KEYS; keyIndex++) - ReleaseSource(m_keySources[kbdNum][keyIndex]); - if (deleteCache) - delete[] m_keySources[kbdNum]; - } - if (deleteCache) - { - delete[] m_keySources; - m_keySources = NULL; - } - } - } + // Clear cache of keyboard sources + if (m_anyKeySources != NULL) + { + for (size_t keyIndex = 0; keyIndex < NUM_VALID_KEYS; keyIndex++) + ReleaseSource(m_anyKeySources[keyIndex]); + if (deleteCache) + { + delete[] m_anyKeySources; + m_anyKeySources = NULL; + } + if (m_numKbds != ANY_KEYBOARD) + { + for (int kbdNum = 0; kbdNum < m_numKbds; kbdNum++) + { + for (size_t keyIndex = 0; keyIndex < NUM_VALID_KEYS; keyIndex++) + ReleaseSource(m_keySources[kbdNum][keyIndex]); + if (deleteCache) + delete[] m_keySources[kbdNum]; + } + if (deleteCache) + { + delete[] m_keySources; + m_keySources = NULL; + } + } + } - // Clear cache of mouse sources - if (m_anyMseSources != NULL) - { - for (int mseIndex = 0; mseIndex < NUM_MOUSE_PARTS; mseIndex++) - ReleaseSource(m_anyMseSources[mseIndex]); - if (deleteCache) - { - delete[] m_anyMseSources; - m_anyMseSources = NULL; - } - if (m_numMice != ANY_MOUSE) - { - for (int mseNum = 0; mseNum < m_numMice; mseNum++) - { - for (int mseIndex = 0; mseIndex < NUM_MOUSE_PARTS; mseIndex++) - ReleaseSource(m_mseSources[mseNum][mseIndex]); - if (deleteCache) - delete[] m_mseSources[mseNum]; - } - if (deleteCache) - { - delete[] m_mseSources; - m_mseSources = NULL; - } - } - } + // Clear cache of mouse sources + if (m_anyMseSources != NULL) + { + for (int mseIndex = 0; mseIndex < NUM_MOUSE_PARTS; mseIndex++) + ReleaseSource(m_anyMseSources[mseIndex]); + if (deleteCache) + { + delete[] m_anyMseSources; + m_anyMseSources = NULL; + } + if (m_numMice != ANY_MOUSE) + { + for (int mseNum = 0; mseNum < m_numMice; mseNum++) + { + for (int mseIndex = 0; mseIndex < NUM_MOUSE_PARTS; mseIndex++) + ReleaseSource(m_mseSources[mseNum][mseIndex]); + if (deleteCache) + delete[] m_mseSources[mseNum]; + } + if (deleteCache) + { + delete[] m_mseSources; + m_mseSources = NULL; + } + } + } - // Clear cache of joystick sources - if (m_anyJoySources != NULL) - { - for (int joyIndex = 0; joyIndex < NUM_JOY_PARTS; joyIndex++) - ReleaseSource(m_anyJoySources[joyIndex]); - if (deleteCache) - { - delete[] m_anyJoySources; - m_anyJoySources = NULL; - } - if (m_numJoys != ANY_JOYSTICK) - { - for (int joyNum = 0; joyNum < m_numJoys; joyNum++) - { - for (int joyIndex = 0; joyIndex < NUM_JOY_PARTS; joyIndex++) - ReleaseSource(m_joySources[joyNum][joyIndex]); - if (deleteCache) - delete[] m_joySources[joyNum]; - } - if (deleteCache) - { - delete[] m_joySources; - m_joySources = NULL; - } - } - } + // Clear cache of joystick sources + if (m_anyJoySources != NULL) + { + for (int joyIndex = 0; joyIndex < NUM_JOY_PARTS; joyIndex++) + ReleaseSource(m_anyJoySources[joyIndex]); + if (deleteCache) + { + delete[] m_anyJoySources; + m_anyJoySources = NULL; + } + if (m_numJoys != ANY_JOYSTICK) + { + for (int joyNum = 0; joyNum < m_numJoys; joyNum++) + { + for (int joyIndex = 0; joyIndex < NUM_JOY_PARTS; joyIndex++) + ReleaseSource(m_joySources[joyNum][joyIndex]); + if (deleteCache) + delete[] m_joySources[joyNum]; + } + if (deleteCache) + { + delete[] m_joySources; + m_joySources = NULL; + } + } + } } void CInputSystem::ReleaseSource(CInputSource *&source) { - if (source != NULL) - source->Release(); - source = NULL; + if (source != NULL) + source->Release(); + source = NULL; } - + CInputSource *CInputSystem::GetKeySource(int kbdNum, int keyIndex) { - if (kbdNum == ANY_KEYBOARD) - { - // Check keyboard source cache first - if (m_anyKeySources[keyIndex] == NULL) - { - if (m_numKbds == ANY_KEYBOARD) - m_anyKeySources[keyIndex] = CreateKeySource(ANY_KEYBOARD, keyIndex); - else - m_anyKeySources[keyIndex] = CreateAnyKeySource(keyIndex); - m_anyKeySources[keyIndex]->Acquire(); - } - return m_anyKeySources[keyIndex]; - } - else if (kbdNum < m_numKbds) - { - // Check keyboard source cache first - if (m_keySources[kbdNum][keyIndex] == NULL) - { - m_keySources[kbdNum][keyIndex] = CreateKeySource(kbdNum, keyIndex); - m_keySources[kbdNum][keyIndex]->Acquire(); - } - return m_keySources[kbdNum][keyIndex]; - } - else - return m_emptySource; + if (kbdNum == ANY_KEYBOARD) + { + // Check keyboard source cache first + if (m_anyKeySources[keyIndex] == NULL) + { + if (m_numKbds == ANY_KEYBOARD) + m_anyKeySources[keyIndex] = CreateKeySource(ANY_KEYBOARD, keyIndex); + else + m_anyKeySources[keyIndex] = CreateAnyKeySource(keyIndex); + m_anyKeySources[keyIndex]->Acquire(); + } + return m_anyKeySources[keyIndex]; + } + else if (kbdNum < m_numKbds) + { + // Check keyboard source cache first + if (m_keySources[kbdNum][keyIndex] == NULL) + { + m_keySources[kbdNum][keyIndex] = CreateKeySource(kbdNum, keyIndex); + m_keySources[kbdNum][keyIndex]->Acquire(); + } + return m_keySources[kbdNum][keyIndex]; + } + else + return m_emptySource; } CInputSource *CInputSystem::GetMouseSource(int mseNum, EMousePart msePart) { - int mseIndex = (int)msePart; - if (mseNum == ANY_MOUSE) - { - // Check mouse source cache first - if (m_anyMseSources[mseIndex] == NULL) - { - if (m_numMice == ANY_MOUSE) - m_anyMseSources[mseIndex] = CreateMouseSource(ANY_MOUSE, msePart); - else - m_anyMseSources[mseIndex] = CreateAnyMouseSource(msePart); - m_anyMseSources[mseIndex]->Acquire(); - } - return m_anyMseSources[mseIndex]; - } - else if (mseNum < m_numMice) - { - // Check mouse source cache first - if (m_mseSources[mseNum][mseIndex] == NULL) - { - m_mseSources[mseNum][mseIndex] = CreateMouseSource(mseNum, msePart); - m_mseSources[mseNum][mseIndex]->Acquire(); - } - return m_mseSources[mseNum][mseIndex]; - } - else - return m_emptySource; + int mseIndex = (int)msePart; + if (mseNum == ANY_MOUSE) + { + // Check mouse source cache first + if (m_anyMseSources[mseIndex] == NULL) + { + if (m_numMice == ANY_MOUSE) + m_anyMseSources[mseIndex] = CreateMouseSource(ANY_MOUSE, msePart); + else + m_anyMseSources[mseIndex] = CreateAnyMouseSource(msePart); + m_anyMseSources[mseIndex]->Acquire(); + } + return m_anyMseSources[mseIndex]; + } + else if (mseNum < m_numMice) + { + // Check mouse source cache first + if (m_mseSources[mseNum][mseIndex] == NULL) + { + m_mseSources[mseNum][mseIndex] = CreateMouseSource(mseNum, msePart); + m_mseSources[mseNum][mseIndex]->Acquire(); + } + return m_mseSources[mseNum][mseIndex]; + } + else + return m_emptySource; } CInputSource *CInputSystem::GetJoySource(int joyNum, EJoyPart joyPart) { - int joyIndex = (int)joyPart; - if (joyNum == ANY_JOYSTICK) - { - // Check joystick source cache first - if (m_anyJoySources[joyIndex] == NULL) - { - if (m_numJoys == ANY_JOYSTICK) - m_anyJoySources[joyIndex] = CreateJoySource(ANY_JOYSTICK, joyPart); - else - m_anyJoySources[joyIndex] = CreateAnyJoySource(joyPart); - m_anyJoySources[joyIndex]->Acquire(); - } - return m_anyJoySources[joyIndex]; - } - else if (joyNum < m_numJoys) - { - // Check joystick source cache first - if (m_joySources[joyNum][joyIndex] == NULL) - { - m_joySources[joyNum][joyIndex] = CreateJoySource(joyNum, joyPart); - m_joySources[joyNum][joyIndex]->Acquire(); - } - return m_joySources[joyNum][joyIndex]; - } - else - return m_emptySource; + int joyIndex = (int)joyPart; + if (joyNum == ANY_JOYSTICK) + { + // Check joystick source cache first + if (m_anyJoySources[joyIndex] == NULL) + { + if (m_numJoys == ANY_JOYSTICK) + m_anyJoySources[joyIndex] = CreateJoySource(ANY_JOYSTICK, joyPart); + else + m_anyJoySources[joyIndex] = CreateAnyJoySource(joyPart); + m_anyJoySources[joyIndex]->Acquire(); + } + return m_anyJoySources[joyIndex]; + } + else if (joyNum < m_numJoys) + { + // Check joystick source cache first + if (m_joySources[joyNum][joyIndex] == NULL) + { + m_joySources[joyNum][joyIndex] = CreateJoySource(joyNum, joyPart); + m_joySources[joyNum][joyIndex]->Acquire(); + } + return m_joySources[joyNum][joyIndex]; + } + else + return m_emptySource; } void CInputSystem::CheckAllSources(unsigned readFlags, bool fullAxisOnly, bool &mseCentered, vector &sources, string &mapping, vector &badSources) { - // See if should read keyboards - if (readFlags & READ_KEYBOARD) - { - // Check all keyboard sources for inputs, merging devices if required - if ((readFlags & READ_MERGE_KEYBOARD) || m_numKbds == ANY_KEYBOARD) - CheckKeySources(ANY_KEYBOARD, fullAxisOnly, sources, mapping, badSources); - else - { - for (int kbdNum = 0; kbdNum < m_numKbds; kbdNum++) - CheckKeySources(kbdNum, fullAxisOnly, sources, mapping, badSources); - } - } + // See if should read keyboards + if (readFlags & READ_KEYBOARD) + { + // Check all keyboard sources for inputs, merging devices if required + if ((readFlags & READ_MERGE_KEYBOARD) || m_numKbds == ANY_KEYBOARD) + CheckKeySources(ANY_KEYBOARD, fullAxisOnly, sources, mapping, badSources); + else + { + for (int kbdNum = 0; kbdNum < m_numKbds; kbdNum++) + CheckKeySources(kbdNum, fullAxisOnly, sources, mapping, badSources); + } + } - // See if should read mice - if (readFlags & READ_MOUSE) - { - // For mouse input, wait until mouse is in centre of display before parsing X- and Y-axis movements - if (!mseCentered) - mseCentered = ConfigMouseCentered(); - - // Check all mouse sources for input, merging devices if required - if ((readFlags & READ_MERGE_MOUSE) || m_numMice == ANY_MOUSE) - CheckMouseSources(ANY_MOUSE, fullAxisOnly, mseCentered, sources, mapping, badSources); - else - { - for (int mseNum = 0; mseNum < m_numMice; mseNum++) - CheckMouseSources(mseNum, fullAxisOnly, mseCentered, sources, mapping, badSources); - } - } - - // See if should read joysticks - if (readFlags & READ_JOYSTICK) - { - // Check all joystick sources, merging devices if required - if ((readFlags & READ_MERGE_JOYSTICK) || m_numJoys == ANY_JOYSTICK) - CheckJoySources(ANY_JOYSTICK, fullAxisOnly, sources, mapping, badSources); - else - { - for (int joyNum = 0; joyNum < m_numJoys; joyNum++) - CheckJoySources(joyNum, fullAxisOnly, sources, mapping, badSources); - } - } + // See if should read mice + if (readFlags & READ_MOUSE) + { + // For mouse input, wait until mouse is in centre of display before parsing X- and Y-axis movements + if (!mseCentered) + mseCentered = ConfigMouseCentered(); + + // Check all mouse sources for input, merging devices if required + if ((readFlags & READ_MERGE_MOUSE) || m_numMice == ANY_MOUSE) + CheckMouseSources(ANY_MOUSE, fullAxisOnly, mseCentered, sources, mapping, badSources); + else + { + for (int mseNum = 0; mseNum < m_numMice; mseNum++) + CheckMouseSources(mseNum, fullAxisOnly, mseCentered, sources, mapping, badSources); + } + } + + // See if should read joysticks + if (readFlags & READ_JOYSTICK) + { + // Check all joystick sources, merging devices if required + if ((readFlags & READ_MERGE_JOYSTICK) || m_numJoys == ANY_JOYSTICK) + CheckJoySources(ANY_JOYSTICK, fullAxisOnly, sources, mapping, badSources); + else + { + for (int joyNum = 0; joyNum < m_numJoys; joyNum++) + CheckJoySources(joyNum, fullAxisOnly, sources, mapping, badSources); + } + } } void CInputSystem::CheckKeySources(int kbdNum, bool fullAxisOnly, vector &sources, string &mapping, vector &badSources) { - // Loop through all valid keys - for (size_t i = 0; i < NUM_VALID_KEYS; i++) - { - const char *keyName = s_validKeyNames[i]; - int keyIndex = GetKeyIndex(keyName); - if (keyIndex < 0) - continue; - // Get key source for keyboard number and key and test to see if it is active (but was not previously) and that it is not a "bad" source - CInputSource *source = GetKeySource(kbdNum, keyIndex); - if (source != NULL && source->IsActive() && find(sources.begin(), sources.end(), source) == sources.end() && - find(badSources.begin(), badSources.end(), source) == badSources.end()) - { - // Update mapping string and add source to list - if (sources.size() == 0) - mapping.assign("KEY"); - else - mapping.append("+KEY"); - if (kbdNum >= 0) - mapping.append(IntToString(kbdNum + 1)); - mapping.append("_"); - mapping.append(keyName); - sources.push_back(source); - } - } + // Loop through all valid keys + for (size_t i = 0; i < NUM_VALID_KEYS; i++) + { + const char *keyName = s_validKeyNames[i]; + int keyIndex = GetKeyIndex(keyName); + if (keyIndex < 0) + continue; + // Get key source for keyboard number and key and test to see if it is active (but was not previously) and that it is not a "bad" source + CInputSource *source = GetKeySource(kbdNum, keyIndex); + if (source != NULL && source->IsActive() && find(sources.begin(), sources.end(), source) == sources.end() && + find(badSources.begin(), badSources.end(), source) == badSources.end()) + { + // Update mapping string and add source to list + if (sources.size() == 0) + mapping.assign("KEY"); + else + mapping.append("+KEY"); + if (kbdNum >= 0) + mapping.append(IntToString(kbdNum + 1)); + mapping.append("_"); + mapping.append(keyName); + sources.push_back(source); + } + } } void CInputSystem::CheckMouseSources(int mseNum, bool fullAxisOnly, bool mseCentered, vector &sources, string &mapping, vector &badSources) { - // Loop through all mouse parts - for (int mseIndex = 0; mseIndex < NUM_MOUSE_PARTS; mseIndex++) - { - EMousePart msePart = (EMousePart)mseIndex; - // Get axis details - int axisNum; - int axisDir; - bool isAxis = GetAxisDetails(msePart, axisNum, axisDir); - bool isXYAxis = isAxis && (axisNum == AXIS_X || axisNum == AXIS_Y); - // Ignore X- & Y-axes if mouse hasn't been centered yet and filter axes according to fullAxisOnly - if ((isXYAxis && !mseCentered) || (isAxis && ((IsFullAxis(msePart) && !fullAxisOnly) || (!IsFullAxis(msePart) && fullAxisOnly)))) - continue; - // Get mouse source for mouse number and part and test to see if it is active (but was not previously) and that it is not a "bad" source - CInputSource *source = GetMouseSource(mseNum, msePart); - if (source != NULL && source->IsActive() && find(sources.begin(), sources.end(), source) == sources.end() && - find(badSources.begin(), badSources.end(), source) == badSources.end()) - { - // Otherwise, update mapping string and add source to list - const char *partName = LookupName(msePart); - if (sources.size() == 0) - mapping.assign("MOUSE"); - else - mapping.append("+MOUSE"); - if (mseNum >= 0) - mapping.append(IntToString(mseNum + 1)); - mapping.append("_"); - mapping.append(partName); - sources.push_back(source); - } - } + // Loop through all mouse parts + for (int mseIndex = 0; mseIndex < NUM_MOUSE_PARTS; mseIndex++) + { + EMousePart msePart = (EMousePart)mseIndex; + // Get axis details + int axisNum; + int axisDir; + bool isAxis = GetAxisDetails(msePart, axisNum, axisDir); + bool isXYAxis = isAxis && (axisNum == AXIS_X || axisNum == AXIS_Y); + // Ignore X- & Y-axes if mouse hasn't been centered yet and filter axes according to fullAxisOnly + if ((isXYAxis && !mseCentered) || (isAxis && ((IsFullAxis(msePart) && !fullAxisOnly) || (!IsFullAxis(msePart) && fullAxisOnly)))) + continue; + // Get mouse source for mouse number and part and test to see if it is active (but was not previously) and that it is not a "bad" source + CInputSource *source = GetMouseSource(mseNum, msePart); + if (source != NULL && source->IsActive() && find(sources.begin(), sources.end(), source) == sources.end() && + find(badSources.begin(), badSources.end(), source) == badSources.end()) + { + // Otherwise, update mapping string and add source to list + const char *partName = LookupName(msePart); + if (sources.size() == 0) + mapping.assign("MOUSE"); + else + mapping.append("+MOUSE"); + if (mseNum >= 0) + mapping.append(IntToString(mseNum + 1)); + mapping.append("_"); + mapping.append(partName); + sources.push_back(source); + } + } } void CInputSystem::CheckJoySources(int joyNum, bool fullAxisOnly, vector &sources, string &mapping, vector &badSources) { - // Loop through all joystick parts - for (int joyIndex = 0; joyIndex < NUM_JOY_PARTS; joyIndex++) - { - EJoyPart joyPart = (EJoyPart)joyIndex; - // Filter axes according to fullAxisOnly - if (IsAxis(joyPart) && ((IsFullAxis(joyPart) && !fullAxisOnly) || (!IsFullAxis(joyPart) && fullAxisOnly))) - continue; - // Get joystick source for joystick number and part and test to see if it is active (but was not previously) and that it is not a "bad" source - CInputSource *source = GetJoySource(joyNum, joyPart); - if (source != NULL && source->IsActive() && find(sources.begin(), sources.end(), source) == sources.end() && - find(badSources.begin(), badSources.end(), source) == badSources.end()) - { - // Otherwise, update mapping string and add source to list - const char *partName = LookupName(joyPart); - if (sources.size() == 0) - mapping.assign("JOY"); - else - mapping.append("+JOY"); - if (joyNum >= 0) - mapping.append(IntToString(joyNum + 1)); - mapping.append("_"); - mapping.append(partName); - sources.push_back(source); - } - } + // Loop through all joystick parts + for (int joyIndex = 0; joyIndex < NUM_JOY_PARTS; joyIndex++) + { + EJoyPart joyPart = (EJoyPart)joyIndex; + // Filter axes according to fullAxisOnly + if (IsAxis(joyPart) && ((IsFullAxis(joyPart) && !fullAxisOnly) || (!IsFullAxis(joyPart) && fullAxisOnly))) + continue; + // Get joystick source for joystick number and part and test to see if it is active (but was not previously) and that it is not a "bad" source + CInputSource *source = GetJoySource(joyNum, joyPart); + if (source != NULL && source->IsActive() && find(sources.begin(), sources.end(), source) == sources.end() && + find(badSources.begin(), badSources.end(), source) == badSources.end()) + { + // Otherwise, update mapping string and add source to list + const char *partName = LookupName(joyPart); + if (sources.size() == 0) + mapping.assign("JOY"); + else + mapping.append("+JOY"); + if (joyNum >= 0) + mapping.append(IntToString(joyNum + 1)); + mapping.append("_"); + mapping.append(partName); + sources.push_back(source); + } + } } bool CInputSystem::ParseInt(string str, int &num) { - stringstream ss(str); - return !(ss >> num).fail(); + stringstream ss(str); + return !(ss >> num).fail(); } string CInputSystem::IntToString(int num) { - stringstream ss; - ss << num; - return ss.str(); + stringstream ss; + ss << num; + return ss.str(); } bool CInputSystem::EqualsIgnoreCase(string str1, const char *str2) { - for (string::const_iterator ci = str1.begin(); ci < str1.end(); ci++) - { - if (*str2 == '\0' || tolower(*ci) != tolower(*str2)) - return false; - str2++; - } - return *str2 == '\0'; + for (string::const_iterator ci = str1.begin(); ci < str1.end(); ci++) + { + if (*str2 == '\0' || tolower(*ci) != tolower(*str2)) + return false; + str2++; + } + return *str2 == '\0'; } bool CInputSystem::StartsWithIgnoreCase(string str1, const char *str2) { - for (string::const_iterator ci = str1.begin(); ci < str1.end(); ci++) - { - if (*str2 == '\0') - return true; - if (tolower(*ci) != tolower(*str2)) - return false; - str2++; - } - return *str2 == '\0'; + for (string::const_iterator ci = str1.begin(); ci < str1.end(); ci++) + { + if (*str2 == '\0') + return true; + if (tolower(*ci) != tolower(*str2)) + return false; + str2++; + } + return *str2 == '\0'; } bool CInputSystem::IsValidKeyName(string str) { - for (size_t i = 0; i < NUM_VALID_KEYS; i++) - { - if (EqualsIgnoreCase(str, s_validKeyNames[i])) - return true; - } - return false; + for (size_t i = 0; i < NUM_VALID_KEYS; i++) + { + if (EqualsIgnoreCase(str, s_validKeyNames[i])) + return true; + } + return false; } EMousePart CInputSystem::LookupMousePart(string str) { - for (int i = 0; s_mseParts[i].id != NULL; i++) - { - if (EqualsIgnoreCase(str, s_mseParts[i].id)) - return s_mseParts[i].msePart; - } - return MouseUnknown; + for (int i = 0; s_mseParts[i].id != NULL; i++) + { + if (EqualsIgnoreCase(str, s_mseParts[i].id)) + return s_mseParts[i].msePart; + } + return MouseUnknown; } const char *CInputSystem::LookupName(EMousePart msePart) { - for (int i = 0; s_mseParts[i].id != NULL; i++) - { - if (msePart == s_mseParts[i].msePart) - return s_mseParts[i].id; - } - return NULL; + for (int i = 0; s_mseParts[i].id != NULL; i++) + { + if (msePart == s_mseParts[i].msePart) + return s_mseParts[i].id; + } + return NULL; } EJoyPart CInputSystem::LookupJoyPart(string str) { - for (int i = 0; s_joyParts[i].id != NULL; i++) - { - if (EqualsIgnoreCase(str, s_joyParts[i].id)) - return s_joyParts[i].joyPart; - } - return JoyUnknown; + for (int i = 0; s_joyParts[i].id != NULL; i++) + { + if (EqualsIgnoreCase(str, s_joyParts[i].id)) + return s_joyParts[i].joyPart; + } + return JoyUnknown; } const char *CInputSystem::LookupName(EJoyPart joyPart) { - for (int i = 0; s_joyParts[i].id != NULL; i++) - { - if (joyPart == s_joyParts[i].joyPart) - return s_joyParts[i].id; - } - return NULL; + for (int i = 0; s_joyParts[i].id != NULL; i++) + { + if (joyPart == s_joyParts[i].joyPart) + return s_joyParts[i].id; + } + return NULL; } size_t CInputSystem::ParseDevMapping(string str, const char *devType, int &devNum) { - if (!StartsWithIgnoreCase(str, devType)) - return -1; - size_t size = str.size(); - size_t devLen = strlen(devType); + if (!StartsWithIgnoreCase(str, devType)) + return -1; + size_t size = str.size(); + size_t devLen = strlen(devType); - // Parse optional device number - devNum = -1; - size_t i = devLen; - while (i < size && isdigit(str[i])) - i++; - if (i > devLen && i < size) - { - if (!ParseInt(str.substr(devLen, i), devNum)) - return -1; - devNum--; - } + // Parse optional device number + devNum = -1; + size_t i = devLen; + while (i < size && isdigit(str[i])) + i++; + if (i > devLen && i < size) + { + if (!ParseInt(str.substr(devLen, i), devNum)) + return -1; + devNum--; + } - // Check hyphen preceeds device part - if (i < size - 1 && str[i] == '_') - return i + 1; - else - return -1; + // Check hyphen preceeds device part + if (i < size - 1 && str[i] == '_') + return i + 1; + else + return -1; } CInputSource* CInputSystem::ParseMultiSource(string str, bool fullAxisOnly, bool isOr) { - // Check for empty or NONE mapping - size_t size = str.size(); - if (size == 0 || EqualsIgnoreCase(str, "NONE")) - return NULL; + // Check for empty or NONE mapping + size_t size = str.size(); + if (size == 0 || EqualsIgnoreCase(str, "NONE")) + return NULL; - CInputSource *source = NULL; - bool isMulti = false; - vector sources; + CInputSource *source = NULL; + bool isMulti = false; + vector sources; - size_t start = 0; - size_t end; - do - { - // Remove leading whitespace/quotes and see if have any plusses/commas in mapping (to specify and/or multiple assignments) - while ((isspace(str[start]) || str[start] == '"') && start < size - 1) - start++; - char delim = (isOr ? ',' : '+'); - end = str.find(delim, start); - if (end == string::npos) - end = size; + size_t start = 0; + size_t end; + do + { + // Remove leading whitespace/quotes and see if have any plusses/commas in mapping (to specify and/or multiple assignments) + while ((isspace(str[start]) || str[start] == '"') && start < size - 1) + start++; + char delim = (isOr ? ',' : '+'); + end = str.find(delim, start); + if (end == string::npos) + end = size; - // Remove tailing whitespace/quotes - size_t subEnd = end; - while (subEnd > 0 && (isspace(str[subEnd - 1]) || str[start] == '"')) - subEnd--; - string subStr = str.substr(start, subEnd - start); - start = end + 1; + // Remove tailing whitespace/quotes + size_t subEnd = end; + while (subEnd > 0 && (isspace(str[subEnd - 1]) || str[start] == '"')) + subEnd--; + string subStr = str.substr(start, subEnd - start); + start = end + 1; - // Parse the multi/single source in substring - CInputSource *parsed; - if (isOr) - parsed = ParseMultiSource(subStr, fullAxisOnly, false); - else - parsed = ParseSingleSource(subStr); + // Parse the multi/single source in substring + CInputSource *parsed; + if (isOr) + parsed = ParseMultiSource(subStr, fullAxisOnly, false); + else + parsed = ParseSingleSource(subStr); - // Check the result is valid - if ((parsed != NULL) && (parsed->type != SourceInvalid) && - ((parsed->type == SourceEmpty) || (parsed->type == SourceFullAxis && fullAxisOnly) || (parsed->type != SourceFullAxis && !fullAxisOnly))) - { - // Keep track of all sources parsed - if (isMulti) - sources.push_back(parsed); - else if (source != NULL) - { - sources.push_back(source); - sources.push_back(parsed); - isMulti = true; - } - else - source = parsed; - } - } - while (start < size); + // Check the result is valid + if ((parsed != NULL) && (parsed->type != SourceInvalid) && + ((parsed->type == SourceEmpty) || (parsed->type == SourceFullAxis && fullAxisOnly) || (parsed->type != SourceFullAxis && !fullAxisOnly))) + { + // Keep track of all sources parsed + if (isMulti) + sources.push_back(parsed); + else if (source != NULL) + { + sources.push_back(source); + sources.push_back(parsed); + isMulti = true; + } + else + source = parsed; + } + } + while (start < size); - // If only parsed a single source, return that, otherwise return a CMultiInputSource combining all the sources - return (isMulti ? new CMultiInputSource(isOr, sources) : source); + // If only parsed a single source, return that, otherwise return a CMultiInputSource combining all the sources + return (isMulti ? new CMultiInputSource(isOr, sources) : source); } CInputSource *CInputSystem::ParseSingleSource(string str) { - // First, check for ! at beginning of string, which means input source must not be activated - if (str[0] == '!') - { - // If found, skip any whitespace after that and get remaining string and parse it again - size_t i = 1; - while (i < str.size() && str[i] == ' ') - i++; - str.erase(0, i); + // First, check for ! at beginning of string, which means input source must not be activated + if (str[0] == '!') + { + // If found, skip any whitespace after that and get remaining string and parse it again + size_t i = 1; + while (i < str.size() && str[i] == ' ') + i++; + str.erase(0, i); - CInputSource *source = ParseSingleSource(str); - if (source != NULL && source != m_emptySource) - return new CNegInputSource(source); - else - return source; - } + CInputSource *source = ParseSingleSource(str); + if (source != NULL && source != m_emptySource) + return new CNegInputSource(source); + else + return source; + } - // Try parsing a key mapping - int kbdNum; - int keyNameIndex = ParseDevMapping(str, "KEY", kbdNum); - if (keyNameIndex >= 0) - { - string keyName = str.substr(keyNameIndex); - if (IsValidKeyName(keyName)) - { - // Lookup key index and map to key source - int keyIndex = GetKeyIndex(keyName.c_str()); - if (keyIndex >= 0) - return GetKeySource(kbdNum, keyIndex); - else if (EqualsIgnoreCase(keyName, "SHIFT") || EqualsIgnoreCase(keyName, "CTRL") || EqualsIgnoreCase(keyName, "ALT")) - { - // Handle special cases if not handled by subclass: SHIFT, CTRL and ALT - string leftName = "LEFT" + keyName; - string rightName = "RIGHT" + keyName; - int leftIndex = GetKeyIndex(leftName.c_str()); - int rightIndex = GetKeyIndex(rightName.c_str()); - vector sources; - if (leftIndex >= 0) - { - CInputSource *leftSource = GetKeySource(kbdNum, leftIndex); - if (leftSource != NULL) - sources.push_back(leftSource); - } - if (rightIndex >= 0) - { - CInputSource *rightSource = GetKeySource(kbdNum, rightIndex); - if (rightSource != NULL) - sources.push_back(rightSource); - } - if (sources.size() > 0) - return new CMultiInputSource(true, sources); - } - return m_emptySource; - } - } - - // Try parsing a mouse mapping - int mseNum; - int msePartIndex = ParseDevMapping(str, "MOUSE", mseNum); - if (msePartIndex >= 0) - { - // Lookup mouse part and map to mouse source - EMousePart msePart = LookupMousePart(str.substr(msePartIndex)); - if (msePart != MouseUnknown) - return GetMouseSource(mseNum, msePart); - } + // Try parsing a key mapping + int kbdNum; + int keyNameIndex = ParseDevMapping(str, "KEY", kbdNum); + if (keyNameIndex >= 0) + { + string keyName = str.substr(keyNameIndex); + if (IsValidKeyName(keyName)) + { + // Lookup key index and map to key source + int keyIndex = GetKeyIndex(keyName.c_str()); + if (keyIndex >= 0) + return GetKeySource(kbdNum, keyIndex); + else if (EqualsIgnoreCase(keyName, "SHIFT") || EqualsIgnoreCase(keyName, "CTRL") || EqualsIgnoreCase(keyName, "ALT")) + { + // Handle special cases if not handled by subclass: SHIFT, CTRL and ALT + string leftName = "LEFT" + keyName; + string rightName = "RIGHT" + keyName; + int leftIndex = GetKeyIndex(leftName.c_str()); + int rightIndex = GetKeyIndex(rightName.c_str()); + vector sources; + if (leftIndex >= 0) + { + CInputSource *leftSource = GetKeySource(kbdNum, leftIndex); + if (leftSource != NULL) + sources.push_back(leftSource); + } + if (rightIndex >= 0) + { + CInputSource *rightSource = GetKeySource(kbdNum, rightIndex); + if (rightSource != NULL) + sources.push_back(rightSource); + } + if (sources.size() > 0) + return new CMultiInputSource(true, sources); + } + return m_emptySource; + } + } + + // Try parsing a mouse mapping + int mseNum; + int msePartIndex = ParseDevMapping(str, "MOUSE", mseNum); + if (msePartIndex >= 0) + { + // Lookup mouse part and map to mouse source + EMousePart msePart = LookupMousePart(str.substr(msePartIndex)); + if (msePart != MouseUnknown) + return GetMouseSource(mseNum, msePart); + } - // Try parsing a joystick mapping - int joyNum; - int joyPartIndex = ParseDevMapping(str, "JOY", joyNum); - if (joyPartIndex >= 0) - { - // Lookup joystick part and map to joystick source - EJoyPart joyPart = LookupJoyPart(str.substr(joyPartIndex)); - if (joyPart != JoyUnknown) - return GetJoySource(joyNum, joyPart); - } + // Try parsing a joystick mapping + int joyNum; + int joyPartIndex = ParseDevMapping(str, "JOY", joyNum); + if (joyPartIndex >= 0) + { + // Lookup joystick part and map to joystick source + EJoyPart joyPart = LookupJoyPart(str.substr(joyPartIndex)); + if (joyPart != JoyUnknown) + return GetJoySource(joyNum, joyPart); + } - // As last option, assume mapping is just a key name and try creating keyboard source from it (to retain compatibility with previous - // versions of Supermodel) - if (IsValidKeyName(str)) - { - // Lookup key index and map to key source - int keyIndex = GetKeyIndex(str.c_str()); - if (keyIndex >= 0) - return GetKeySource(ANY_KEYBOARD, keyIndex); - else - return m_emptySource; - } + // As last option, assume mapping is just a key name and try creating keyboard source from it (to retain compatibility with previous + // versions of Supermodel) + if (IsValidKeyName(str)) + { + // Lookup key index and map to key source + int keyIndex = GetKeyIndex(str.c_str()); + if (keyIndex >= 0) + return GetKeySource(ANY_KEYBOARD, keyIndex); + else + return m_emptySource; + } - // If got here, it was not possible to parse mapping string so return NULL - return NULL; + // If got here, it was not possible to parse mapping string so return NULL + return NULL; } void CInputSystem::PrintKeySettings(int kbdNum, KeySettings *settings) { - printf(" Sensitivity = %u %%\n", settings->sensitivity); - printf(" Decay Speed = %u %%\n", settings->decaySpeed); + printf(" Sensitivity = %u %%\n", settings->sensitivity); + printf(" Decay Speed = %u %%\n", settings->decaySpeed); +} + +KeySettings *CInputSystem::LoadKeySettings(const Util::Config::Node &config, int kbdNum) +{ + // Get common key settings and create new key settings based on that + KeySettings *common = (kbdNum != ANY_KEYBOARD ? GetKeySettings(ANY_KEYBOARD, true) : &m_defKeySettings); + KeySettings *settings = new KeySettings(*common); + settings->kbdNum = kbdNum; + + // Read settings from ini file + string baseKey("InputKey"); + if (kbdNum != ANY_KEYBOARD) + baseKey.append(IntToString(kbdNum + 1)); + bool read = false; + auto *node = config.TryGet(baseKey + "Sensitivity"); + if (node) + { + settings->sensitivity = node->ValueAs(); + read |= true; + } + node = config.TryGet(baseKey + "DecaySpeed"); + if (node) + { + settings->decaySpeed = node->ValueAs(); + read |= true; + } + if (read) + return settings; + delete settings; + return NULL; +} + +void CInputSystem::StoreKeySettings(Util::Config::Node *config, KeySettings *settings) +{ + // Get common key settings + KeySettings *common = (settings->kbdNum != ANY_KEYBOARD ? GetKeySettings(ANY_KEYBOARD, true) : &m_defKeySettings); + + // Write to ini file any settings that are different to common settings + string baseKey("InputKey"); + if (settings->kbdNum != ANY_KEYBOARD) + baseKey.append(IntToString(settings->kbdNum + 1)); + if (settings->sensitivity != common->sensitivity) + config->Set(baseKey + "Sensitivity", settings->sensitivity); + if (settings->decaySpeed != common->decaySpeed) + config->Set(baseKey + "DecaySpeed", settings->decaySpeed); } KeySettings *CInputSystem::ReadKeySettings(CINIFile *ini, const char *section, int kbdNum) { - // Get common key settings and create new key settings based on that - KeySettings *common = (kbdNum != ANY_KEYBOARD ? GetKeySettings(ANY_KEYBOARD, true) : &m_defKeySettings); - KeySettings *settings = new KeySettings(*common); - settings->kbdNum = kbdNum; + // Get common key settings and create new key settings based on that + KeySettings *common = (kbdNum != ANY_KEYBOARD ? GetKeySettings(ANY_KEYBOARD, true) : &m_defKeySettings); + KeySettings *settings = new KeySettings(*common); + settings->kbdNum = kbdNum; - // Read settings from ini file - string baseKey("InputKey"); - if (kbdNum != ANY_KEYBOARD) - baseKey.append(IntToString(kbdNum + 1)); - bool read = false; - read |= ini->Get(section, baseKey + "Sensitivity", settings->sensitivity) == OKAY; - read |= ini->Get(section, baseKey + "DecaySpeed", settings->decaySpeed) == OKAY; - if (read) - return settings; - delete settings; - return NULL; + // Read settings from ini file + string baseKey("InputKey"); + if (kbdNum != ANY_KEYBOARD) + baseKey.append(IntToString(kbdNum + 1)); + bool read = false; + read |= ini->Get(section, baseKey + "Sensitivity", settings->sensitivity) == OKAY; + read |= ini->Get(section, baseKey + "DecaySpeed", settings->decaySpeed) == OKAY; + if (read) + return settings; + delete settings; + return NULL; } void CInputSystem::WriteKeySettings(CINIFile *ini, const char *section, KeySettings *settings) { - // Get common key settings - KeySettings *common = (settings->kbdNum != ANY_KEYBOARD ? GetKeySettings(ANY_KEYBOARD, true) : &m_defKeySettings); + // Get common key settings + KeySettings *common = (settings->kbdNum != ANY_KEYBOARD ? GetKeySettings(ANY_KEYBOARD, true) : &m_defKeySettings); - // Write to ini file any settings that are different to common settings - string baseKey("InputKey"); - if (settings->kbdNum != ANY_KEYBOARD) - baseKey.append(IntToString(settings->kbdNum + 1)); - if (settings->sensitivity != common->sensitivity) ini->Set(section, baseKey + "Sensitivity", settings->sensitivity); - if (settings->decaySpeed != common->decaySpeed) ini->Set(section, baseKey + "DecaySpeed", settings->decaySpeed); + // Write to ini file any settings that are different to common settings + string baseKey("InputKey"); + if (settings->kbdNum != ANY_KEYBOARD) + baseKey.append(IntToString(settings->kbdNum + 1)); + if (settings->sensitivity != common->sensitivity) ini->Set(section, baseKey + "Sensitivity", settings->sensitivity); + if (settings->decaySpeed != common->decaySpeed) ini->Set(section, baseKey + "DecaySpeed", settings->decaySpeed); } void CInputSystem::PrintMouseSettings(int mseNum, MouseSettings *settings) { - for (int axisNum = 0; axisNum < NUM_MOUSE_AXES; axisNum++) - printf(" %-7s Dead Zone = %u %%\n", s_axisNames[axisNum], settings->deadZones[axisNum]); + for (int axisNum = 0; axisNum < NUM_MOUSE_AXES; axisNum++) + printf(" %-7s Dead Zone = %u %%\n", s_axisNames[axisNum], settings->deadZones[axisNum]); +} + +MouseSettings *CInputSystem::LoadMouseSettings(const Util::Config::Node &config, int mseNum) +{ + // Get common mouse settings and create new mouse settings based on that + MouseSettings *common = (mseNum != ANY_MOUSE ? GetMouseSettings(ANY_MOUSE, true) : &m_defMseSettings); + MouseSettings *settings = new MouseSettings(*common); + settings->mseNum = mseNum; + + // Read settings from ini file + string baseKey("InputMouse"); + if (mseNum != ANY_MOUSE) + baseKey.append(IntToString(mseNum + 1)); + bool read = false; + for (int axisNum = 0; axisNum < NUM_MOUSE_AXES; axisNum++) + { + auto *node = config.TryGet(baseKey + s_axisIds[axisNum] + "DeadZone"); + if (node) + { + settings->deadZones[axisNum] = node->ValueAs(); + read |= true; + } + + } + if (read) + return settings; + delete settings; + return NULL; +} + +void CInputSystem::StoreMouseSettings(Util::Config::Node *config, MouseSettings *settings) +{ + // Get common mouse settings + MouseSettings *common = (settings->mseNum != ANY_MOUSE ? GetMouseSettings(ANY_MOUSE, true) : &m_defMseSettings); + + // Write to ini file any settings that are different to common/default settings + string baseKey("InputMouse"); + if (settings->mseNum != ANY_MOUSE) + baseKey.append(IntToString(settings->mseNum + 1)); + for (int axisNum = 0; axisNum < NUM_MOUSE_AXES; axisNum++) + { + if (settings->deadZones[axisNum] != common->deadZones[axisNum]) + config->Set(baseKey + s_axisIds[axisNum] + "DeadZone", settings->deadZones[axisNum]); + } } MouseSettings *CInputSystem::ReadMouseSettings(CINIFile *ini, const char *section, int mseNum) { - // Get common mouse settings and create new mouse settings based on that - MouseSettings *common = (mseNum != ANY_MOUSE ? GetMouseSettings(ANY_MOUSE, true) : &m_defMseSettings); - MouseSettings *settings = new MouseSettings(*common); - settings->mseNum = mseNum; + // Get common mouse settings and create new mouse settings based on that + MouseSettings *common = (mseNum != ANY_MOUSE ? GetMouseSettings(ANY_MOUSE, true) : &m_defMseSettings); + MouseSettings *settings = new MouseSettings(*common); + settings->mseNum = mseNum; - // Read settings from ini file - string baseKey("InputMouse"); - if (mseNum != ANY_MOUSE) - baseKey.append(IntToString(mseNum + 1)); - bool read = false; - for (int axisNum = 0; axisNum < NUM_MOUSE_AXES; axisNum++) - read |= ini->Get(section, baseKey + s_axisIds[axisNum] + "DeadZone", settings->deadZones[axisNum]) == OKAY; - if (read) - return settings; - delete settings; - return NULL; + // Read settings from ini file + string baseKey("InputMouse"); + if (mseNum != ANY_MOUSE) + baseKey.append(IntToString(mseNum + 1)); + bool read = false; + for (int axisNum = 0; axisNum < NUM_MOUSE_AXES; axisNum++) + read |= ini->Get(section, baseKey + s_axisIds[axisNum] + "DeadZone", settings->deadZones[axisNum]) == OKAY; + if (read) + return settings; + delete settings; + return NULL; } void CInputSystem::WriteMouseSettings(CINIFile *ini, const char *section, MouseSettings *settings) { - // Get common mouse settings - MouseSettings *common = (settings->mseNum != ANY_MOUSE ? GetMouseSettings(ANY_MOUSE, true) : &m_defMseSettings); - - // Write to ini file any settings that are different to common/default settings - string baseKey("InputMouse"); - if (settings->mseNum != ANY_MOUSE) - baseKey.append(IntToString(settings->mseNum + 1)); - for (int axisNum = 0; axisNum < NUM_MOUSE_AXES; axisNum++) - { - if (settings->deadZones[axisNum] != common->deadZones[axisNum]) - ini->Set(section, baseKey + s_axisIds[axisNum] + "DeadZone", settings->deadZones[axisNum]); - } + // Get common mouse settings + MouseSettings *common = (settings->mseNum != ANY_MOUSE ? GetMouseSettings(ANY_MOUSE, true) : &m_defMseSettings); + + // Write to ini file any settings that are different to common/default settings + string baseKey("InputMouse"); + if (settings->mseNum != ANY_MOUSE) + baseKey.append(IntToString(settings->mseNum + 1)); + for (int axisNum = 0; axisNum < NUM_MOUSE_AXES; axisNum++) + { + if (settings->deadZones[axisNum] != common->deadZones[axisNum]) + ini->Set(section, baseKey + s_axisIds[axisNum] + "DeadZone", settings->deadZones[axisNum]); + } } void CInputSystem::PrintJoySettings(int joyNum, JoySettings *settings) { - const JoyDetails *joyDetails = (joyNum != ANY_JOYSTICK ? GetJoyDetails(joyNum) : NULL); - for (int axisNum = 0; axisNum < NUM_JOY_AXES; axisNum++) - { - if (joyDetails && !joyDetails->hasAxis[axisNum]) - continue; - const char *axisName = s_axisNames[axisNum]; - printf(" %-7s Min Value = %d\n", axisName, settings->axisMinVals[axisNum]); - printf(" %-7s Center/Off Value = %d\n", axisName, settings->axisOffVals[axisNum]); - printf(" %-7s Max Value = %d\n", axisName, settings->axisMaxVals[axisNum]); - printf(" %-7s Dead Zone = %u %%\n", axisName, settings->deadZones[axisNum]); - printf(" %-7s Saturation = %u %%\n", axisName, settings->saturations[axisNum]); - } + const JoyDetails *joyDetails = (joyNum != ANY_JOYSTICK ? GetJoyDetails(joyNum) : NULL); + for (int axisNum = 0; axisNum < NUM_JOY_AXES; axisNum++) + { + if (joyDetails && !joyDetails->hasAxis[axisNum]) + continue; + const char *axisName = s_axisNames[axisNum]; + printf(" %-7s Min Value = %d\n", axisName, settings->axisMinVals[axisNum]); + printf(" %-7s Center/Off Value = %d\n", axisName, settings->axisOffVals[axisNum]); + printf(" %-7s Max Value = %d\n", axisName, settings->axisMaxVals[axisNum]); + printf(" %-7s Dead Zone = %u %%\n", axisName, settings->deadZones[axisNum]); + printf(" %-7s Saturation = %u %%\n", axisName, settings->saturations[axisNum]); + } +} + +JoySettings *CInputSystem::LoadJoySettings(const Util::Config::Node &config, int joyNum) +{ + // Get common/default joystick settings and create new joystick settings based on that + JoySettings *common = (joyNum != ANY_JOYSTICK ? GetJoySettings(ANY_JOYSTICK, true) : &m_defJoySettings); + JoySettings *settings = new JoySettings(*common); + settings->joyNum = joyNum; + + // Read settings from ini file + string baseKey("InputJoy"); + if (joyNum != ANY_JOYSTICK) + baseKey.append(IntToString(joyNum + 1)); + bool read = false; + for (int axisNum = 0; axisNum < NUM_JOY_AXES; axisNum++) + { + const char *axisId = s_axisIds[axisNum]; + auto *node = config.TryGet(baseKey + axisId + "MinVal"); + if (node) + { + settings->axisMinVals[axisNum] = node->ValueAs(); + read |= true; + } + node = config.TryGet(baseKey + axisId + "OffVal"); + if (node) + { + settings->axisOffVals[axisNum] = node->ValueAs(); + read |= true; + } + node = config.TryGet(baseKey + axisId + "MaxVal"); + if (node) + { + settings->axisMaxVals[axisNum] = node->ValueAs(); + read |= true; + } + node = config.TryGet(baseKey + axisId + "DeadZone"); + if (node) + { + settings->deadZones[axisNum] = node->ValueAs(); + read |= true; + } + node = config.TryGet(baseKey + axisId + "Saturation"); + if (node) + { + settings->saturations[axisNum] = node->ValueAs(); + read |= true; + } + } + if (read) + return settings; + delete settings; + return NULL; +} + +void CInputSystem::StoreJoySettings(Util::Config::Node *config, JoySettings *settings) +{ + // Get common/default joystick settings + JoySettings *common = (settings->joyNum != ANY_JOYSTICK ? GetJoySettings(ANY_JOYSTICK, true) : &m_defJoySettings); + + // Write to ini file any settings that are different to common/default settings + string baseKey("InputJoy"); + if (settings->joyNum != ANY_JOYSTICK) + baseKey.append(IntToString(settings->joyNum + 1)); + for (int axisNum = 0; axisNum < NUM_JOY_AXES; axisNum++) + { + const char *axisId = s_axisIds[axisNum]; + if (settings->axisMinVals[axisNum] != common->axisMinVals[axisNum]) + config->Set(baseKey + axisId + "MinVal", settings->axisMinVals[axisNum]); + if (settings->axisOffVals[axisNum] != common->axisOffVals[axisNum]) + config->Set(baseKey + axisId + "OffVal", settings->axisOffVals[axisNum]); + if (settings->axisMaxVals[axisNum] != common->axisMaxVals[axisNum]) + config->Set(baseKey + axisId + "MaxVal", settings->axisMaxVals[axisNum]); + if (settings->deadZones[axisNum] != common->deadZones[axisNum]) + config->Set(baseKey + axisId + "DeadZone", settings->deadZones[axisNum]); + if (settings->saturations[axisNum] != common->saturations[axisNum]) + config->Set(baseKey + axisId + "Saturation", settings->saturations[axisNum]); + } } JoySettings *CInputSystem::ReadJoySettings(CINIFile *ini, const char *section, int joyNum) { - // Get common/default joystick settings and create new joystick settings based on that - JoySettings *common = (joyNum != ANY_JOYSTICK ? GetJoySettings(ANY_JOYSTICK, true) : &m_defJoySettings); - JoySettings *settings = new JoySettings(*common); - settings->joyNum = joyNum; + // Get common/default joystick settings and create new joystick settings based on that + JoySettings *common = (joyNum != ANY_JOYSTICK ? GetJoySettings(ANY_JOYSTICK, true) : &m_defJoySettings); + JoySettings *settings = new JoySettings(*common); + settings->joyNum = joyNum; - // Read settings from ini file - string baseKey("InputJoy"); - if (joyNum != ANY_JOYSTICK) - baseKey.append(IntToString(joyNum + 1)); - bool read = false; - for (int axisNum = 0; axisNum < NUM_JOY_AXES; axisNum++) - { - const char *axisId = s_axisIds[axisNum]; - read |= ini->Get(section, baseKey + axisId + "MinVal", settings->axisMinVals[axisNum]) == OKAY; - read |= ini->Get(section, baseKey + axisId + "OffVal", settings->axisOffVals[axisNum]) == OKAY; - read |= ini->Get(section, baseKey + axisId + "MaxVal", settings->axisMaxVals[axisNum]) == OKAY; - read |= ini->Get(section, baseKey + axisId + "DeadZone", settings->deadZones[axisNum]) == OKAY; - read |= ini->Get(section, baseKey + axisId + "Saturation", settings->saturations[axisNum]) == OKAY; - } - if (read) - return settings; - delete settings; - return NULL; + // Read settings from ini file + string baseKey("InputJoy"); + if (joyNum != ANY_JOYSTICK) + baseKey.append(IntToString(joyNum + 1)); + bool read = false; + for (int axisNum = 0; axisNum < NUM_JOY_AXES; axisNum++) + { + const char *axisId = s_axisIds[axisNum]; + read |= ini->Get(section, baseKey + axisId + "MinVal", settings->axisMinVals[axisNum]) == OKAY; + read |= ini->Get(section, baseKey + axisId + "OffVal", settings->axisOffVals[axisNum]) == OKAY; + read |= ini->Get(section, baseKey + axisId + "MaxVal", settings->axisMaxVals[axisNum]) == OKAY; + read |= ini->Get(section, baseKey + axisId + "DeadZone", settings->deadZones[axisNum]) == OKAY; + read |= ini->Get(section, baseKey + axisId + "Saturation", settings->saturations[axisNum]) == OKAY; + } + if (read) + return settings; + delete settings; + return NULL; } void CInputSystem::WriteJoySettings(CINIFile *ini, const char *section, JoySettings *settings) { - // Get common/default joystick settings - JoySettings *common = (settings->joyNum != ANY_JOYSTICK ? GetJoySettings(ANY_JOYSTICK, true) : &m_defJoySettings); + // Get common/default joystick settings + JoySettings *common = (settings->joyNum != ANY_JOYSTICK ? GetJoySettings(ANY_JOYSTICK, true) : &m_defJoySettings); - // Write to ini file any settings that are different to common/default settings - string baseKey("InputJoy"); - if (settings->joyNum != ANY_JOYSTICK) - baseKey.append(IntToString(settings->joyNum + 1)); - for (int axisNum = 0; axisNum < NUM_JOY_AXES; axisNum++) - { - const char *axisId = s_axisIds[axisNum]; - if (settings->axisMinVals[axisNum] != common->axisMinVals[axisNum]) - ini->Set(section, baseKey + axisId + "MinVal", settings->axisMinVals[axisNum]); - if (settings->axisOffVals[axisNum] != common->axisOffVals[axisNum]) - ini->Set(section, baseKey + axisId + "OffVal", settings->axisOffVals[axisNum]); - if (settings->axisMaxVals[axisNum] != common->axisMaxVals[axisNum]) - ini->Set(section, baseKey + axisId + "MaxVal", settings->axisMaxVals[axisNum]); - if (settings->deadZones[axisNum] != common->deadZones[axisNum]) - ini->Set(section, baseKey + axisId + "DeadZone", settings->deadZones[axisNum]); - if (settings->saturations[axisNum] != common->saturations[axisNum]) - ini->Set(section, baseKey + axisId + "Saturation", settings->saturations[axisNum]); - } + // Write to ini file any settings that are different to common/default settings + string baseKey("InputJoy"); + if (settings->joyNum != ANY_JOYSTICK) + baseKey.append(IntToString(settings->joyNum + 1)); + for (int axisNum = 0; axisNum < NUM_JOY_AXES; axisNum++) + { + const char *axisId = s_axisIds[axisNum]; + if (settings->axisMinVals[axisNum] != common->axisMinVals[axisNum]) + ini->Set(section, baseKey + axisId + "MinVal", settings->axisMinVals[axisNum]); + if (settings->axisOffVals[axisNum] != common->axisOffVals[axisNum]) + ini->Set(section, baseKey + axisId + "OffVal", settings->axisOffVals[axisNum]); + if (settings->axisMaxVals[axisNum] != common->axisMaxVals[axisNum]) + ini->Set(section, baseKey + axisId + "MaxVal", settings->axisMaxVals[axisNum]); + if (settings->deadZones[axisNum] != common->deadZones[axisNum]) + ini->Set(section, baseKey + axisId + "DeadZone", settings->deadZones[axisNum]); + if (settings->saturations[axisNum] != common->saturations[axisNum]) + ini->Set(section, baseKey + axisId + "Saturation", settings->saturations[axisNum]); + } } KeySettings *CInputSystem::GetKeySettings(int kbdNum, bool useDefault) { - KeySettings *common = NULL; - for (vector::iterator it = m_keySettings.begin(); it != m_keySettings.end(); it++) - { - if ((*it)->kbdNum == kbdNum) - return *it; - else if ((*it)->kbdNum == ANY_KEYBOARD) - common = *it; - } - if (!useDefault) - return NULL; - return (common != NULL ? common : &m_defKeySettings); + KeySettings *common = NULL; + for (vector::iterator it = m_keySettings.begin(); it != m_keySettings.end(); it++) + { + if ((*it)->kbdNum == kbdNum) + return *it; + else if ((*it)->kbdNum == ANY_KEYBOARD) + common = *it; + } + if (!useDefault) + return NULL; + return (common != NULL ? common : &m_defKeySettings); } MouseSettings *CInputSystem::GetMouseSettings(int mseNum, bool useDefault) { - MouseSettings *common = NULL; - for (vector::iterator it = m_mseSettings.begin(); it != m_mseSettings.end(); it++) - { - if ((*it)->mseNum == mseNum) - return *it; - else if ((*it)->mseNum == ANY_MOUSE) - common = *it; - } - if (!useDefault) - return NULL; - return (common != NULL ? common : &m_defMseSettings); + MouseSettings *common = NULL; + for (vector::iterator it = m_mseSettings.begin(); it != m_mseSettings.end(); it++) + { + if ((*it)->mseNum == mseNum) + return *it; + else if ((*it)->mseNum == ANY_MOUSE) + common = *it; + } + if (!useDefault) + return NULL; + return (common != NULL ? common : &m_defMseSettings); } JoySettings *CInputSystem::GetJoySettings(int joyNum, bool useDefault) { - JoySettings *common = NULL; - for (vector::iterator it = m_joySettings.begin(); it != m_joySettings.end(); it++) - { - if ((*it)->joyNum == joyNum) - return *it; - else if ((*it)->joyNum == ANY_JOYSTICK) - common = *it; - } - if (!useDefault) - return NULL; - return (common != NULL ? common : &m_defJoySettings); + JoySettings *common = NULL; + for (vector::iterator it = m_joySettings.begin(); it != m_joySettings.end(); it++) + { + if ((*it)->joyNum == joyNum) + return *it; + else if ((*it)->joyNum == ANY_JOYSTICK) + common = *it; + } + if (!useDefault) + return NULL; + return (common != NULL ? common : &m_defJoySettings); } bool CInputSystem::IsAxis(EMousePart msePart) { - return msePart >= MouseXAxis && msePart <= MouseZAxisNeg; + return msePart >= MouseXAxis && msePart <= MouseZAxisNeg; } bool CInputSystem::IsFullAxis(EMousePart msePart) { - return IsAxis(msePart) && (((msePart - MouseXAxis) % 4) == AXIS_FULL || ((msePart - MouseXAxis) % 4) == AXIS_INVERTED); + return IsAxis(msePart) && (((msePart - MouseXAxis) % 4) == AXIS_FULL || ((msePart - MouseXAxis) % 4) == AXIS_INVERTED); } bool CInputSystem::GetAxisDetails(EMousePart msePart, int &axisNum, int &axisDir) { - if (!IsAxis(msePart)) - return false; - axisNum = (msePart - MouseXAxis) / 4; - axisDir = (msePart - MouseXAxis) % 4; - return true; + if (!IsAxis(msePart)) + return false; + axisNum = (msePart - MouseXAxis) / 4; + axisDir = (msePart - MouseXAxis) % 4; + return true; } bool CInputSystem::IsButton(EMousePart msePart) { - return msePart >= MouseButtonLeft && msePart <= MouseButtonX2; + return msePart >= MouseButtonLeft && msePart <= MouseButtonX2; } int CInputSystem::GetButtonNumber(EMousePart msePart) { - if (!IsButton(msePart)) - return -1; - return msePart - MouseButtonLeft; + if (!IsButton(msePart)) + return -1; + return msePart - MouseButtonLeft; } EMousePart CInputSystem::GetMouseAxis(int axisNum, int axisDir) { - if (axisNum > 0 || axisNum >= NUM_MOUSE_AXES || axisDir < 0 || axisDir > 3) - return MouseUnknown; - return (EMousePart)(MouseXAxis + 4 * axisNum + axisDir); + if (axisNum > 0 || axisNum >= NUM_MOUSE_AXES || axisDir < 0 || axisDir > 3) + return MouseUnknown; + return (EMousePart)(MouseXAxis + 4 * axisNum + axisDir); } EMousePart CInputSystem::GetMouseButton(int butNum) { - if (butNum < 0 || butNum >= NUM_MOUSE_BUTTONS) - return MouseUnknown; - return (EMousePart)(MouseButtonLeft + butNum); + if (butNum < 0 || butNum >= NUM_MOUSE_BUTTONS) + return MouseUnknown; + return (EMousePart)(MouseButtonLeft + butNum); } bool CInputSystem::IsAxis(EJoyPart joyPart) { - return joyPart >= JoyXAxis && joyPart <= JoyS2AxisNeg; + return joyPart >= JoyXAxis && joyPart <= JoyS2AxisNeg; } bool CInputSystem::IsFullAxis(EJoyPart joyPart) { - return IsAxis(joyPart) && (((joyPart - JoyXAxis) % 4) == AXIS_FULL || ((joyPart - JoyXAxis) % 4) == AXIS_INVERTED); + return IsAxis(joyPart) && (((joyPart - JoyXAxis) % 4) == AXIS_FULL || ((joyPart - JoyXAxis) % 4) == AXIS_INVERTED); } bool CInputSystem::IsSliderAxis(EJoyPart joyPart) { - return joyPart >= JoyS1Axis && joyPart <= JoyS2AxisNeg; + return joyPart >= JoyS1Axis && joyPart <= JoyS2AxisNeg; } bool CInputSystem::GetAxisDetails(EJoyPart joyPart, int &axisNum, int &axisDir) { - if (!IsAxis(joyPart)) - return false; - axisNum = (joyPart - JoyXAxis) / 4; - axisDir = (joyPart - JoyXAxis) % 4; - return true; + if (!IsAxis(joyPart)) + return false; + axisNum = (joyPart - JoyXAxis) / 4; + axisDir = (joyPart - JoyXAxis) % 4; + return true; } bool CInputSystem::IsPOV(EJoyPart joyPart) { - return joyPart >= JoyPOV0Up && joyPart <= JoyPOV3Right; + return joyPart >= JoyPOV0Up && joyPart <= JoyPOV3Right; } bool CInputSystem::GetPOVDetails(EJoyPart joyPart, int &povNum, int &povDir) { - if (!IsPOV(joyPart)) - return false; - povNum = (joyPart - JoyPOV0Up) / 4; - povDir = (joyPart - JoyPOV0Up) % 4; - return true; + if (!IsPOV(joyPart)) + return false; + povNum = (joyPart - JoyPOV0Up) / 4; + povDir = (joyPart - JoyPOV0Up) % 4; + return true; } bool CInputSystem::IsButton(EJoyPart joyPart) { - return joyPart >= JoyButton0 && joyPart <= JoyButton31; + return joyPart >= JoyButton0 && joyPart <= JoyButton31; } int CInputSystem::GetButtonNumber(EJoyPart joyPart) { - if (!IsButton(joyPart)) - return -1; - return joyPart - JoyButton0; + if (!IsButton(joyPart)) + return -1; + return joyPart - JoyButton0; } EJoyPart CInputSystem::GetJoyAxis(int axisNum, int axisDir) { - if (axisNum < 0 || axisNum >= NUM_JOY_AXES || axisDir < 0 || axisDir > 3) - return JoyUnknown; - return (EJoyPart)(JoyXAxis + 4 * axisNum + axisDir); + if (axisNum < 0 || axisNum >= NUM_JOY_AXES || axisDir < 0 || axisDir > 3) + return JoyUnknown; + return (EJoyPart)(JoyXAxis + 4 * axisNum + axisDir); } EJoyPart CInputSystem::GetJoyPOV(int povNum, int povDir) { - if (povNum < 0 || povNum >= NUM_JOY_POVS) - return JoyUnknown; - return (EJoyPart)(JoyPOV0Up + 4 * povNum + povDir); + if (povNum < 0 || povNum >= NUM_JOY_POVS) + return JoyUnknown; + return (EJoyPart)(JoyPOV0Up + 4 * povNum + povDir); } EJoyPart CInputSystem::GetJoyButton(int butNum) { - if (butNum < 0 || butNum >= NUM_JOY_BUTTONS) - return JoyUnknown; - return (EJoyPart)(JoyButton0 + butNum); + if (butNum < 0 || butNum >= NUM_JOY_BUTTONS) + return JoyUnknown; + return (EJoyPart)(JoyButton0 + butNum); } bool CInputSystem::ConfigMouseCentered() { - // Get mouse X & Y - int mx = GetMouseAxisValue(ANY_MOUSE, AXIS_X); - int my = GetMouseAxisValue(ANY_MOUSE, AXIS_Y); - - // See if mouse in center of display - unsigned lx = m_dispX + m_dispW / 4; - unsigned ly = m_dispY + m_dispH / 4; - return mx >= (int)lx && mx <= (int)(lx + m_dispW / 2) && my >= (int)ly && my <= (int)(ly + m_dispH / 2); -} + // Get mouse X & Y + int mx = GetMouseAxisValue(ANY_MOUSE, AXIS_X); + int my = GetMouseAxisValue(ANY_MOUSE, AXIS_Y); + + // See if mouse in center of display + unsigned lx = m_dispX + m_dispW / 4; + unsigned ly = m_dispY + m_dispH / 4; + return mx >= (int)lx && mx <= (int)(lx + m_dispW / 2) && my >= (int)ly && my <= (int)(ly + m_dispH / 2); +} CInputSource *CInputSystem::CreateAnyKeySource(int keyIndex) { - // Default ANY_KEYBOARD source is to use CMultiInputSource to combine all individual sources - vector keySrcs; - for (int kbdNum = 0; kbdNum < m_numKbds; kbdNum++) - { - CInputSource *keySrc = CreateKeySource(kbdNum, keyIndex); - if (keySrc != NULL) - keySrcs.push_back(keySrc); - } - return new CMultiInputSource(true, keySrcs); + // Default ANY_KEYBOARD source is to use CMultiInputSource to combine all individual sources + vector keySrcs; + for (int kbdNum = 0; kbdNum < m_numKbds; kbdNum++) + { + CInputSource *keySrc = CreateKeySource(kbdNum, keyIndex); + if (keySrc != NULL) + keySrcs.push_back(keySrc); + } + return new CMultiInputSource(true, keySrcs); } CInputSource *CInputSystem::CreateAnyMouseSource(EMousePart msePart) { - // Default ANY_MOUSE source is to use CMultiInputSource to combine all individual sources - vector mseSrcs; - for (int mseNum = 0; mseNum < m_numMice; mseNum++) - { - CInputSource *mseSrc = CreateMouseSource(mseNum, msePart); - if (mseSrc != NULL) - mseSrcs.push_back(mseSrc); - } - return new CMultiInputSource(true, mseSrcs); + // Default ANY_MOUSE source is to use CMultiInputSource to combine all individual sources + vector mseSrcs; + for (int mseNum = 0; mseNum < m_numMice; mseNum++) + { + CInputSource *mseSrc = CreateMouseSource(mseNum, msePart); + if (mseSrc != NULL) + mseSrcs.push_back(mseSrc); + } + return new CMultiInputSource(true, mseSrcs); } CInputSource *CInputSystem::CreateAnyJoySource(EJoyPart joyPart) { - // Default ANY_JOYSTICK source is to use CMultiInputSource to combine all individual sources - vector joySrcs; - for (int joyNum = 0; joyNum < m_numJoys; joyNum++) - { - CInputSource *joySrc = CreateJoySource(joyNum, joyPart); - if (joySrc != NULL) - joySrcs.push_back(joySrc); - } - return new CMultiInputSource(true, joySrcs); + // Default ANY_JOYSTICK source is to use CMultiInputSource to combine all individual sources + vector joySrcs; + for (int joyNum = 0; joyNum < m_numJoys; joyNum++) + { + CInputSource *joySrc = CreateJoySource(joyNum, joyPart); + if (joySrc != NULL) + joySrcs.push_back(joySrc); + } + return new CMultiInputSource(true, joySrcs); } CInputSource *CInputSystem::CreateKeySource(int kbdNum, int keyIndex) { - // Get key settings - KeySettings *settings = GetKeySettings(kbdNum, true); + // Get key settings + KeySettings *settings = GetKeySettings(kbdNum, true); - // Create source for given key index - return new CKeyInputSource(this, kbdNum, keyIndex, settings->sensitivity, settings->decaySpeed); + // Create source for given key index + return new CKeyInputSource(this, kbdNum, keyIndex, settings->sensitivity, settings->decaySpeed); } CInputSource *CInputSystem::CreateMouseSource(int mseNum, EMousePart msePart) { - // Get mouse settings - MouseSettings *settings = GetMouseSettings(mseNum, true); + // Get mouse settings + MouseSettings *settings = GetMouseSettings(mseNum, true); - // Create source according to given mouse part - int axisNum; - int axisDir; - if (GetAxisDetails(msePart, axisNum, axisDir)) - { - // Part is mouse axis so create axis source with appropriate deadzone setting - return new CMseAxisInputSource(this, mseNum, axisNum, axisDir, settings->deadZones[axisNum]); - } - else if (IsButton(msePart)) - { - // Part is mouse button so map it to button number - int butNum = GetButtonNumber(msePart); - if (butNum < 0) - return NULL; // Buttons out of range are invalid - return new CMseButInputSource(this, mseNum, butNum); - } + // Create source according to given mouse part + int axisNum; + int axisDir; + if (GetAxisDetails(msePart, axisNum, axisDir)) + { + // Part is mouse axis so create axis source with appropriate deadzone setting + return new CMseAxisInputSource(this, mseNum, axisNum, axisDir, settings->deadZones[axisNum]); + } + else if (IsButton(msePart)) + { + // Part is mouse button so map it to button number + int butNum = GetButtonNumber(msePart); + if (butNum < 0) + return NULL; // Buttons out of range are invalid + return new CMseButInputSource(this, mseNum, butNum); + } - // If got here, then mouse part is invalid - return NULL; + // If got here, then mouse part is invalid + return NULL; } CInputSource *CInputSystem::CreateJoySource(int joyNum, EJoyPart joyPart) { - // Get joystick details and settings - const JoyDetails *joyDetails = GetJoyDetails(joyNum); - JoySettings *settings = GetJoySettings(joyNum, true); - - // Create source according to given joystick part - int axisNum; - int axisDir; - int povNum; - int povDir; - if (GetAxisDetails(joyPart, axisNum, axisDir)) - { - // Part is joystick axis, so see whether joystick actually has this axis - if (!joyDetails->hasAxis[axisNum]) - return m_emptySource; // If joystick doesn't have axis, then return empty source rather than NULL as not really an error - // Otherwise, create axis source with appropriate axis range, deadzone and saturation settings - return new CJoyAxisInputSource(this, joyNum, axisNum, axisDir, - settings->axisMinVals[axisNum], settings->axisOffVals[axisNum], settings->axisMaxVals[axisNum], - settings->deadZones[axisNum], settings->saturations[axisNum]); - } - else if (GetPOVDetails(joyPart, povNum, povDir)) - { - // Part is joystick POV hat controller so see whether joystick has this POV - if (povNum >= joyDetails->numPOVs) - return m_emptySource; // If joystick doesn't have POV, then return empty source rather than NULL as not really an error - return new CJoyPOVInputSource(this, joyNum, povNum, povDir); - } - else if (IsButton(joyPart)) - { - // Part is joystick button so map it to a button number - int butNum = GetButtonNumber(joyPart); - if (butNum < 0 || butNum >= NUM_JOY_BUTTONS) - return NULL; // Buttons out of range are invalid - if (butNum >= joyDetails->numButtons) - return m_emptySource; // If joystick doesn't have button, then return empty source rather than NULL as not really an error - return new CJoyButInputSource(this, joyNum, butNum); - } - - // If got here, then joystick part is invalid - return NULL; + // Get joystick details and settings + const JoyDetails *joyDetails = GetJoyDetails(joyNum); + JoySettings *settings = GetJoySettings(joyNum, true); + + // Create source according to given joystick part + int axisNum; + int axisDir; + int povNum; + int povDir; + if (GetAxisDetails(joyPart, axisNum, axisDir)) + { + // Part is joystick axis, so see whether joystick actually has this axis + if (!joyDetails->hasAxis[axisNum]) + return m_emptySource; // If joystick doesn't have axis, then return empty source rather than NULL as not really an error + // Otherwise, create axis source with appropriate axis range, deadzone and saturation settings + return new CJoyAxisInputSource(this, joyNum, axisNum, axisDir, + settings->axisMinVals[axisNum], settings->axisOffVals[axisNum], settings->axisMaxVals[axisNum], + settings->deadZones[axisNum], settings->saturations[axisNum]); + } + else if (GetPOVDetails(joyPart, povNum, povDir)) + { + // Part is joystick POV hat controller so see whether joystick has this POV + if (povNum >= joyDetails->numPOVs) + return m_emptySource; // If joystick doesn't have POV, then return empty source rather than NULL as not really an error + return new CJoyPOVInputSource(this, joyNum, povNum, povDir); + } + else if (IsButton(joyPart)) + { + // Part is joystick button so map it to a button number + int butNum = GetButtonNumber(joyPart); + if (butNum < 0 || butNum >= NUM_JOY_BUTTONS) + return NULL; // Buttons out of range are invalid + if (butNum >= joyDetails->numButtons) + return m_emptySource; // If joystick doesn't have button, then return empty source rather than NULL as not really an error + return new CJoyButInputSource(this, joyNum, butNum); + } + + // If got here, then joystick part is invalid + return NULL; } bool CInputSystem::Initialize() { - // Initialize subclass - if (!InitializeSystem()) - return false; + // Initialize subclass + if (!InitializeSystem()) + return false; - // Get number of keyboard, mice and joysticks (they are stored here as need to access the values in the destructor) - m_numKbds = GetNumKeyboards(); - m_numMice = GetNumMice(); - m_numJoys = GetNumJoysticks(); + // Get number of keyboard, mice and joysticks (they are stored here as need to access the values in the destructor) + m_numKbds = GetNumKeyboards(); + m_numMice = GetNumMice(); + m_numJoys = GetNumJoysticks(); - // Create cache to hold input sources - CreateSourceCache(); + // Create cache to hold input sources + CreateSourceCache(); - GrabMouse(); - return true; + GrabMouse(); + return true; } void CInputSystem::SetDisplayGeom(unsigned dispX, unsigned dispY, unsigned dispW, unsigned dispH) { - // Remember display geometry - m_dispX = dispX; - m_dispY = dispY; - m_dispW = dispW; - m_dispH = dispH; + // Remember display geometry + m_dispX = dispX; + m_dispY = dispY; + m_dispW = dispW; + m_dispH = dispH; } CInputSource* CInputSystem::ParseSource(const char *mapping, bool fullAxisOnly) { - return ParseMultiSource(mapping, fullAxisOnly, true); + return ParseMultiSource(mapping, fullAxisOnly, true); } void CInputSystem::ClearSettings() { - // Delete all key settings - for (vector::iterator it = m_keySettings.begin(); it != m_keySettings.end(); it++) - delete *it; - m_keySettings.clear(); + // Delete all key settings + for (vector::iterator it = m_keySettings.begin(); it != m_keySettings.end(); it++) + delete *it; + m_keySettings.clear(); - // Delete all mouse settings - for (vector::iterator it = m_mseSettings.begin(); it != m_mseSettings.end(); it++) - delete *it; - m_mseSettings.clear(); + // Delete all mouse settings + for (vector::iterator it = m_mseSettings.begin(); it != m_mseSettings.end(); it++) + delete *it; + m_mseSettings.clear(); - // Delete all joystick settings - for (vector::iterator it = m_joySettings.begin(); it != m_joySettings.end(); it++) - delete *it; - m_joySettings.clear(); + // Delete all joystick settings + for (vector::iterator it = m_joySettings.begin(); it != m_joySettings.end(); it++) + delete *it; + m_joySettings.clear(); } void CInputSystem::PrintSettings() { - puts("Input System Settings"); - puts("---------------------"); - puts(""); + puts("Input System Settings"); + puts("---------------------"); + puts(""); - printf("Input System: %s\n", name); + printf("Input System: %s\n", name); - puts(""); + puts(""); - PrintDevices(); + PrintDevices(); - puts(""); + puts(""); - // Print all key settings for attached keyboards - KeySettings *keySettings; - if (m_numKbds == ANY_KEYBOARD) - { - puts("Common Keyboard Settings:"); - keySettings = GetKeySettings(ANY_KEYBOARD, true); - PrintKeySettings(ANY_KEYBOARD, keySettings); - } - else - { - for (int kbdNum = 0; kbdNum < m_numKbds; kbdNum++) - { - printf("Keyboard %d Settings:\n", kbdNum + 1); - keySettings = GetKeySettings(kbdNum, true); - PrintKeySettings(kbdNum, keySettings); - } - } + // Print all key settings for attached keyboards + KeySettings *keySettings; + if (m_numKbds == ANY_KEYBOARD) + { + puts("Common Keyboard Settings:"); + keySettings = GetKeySettings(ANY_KEYBOARD, true); + PrintKeySettings(ANY_KEYBOARD, keySettings); + } + else + { + for (int kbdNum = 0; kbdNum < m_numKbds; kbdNum++) + { + printf("Keyboard %d Settings:\n", kbdNum + 1); + keySettings = GetKeySettings(kbdNum, true); + PrintKeySettings(kbdNum, keySettings); + } + } - // Print all mouse settings for attached mice - MouseSettings *mseSettings; - if (m_numMice == ANY_MOUSE) - { - puts("Common Mouse Settings:"); - mseSettings = GetMouseSettings(ANY_MOUSE, true); - PrintMouseSettings(ANY_MOUSE, mseSettings); - } - else - { - for (int mseNum = 0; mseNum < m_numMice; mseNum++) - { - printf("Mouse %d Settings:\n", mseNum + 1); - mseSettings = GetMouseSettings(mseNum, true); - PrintMouseSettings(mseNum, mseSettings); - } - } + // Print all mouse settings for attached mice + MouseSettings *mseSettings; + if (m_numMice == ANY_MOUSE) + { + puts("Common Mouse Settings:"); + mseSettings = GetMouseSettings(ANY_MOUSE, true); + PrintMouseSettings(ANY_MOUSE, mseSettings); + } + else + { + for (int mseNum = 0; mseNum < m_numMice; mseNum++) + { + printf("Mouse %d Settings:\n", mseNum + 1); + mseSettings = GetMouseSettings(mseNum, true); + PrintMouseSettings(mseNum, mseSettings); + } + } - // Print all joystick settings for attached joysticks - JoySettings *joySettings; - if (m_numJoys == ANY_JOYSTICK) - { - puts("Common Joystick Settings:"); - joySettings = GetJoySettings(ANY_JOYSTICK, true); - PrintJoySettings(ANY_JOYSTICK, joySettings); - } - else - { - for (int joyNum = 0; joyNum < m_numJoys; joyNum++) - { - printf("Joystick %d Settings:\n", joyNum + 1); - joySettings = GetJoySettings(joyNum, true); - PrintJoySettings(joyNum, joySettings); - } - } + // Print all joystick settings for attached joysticks + JoySettings *joySettings; + if (m_numJoys == ANY_JOYSTICK) + { + puts("Common Joystick Settings:"); + joySettings = GetJoySettings(ANY_JOYSTICK, true); + PrintJoySettings(ANY_JOYSTICK, joySettings); + } + else + { + for (int joyNum = 0; joyNum < m_numJoys; joyNum++) + { + printf("Joystick %d Settings:\n", joyNum + 1); + joySettings = GetJoySettings(joyNum, true); + PrintJoySettings(joyNum, joySettings); + } + } - puts(""); + puts(""); +} + +void CInputSystem::LoadFromConfig(const Util::Config::Node &config) +{ + ClearSettings(); + ClearSourceCache(); + + // Read all key settings for attached keyboards + KeySettings *keySettings = LoadKeySettings(config, ANY_KEYBOARD); + if (keySettings != NULL) + m_keySettings.push_back(keySettings); + for (int kbdNum = 0; kbdNum < m_numKbds; kbdNum++) + { + keySettings = LoadKeySettings(config, kbdNum); + if (keySettings != NULL) + m_keySettings.push_back(keySettings); + } + + // Read all mouse settings for attached mice + MouseSettings *mseSettings = LoadMouseSettings(config, ANY_MOUSE); + if (mseSettings != NULL) + m_mseSettings.push_back(mseSettings); + for (int mseNum = 0; mseNum < m_numMice; mseNum++) + { + mseSettings = LoadMouseSettings(config, mseNum); + if (mseSettings != NULL) + m_mseSettings.push_back(mseSettings); + } + + // Read all joystick settings for attached joysticks + JoySettings *joySettings = LoadJoySettings(config, ANY_JOYSTICK); + if (joySettings != NULL) + m_joySettings.push_back(joySettings); + for (int joyNum = 0; joyNum < m_numJoys; joyNum++) + { + joySettings = LoadJoySettings(config, joyNum); + if (joySettings != NULL) + m_joySettings.push_back(joySettings); + } +} + +void CInputSystem::StoreToConfig(Util::Config::Node *config) +{ + // Write all key settings + for (vector::iterator it = m_keySettings.begin(); it != m_keySettings.end(); it++) + StoreKeySettings(config, *it); + + // Write all mouse settings + for (vector::iterator it = m_mseSettings.begin(); it != m_mseSettings.end(); it++) + StoreMouseSettings(config, *it); + + // Write all joystick settings + for (vector::iterator it = m_joySettings.begin(); it != m_joySettings.end(); it++) + StoreJoySettings(config, *it); } void CInputSystem::ReadFromINIFile(CINIFile *ini, const char *section) { - ClearSettings(); - ClearSourceCache(); + ClearSettings(); + ClearSourceCache(); - // Read all key settings for attached keyboards - KeySettings *keySettings = ReadKeySettings(ini, section, ANY_KEYBOARD); - if (keySettings != NULL) - m_keySettings.push_back(keySettings); - for (int kbdNum = 0; kbdNum < m_numKbds; kbdNum++) - { - keySettings = ReadKeySettings(ini, section, kbdNum); - if (keySettings != NULL) - m_keySettings.push_back(keySettings); - } + // Read all key settings for attached keyboards + KeySettings *keySettings = ReadKeySettings(ini, section, ANY_KEYBOARD); + if (keySettings != NULL) + m_keySettings.push_back(keySettings); + for (int kbdNum = 0; kbdNum < m_numKbds; kbdNum++) + { + keySettings = ReadKeySettings(ini, section, kbdNum); + if (keySettings != NULL) + m_keySettings.push_back(keySettings); + } - // Read all mouse settings for attached mice - MouseSettings *mseSettings = ReadMouseSettings(ini, section, ANY_MOUSE); - if (mseSettings != NULL) - m_mseSettings.push_back(mseSettings); - for (int mseNum = 0; mseNum < m_numMice; mseNum++) - { - mseSettings = ReadMouseSettings(ini, section, mseNum); - if (mseSettings != NULL) - m_mseSettings.push_back(mseSettings); - } + // Read all mouse settings for attached mice + MouseSettings *mseSettings = ReadMouseSettings(ini, section, ANY_MOUSE); + if (mseSettings != NULL) + m_mseSettings.push_back(mseSettings); + for (int mseNum = 0; mseNum < m_numMice; mseNum++) + { + mseSettings = ReadMouseSettings(ini, section, mseNum); + if (mseSettings != NULL) + m_mseSettings.push_back(mseSettings); + } - // Read all joystick settings for attached joysticks - JoySettings *joySettings = ReadJoySettings(ini, section, ANY_JOYSTICK); - if (joySettings != NULL) - m_joySettings.push_back(joySettings); - for (int joyNum = 0; joyNum < m_numJoys; joyNum++) - { - joySettings = ReadJoySettings(ini, section, joyNum); - if (joySettings != NULL) - m_joySettings.push_back(joySettings); - } + // Read all joystick settings for attached joysticks + JoySettings *joySettings = ReadJoySettings(ini, section, ANY_JOYSTICK); + if (joySettings != NULL) + m_joySettings.push_back(joySettings); + for (int joyNum = 0; joyNum < m_numJoys; joyNum++) + { + joySettings = ReadJoySettings(ini, section, joyNum); + if (joySettings != NULL) + m_joySettings.push_back(joySettings); + } } void CInputSystem::WriteToINIFile(CINIFile *ini, const char *section) { - // Write all key settings - for (vector::iterator it = m_keySettings.begin(); it != m_keySettings.end(); it++) - WriteKeySettings(ini, section, *it); + // Write all key settings + for (vector::iterator it = m_keySettings.begin(); it != m_keySettings.end(); it++) + WriteKeySettings(ini, section, *it); - // Write all mouse settings - for (vector::iterator it = m_mseSettings.begin(); it != m_mseSettings.end(); it++) - WriteMouseSettings(ini, section, *it); + // Write all mouse settings + for (vector::iterator it = m_mseSettings.begin(); it != m_mseSettings.end(); it++) + WriteMouseSettings(ini, section, *it); - // Write all joystick settings - for (vector::iterator it = m_joySettings.begin(); it != m_joySettings.end(); it++) - WriteJoySettings(ini, section, *it); + // Write all joystick settings + for (vector::iterator it = m_joySettings.begin(); it != m_joySettings.end(); it++) + WriteJoySettings(ini, section, *it); } bool CInputSystem::ReadMapping(char *buffer, unsigned bufSize, bool fullAxisOnly, unsigned readFlags, const char *escapeMapping) { - // Map given escape mapping to an input source - bool cancelled = false; - CInputSource *escape = ParseSource(escapeMapping); - if (escape) - escape->Acquire(); - - string badMapping; - string mapping; - vector badSources; - vector sources; - bool mseCentered = false; - - // See which sources activated to begin with and from here on ignore these (this stops badly calibrated axes that are constantly "active" - // from preventing the user from exiting read loop) - if (!Poll()) - goto Cancelled; + // Map given escape mapping to an input source + bool cancelled = false; + CInputSource *escape = ParseSource(escapeMapping); + if (escape) + escape->Acquire(); + + string badMapping; + string mapping; + vector badSources; + vector sources; + bool mseCentered = false; + + // See which sources activated to begin with and from here on ignore these (this stops badly calibrated axes that are constantly "active" + // from preventing the user from exiting read loop) + if (!Poll()) + goto Cancelled; - CheckAllSources(readFlags, fullAxisOnly, mseCentered, badSources, badMapping, sources); + CheckAllSources(readFlags, fullAxisOnly, mseCentered, badSources, badMapping, sources); - // Loop until have received meaningful inputs - for (;;) - { - // Poll inputs - if (!Poll()) - goto Cancelled; + // Loop until have received meaningful inputs + for (;;) + { + // Poll inputs + if (!Poll()) + goto Cancelled; - // Check if escape source was triggered - if (escape && escape->IsActive()) - { - // If so, wait until source no longer active and then exit - while (escape->IsActive()) - { - if (!Poll()) - goto Cancelled; - CThread::Sleep(1000/60); - } - goto Cancelled; - } + // Check if escape source was triggered + if (escape && escape->IsActive()) + { + // If so, wait until source no longer active and then exit + while (escape->IsActive()) + { + if (!Poll()) + goto Cancelled; + CThread::Sleep(1000/60); + } + goto Cancelled; + } - // Check all active sources - CheckAllSources(readFlags, fullAxisOnly, mseCentered, sources, mapping, badSources); + // Check all active sources + CheckAllSources(readFlags, fullAxisOnly, mseCentered, sources, mapping, badSources); - // When some inputs have been activated, keep looping until they have all been released again. - if (sources.size() > 0) - { - // Check each source is no longer active - bool active = false; - for (vector::iterator it = sources.begin(); it != sources.end(); it++) - { - if ((*it)->IsActive()) - { - active = true; - break; - } - } - if (!active) - { - // If so, get combined type of sources and if is valid then return - ESourceType type = CMultiInputSource::GetCombinedType(sources); - if ((type != SourceInvalid) && ((type == SourceFullAxis && fullAxisOnly) || (type != SourceFullAxis && !fullAxisOnly))) - break; + // When some inputs have been activated, keep looping until they have all been released again. + if (sources.size() > 0) + { + // Check each source is no longer active + bool active = false; + for (vector::iterator it = sources.begin(); it != sources.end(); it++) + { + if ((*it)->IsActive()) + { + active = true; + break; + } + } + if (!active) + { + // If so, get combined type of sources and if is valid then return + ESourceType type = CMultiInputSource::GetCombinedType(sources); + if ((type != SourceInvalid) && ((type == SourceFullAxis && fullAxisOnly) || (type != SourceFullAxis && !fullAxisOnly))) + break; - mapping.clear(); - sources.clear(); - mseCentered = false; - } - } + mapping.clear(); + sources.clear(); + mseCentered = false; + } + } - // Don't poll continuously - CThread::Sleep(1000/60); - } + // Don't poll continuously + CThread::Sleep(1000/60); + } - // Copy mapping to buffer and return - strncpy(buffer, mapping.c_str(), bufSize - 1); - buffer[bufSize - 1] = '\0'; - goto Finish; + // Copy mapping to buffer and return + strncpy(buffer, mapping.c_str(), bufSize - 1); + buffer[bufSize - 1] = '\0'; + goto Finish; Cancelled: - cancelled = true; + cancelled = true; Finish: - if (escape) - escape->Release(); - return !cancelled; + if (escape) + escape->Release(); + return !cancelled; } void CInputSystem::GrabMouse() { - m_grabMouse = true; + m_grabMouse = true; } void CInputSystem::UngrabMouse() { - m_grabMouse = false; + m_grabMouse = false; - // Make sure mouse is visible - SetMouseVisibility(true); + // Make sure mouse is visible + SetMouseVisibility(true); } bool CInputSystem::SendForceFeedbackCmd(int joyNum, int axisNum, ForceFeedbackCmd ffCmd) { - const JoyDetails *joyDetails = GetJoyDetails(joyNum); - if (!joyDetails->hasFFeedback || !joyDetails->axisHasFF[axisNum]) - return false; - return ProcessForceFeedbackCmd(joyNum, axisNum, ffCmd); + const JoyDetails *joyDetails = GetJoyDetails(joyNum); + if (!joyDetails->hasFFeedback || !joyDetails->axisHasFF[axisNum]) + return false; + return ProcessForceFeedbackCmd(joyNum, axisNum, ffCmd); } bool CInputSystem::DetectJoystickAxis(unsigned joyNum, unsigned &axisNum, const char *escapeMapping, const char *confirmMapping) { - const JoyDetails *joyDetails = GetJoyDetails(joyNum); - if (joyDetails == NULL) - { - puts("No such joystick!"); - return false; - } + const JoyDetails *joyDetails = GetJoyDetails(joyNum); + if (joyDetails == NULL) + { + puts("No such joystick!"); + return false; + } - // Map given escape & confirm mappings to input sources - bool cancelled = false; - CInputSource *escape = ParseSource(escapeMapping); - CInputSource *confirm = ParseSource(confirmMapping); - CInputSource *output = ParseSource("KEY_SHIFT"); - if (escape) - escape->Acquire(); - if (confirm) - confirm->Acquire(); - if (output) - output->Acquire(); + // Map given escape & confirm mappings to input sources + bool cancelled = false; + CInputSource *escape = ParseSource(escapeMapping); + CInputSource *confirm = ParseSource(confirmMapping); + CInputSource *output = ParseSource("KEY_SHIFT"); + if (escape) + escape->Acquire(); + if (confirm) + confirm->Acquire(); + if (output) + output->Acquire(); - printf("Move axis around and then press Return (or press Esc to cancel): "); - fflush(stdout); // required on terminals that use buffering + printf("Move axis around and then press Return (or press Esc to cancel): "); + fflush(stdout); // required on terminals that use buffering - unsigned maxRange; - //unsigned maxAxisNum; + unsigned maxRange; + //unsigned maxAxisNum; - bool firstOut = true; - int minVals[NUM_JOY_AXES]; - int maxVals[NUM_JOY_AXES]; - for (unsigned loopAxisNum = 0; loopAxisNum < NUM_JOY_AXES; loopAxisNum++) - { - if (!joyDetails->hasAxis[loopAxisNum]) - continue; - int joyVal = GetJoyAxisValue(joyNum, loopAxisNum); - minVals[loopAxisNum] = joyVal; - maxVals[loopAxisNum] = joyVal; - } - for (;;) - { - if (!Poll()) - goto Cancelled; - - // Check if escape source was triggered - if (escape && escape->IsActive()) - { - // If so, wait until source no longer active and then exit - while (escape->IsActive()) - { - if (!Poll()) - goto Cancelled; - CThread::Sleep(1000/60); - } - goto Cancelled; - } + bool firstOut = true; + int minVals[NUM_JOY_AXES]; + int maxVals[NUM_JOY_AXES]; + for (unsigned loopAxisNum = 0; loopAxisNum < NUM_JOY_AXES; loopAxisNum++) + { + if (!joyDetails->hasAxis[loopAxisNum]) + continue; + int joyVal = GetJoyAxisValue(joyNum, loopAxisNum); + minVals[loopAxisNum] = joyVal; + maxVals[loopAxisNum] = joyVal; + } + for (;;) + { + if (!Poll()) + goto Cancelled; + + // Check if escape source was triggered + if (escape && escape->IsActive()) + { + // If so, wait until source no longer active and then exit + while (escape->IsActive()) + { + if (!Poll()) + goto Cancelled; + CThread::Sleep(1000/60); + } + goto Cancelled; + } - // Check if confirm source was triggered - if (confirm && confirm->IsActive()) - { - // If so, wait until source no longer active and then exit - while (confirm->IsActive()) - { - if (!Poll()) - goto Cancelled; - CThread::Sleep(1000/60); - } - break; - } + // Check if confirm source was triggered + if (confirm && confirm->IsActive()) + { + // If so, wait until source no longer active and then exit + while (confirm->IsActive()) + { + if (!Poll()) + goto Cancelled; + CThread::Sleep(1000/60); + } + break; + } - for (unsigned loopAxisNum = 0; loopAxisNum < NUM_JOY_AXES; loopAxisNum++) - { - if (!joyDetails->hasAxis[loopAxisNum]) - continue; - int joyVal = GetJoyAxisValue(joyNum, loopAxisNum); - minVals[loopAxisNum] = min(joyVal, minVals[loopAxisNum]); - maxVals[loopAxisNum] = max(joyVal, maxVals[loopAxisNum]); - } + for (unsigned loopAxisNum = 0; loopAxisNum < NUM_JOY_AXES; loopAxisNum++) + { + if (!joyDetails->hasAxis[loopAxisNum]) + continue; + int joyVal = GetJoyAxisValue(joyNum, loopAxisNum); + minVals[loopAxisNum] = min(joyVal, minVals[loopAxisNum]); + maxVals[loopAxisNum] = max(joyVal, maxVals[loopAxisNum]); + } - // Check if output source is triggered, and if so output value for debugging - if (output && output->IsActive()) - { - if (firstOut) - puts(""); - printf(" ["); - for (unsigned loopAxisNum = 0; loopAxisNum < NUM_JOY_AXES; loopAxisNum++) - { - int joyVal = GetJoyAxisValue(joyNum, loopAxisNum); - if (loopAxisNum > 0) - printf(", "); - printf("%s: %d", s_axisIds[loopAxisNum], joyVal); - } - puts("]"); - firstOut = false; - } + // Check if output source is triggered, and if so output value for debugging + if (output && output->IsActive()) + { + if (firstOut) + puts(""); + printf(" ["); + for (unsigned loopAxisNum = 0; loopAxisNum < NUM_JOY_AXES; loopAxisNum++) + { + int joyVal = GetJoyAxisValue(joyNum, loopAxisNum); + if (loopAxisNum > 0) + printf(", "); + printf("%s: %d", s_axisIds[loopAxisNum], joyVal); + } + puts("]"); + firstOut = false; + } - // Don't poll continuously - CThread::Sleep(1000/60); - } + // Don't poll continuously + CThread::Sleep(1000/60); + } - maxRange = 0; - //maxAxisNum = 0; - for (unsigned loopAxisNum = 0; loopAxisNum < NUM_JOY_AXES; loopAxisNum++) - { - if (!joyDetails->hasAxis[loopAxisNum]) - continue; - unsigned range = maxVals[loopAxisNum] - minVals[loopAxisNum]; - if (range > maxRange) - { - maxRange = range; - axisNum = loopAxisNum; - } - } + maxRange = 0; + //maxAxisNum = 0; + for (unsigned loopAxisNum = 0; loopAxisNum < NUM_JOY_AXES; loopAxisNum++) + { + if (!joyDetails->hasAxis[loopAxisNum]) + continue; + unsigned range = maxVals[loopAxisNum] - minVals[loopAxisNum]; + if (range > maxRange) + { + maxRange = range; + axisNum = loopAxisNum; + } + } - if (maxRange > 3000) - printf("Detected %s\n", joyDetails->axisName[axisNum]); - else - { - cancelled = true; - puts("Not Detected"); - } - goto Finish; - + if (maxRange > 3000) + printf("Detected %s\n", joyDetails->axisName[axisNum]); + else + { + cancelled = true; + puts("Not Detected"); + } + goto Finish; + Cancelled: - puts("[Cancelled]"); - cancelled = true; + puts("[Cancelled]"); + cancelled = true; Finish: - if (escape) - escape->Release(); - if (confirm) - confirm->Release(); - if (output) - output->Release(); - return !cancelled; + if (escape) + escape->Release(); + if (confirm) + confirm->Release(); + if (output) + output->Release(); + return !cancelled; } bool CInputSystem::CalibrateJoystickAxis(unsigned joyNum, unsigned axisNum, const char *escapeMapping, const char *confirmMapping) { - const JoyDetails *joyDetails = GetJoyDetails(joyNum); - if (joyDetails == NULL || axisNum >= NUM_JOY_AXES || !joyDetails->hasAxis[axisNum]) - { - puts("No such axis or joystick!"); - return false; - } + const JoyDetails *joyDetails = GetJoyDetails(joyNum); + if (joyDetails == NULL || axisNum >= NUM_JOY_AXES || !joyDetails->hasAxis[axisNum]) + { + puts("No such axis or joystick!"); + return false; + } - // Map given escape mapping to input source - bool cancelled = false; - CInputSource *escape = ParseSource(escapeMapping); - CInputSource *output = ParseSource("KEY_SHIFT"); - if (escape) - escape->Acquire(); - if (output) - output->Acquire(); + // Map given escape mapping to input source + bool cancelled = false; + CInputSource *escape = ParseSource(escapeMapping); + CInputSource *output = ParseSource("KEY_SHIFT"); + if (escape) + escape->Acquire(); + if (output) + output->Acquire(); Repeat: - printf("Calibrating %s of joystick '%s'.\n\n", joyDetails->axisName[axisNum], joyDetails->name); - - unsigned totalRange; - unsigned posDeadZone; - unsigned negDeadZone; - unsigned deadZone; - - int posVal = 0; - int negVal = 0; - int offVal = 0; - unsigned posRange = 0; - unsigned negRange = 0; - unsigned posOffRange = 0; - unsigned negOffRange = 0; - char mapping[50]; - for (unsigned step = 0; step < 3; step++) - { - switch (step) - { - case 0: - puts("Step 1:"); - puts(" Move axis now to its furthest positive/'on' position and hold, ie:"); - if (axisNum == AXIS_X || axisNum == AXIS_RX || axisNum == AXIS_Z || axisNum == AXIS_RZ) - puts(" - for a horizontal joystick axis, push it all the way to the right."); - if (axisNum == AXIS_Y || axisNum == AXIS_RY || axisNum == AXIS_Z || axisNum == AXIS_RZ) - puts(" - for a vertical joystick axis, push it all the way downwards."); - if (axisNum == AXIS_S1 || axisNum == AXIS_S2) - puts(" - for a joystick slider, push it all the way to its extreme."); - puts(" - for a steering wheel, turn it all the way to the right."); - puts(" - for a pedal, press it all the way to the floor."); - break; - case 1: - puts("Step 2:"); - puts(" Move axis the other way to its furthest negative position and hold, ie:"); - if (axisNum == AXIS_X || axisNum == AXIS_RX || axisNum == AXIS_Z || axisNum == AXIS_RZ) - puts(" - for a horizontal joystick axis, push it all the way to the left."); - if (axisNum == AXIS_Y || axisNum == AXIS_RY || axisNum == AXIS_Z || axisNum == AXIS_RZ) - puts(" - for a vertical joystick axis, push it all the way updwards."); - if (axisNum == AXIS_S1 || axisNum == AXIS_S2) - puts(" - for a joystick slider, return it to its off position."); - puts(" - for a steering wheel, turn it all the way to the left."); - puts(" - for a pedal, let go of the pedal completely. If there is another pedal"); - puts(" that shares the same axis then press that one all the way to the floor."); - break; - case 2: - puts("Step 3:"); - puts(" Return axis to its central/'off' position and hold, ie:"); - if (axisNum == AXIS_X || axisNum == AXIS_RX || axisNum == AXIS_Y || axisNum == AXIS_RY || axisNum == AXIS_Z || axisNum == AXIS_RZ) - puts(" - for a joystick axis, let it return to the middle."); - else if (axisNum == AXIS_S1 || axisNum == AXIS_S2) - puts(" - for a joystick slider, keep it at its off position."); - puts(" - for a steering weel, turn it back to the center."); - puts(" - for a pedal, let go of pedal completely. Likewise for any other pedal"); - puts(" that shares the same axis."); - break; - } - printf("\nPress Return when done (or press Esc to cancel): "); - fflush(stdout); // required on terminals that use buffering + printf("Calibrating %s of joystick '%s'.\n\n", joyDetails->axisName[axisNum], joyDetails->name); + + unsigned totalRange; + unsigned posDeadZone; + unsigned negDeadZone; + unsigned deadZone; + + int posVal = 0; + int negVal = 0; + int offVal = 0; + unsigned posRange = 0; + unsigned negRange = 0; + unsigned posOffRange = 0; + unsigned negOffRange = 0; + char mapping[50]; + for (unsigned step = 0; step < 3; step++) + { + switch (step) + { + case 0: + puts("Step 1:"); + puts(" Move axis now to its furthest positive/'on' position and hold, ie:"); + if (axisNum == AXIS_X || axisNum == AXIS_RX || axisNum == AXIS_Z || axisNum == AXIS_RZ) + puts(" - for a horizontal joystick axis, push it all the way to the right."); + if (axisNum == AXIS_Y || axisNum == AXIS_RY || axisNum == AXIS_Z || axisNum == AXIS_RZ) + puts(" - for a vertical joystick axis, push it all the way downwards."); + if (axisNum == AXIS_S1 || axisNum == AXIS_S2) + puts(" - for a joystick slider, push it all the way to its extreme."); + puts(" - for a steering wheel, turn it all the way to the right."); + puts(" - for a pedal, press it all the way to the floor."); + break; + case 1: + puts("Step 2:"); + puts(" Move axis the other way to its furthest negative position and hold, ie:"); + if (axisNum == AXIS_X || axisNum == AXIS_RX || axisNum == AXIS_Z || axisNum == AXIS_RZ) + puts(" - for a horizontal joystick axis, push it all the way to the left."); + if (axisNum == AXIS_Y || axisNum == AXIS_RY || axisNum == AXIS_Z || axisNum == AXIS_RZ) + puts(" - for a vertical joystick axis, push it all the way updwards."); + if (axisNum == AXIS_S1 || axisNum == AXIS_S2) + puts(" - for a joystick slider, return it to its off position."); + puts(" - for a steering wheel, turn it all the way to the left."); + puts(" - for a pedal, let go of the pedal completely. If there is another pedal"); + puts(" that shares the same axis then press that one all the way to the floor."); + break; + case 2: + puts("Step 3:"); + puts(" Return axis to its central/'off' position and hold, ie:"); + if (axisNum == AXIS_X || axisNum == AXIS_RX || axisNum == AXIS_Y || axisNum == AXIS_RY || axisNum == AXIS_Z || axisNum == AXIS_RZ) + puts(" - for a joystick axis, let it return to the middle."); + else if (axisNum == AXIS_S1 || axisNum == AXIS_S2) + puts(" - for a joystick slider, keep it at its off position."); + puts(" - for a steering weel, turn it back to the center."); + puts(" - for a pedal, let go of pedal completely. Likewise for any other pedal"); + puts(" that shares the same axis."); + break; + } + printf("\nPress Return when done (or press Esc to cancel): "); + fflush(stdout); // required on terminals that use buffering - // Loop until user confirms or aborts - for (;;) - { - if (!ReadMapping(mapping, 50, false, READ_KEYBOARD|READ_MERGE, escapeMapping)) - goto Cancelled; - if (stricmp(mapping, confirmMapping) == 0) - break; - } + // Loop until user confirms or aborts + for (;;) + { + if (!ReadMapping(mapping, 50, false, READ_KEYBOARD|READ_MERGE, escapeMapping)) + goto Cancelled; + if (stricmp(mapping, confirmMapping) == 0) + break; + } - printf("Calibrating... "); - fflush(stdout); // required on terminals that use buffering + printf("Calibrating... "); + fflush(stdout); // required on terminals that use buffering - // Loop until at least three seconds have elapsed or user aborts - int joyVal = GetJoyAxisValue(joyNum, axisNum); - int minVal = joyVal; - int maxVal = joyVal; - bool firstOut = true; - for (unsigned frames = 0; frames < 3 * 60; frames++) - { - if (!Poll()) - goto Cancelled; + // Loop until at least three seconds have elapsed or user aborts + int joyVal = GetJoyAxisValue(joyNum, axisNum); + int minVal = joyVal; + int maxVal = joyVal; + bool firstOut = true; + for (unsigned frames = 0; frames < 3 * 60; frames++) + { + if (!Poll()) + goto Cancelled; - // Check if escape source was triggered - if (escape && escape->IsActive()) - { - // If so, wait until source no longer active and then exit - while (escape->IsActive()) - { - if (!Poll()) - goto Cancelled; - CThread::Sleep(1000/60); - } - goto Cancelled; - } + // Check if escape source was triggered + if (escape && escape->IsActive()) + { + // If so, wait until source no longer active and then exit + while (escape->IsActive()) + { + if (!Poll()) + goto Cancelled; + CThread::Sleep(1000/60); + } + goto Cancelled; + } - joyVal = GetJoyAxisValue(joyNum, axisNum); - minVal = min(minVal, joyVal); - maxVal = max(maxVal, joyVal); + joyVal = GetJoyAxisValue(joyNum, axisNum); + minVal = min(minVal, joyVal); + maxVal = max(maxVal, joyVal); - // Check if output source is triggered, and if so output value for debugging - if (output && output->IsActive()) - { - if (firstOut) - puts(""); - printf(" [value: %d, min: %d, %max: %d]\n", joyVal, minVal, maxVal); - firstOut = false; - } + // Check if output source is triggered, and if so output value for debugging + if (output && output->IsActive()) + { + if (firstOut) + puts(""); + printf(" [value: %d, min: %d, %max: %d]\n", joyVal, minVal, maxVal); + firstOut = false; + } - // Don't poll continuously - CThread::Sleep(1000/60); - } + // Don't poll continuously + CThread::Sleep(1000/60); + } - printf("Done\n\n"); + printf("Done\n\n"); - switch (step) - { - case 0: posVal = (abs(maxVal) >= abs(minVal) ? maxVal : minVal); break; - case 1: negVal = (abs(minVal) >= abs(maxVal) ? minVal : maxVal); break; - case 2: - if (minVal <= 0 && maxVal >= 0) - offVal = 0; - else if (minVal == DEFAULT_JOY_AXISMINVAL) - offVal = DEFAULT_JOY_AXISMINVAL; - else if (maxVal == DEFAULT_JOY_AXISMAXVAL) - offVal = DEFAULT_JOY_AXISMAXVAL; - else - offVal = (minVal + maxVal) / 2; - posRange = abs(posVal - offVal); - negRange = abs(negVal - offVal); - posOffRange = (unsigned)(posVal > offVal ? maxVal - offVal : offVal - minVal); - negOffRange = (unsigned)(posVal > offVal ? offVal - minVal : maxVal - offVal); - break; - } - } - - totalRange = posRange + negRange; - posDeadZone = (unsigned)ceil(100.0 * (double)posOffRange / (double)posRange); - negDeadZone = (unsigned)ceil(100.0 * (double)negOffRange / (double)negRange); - deadZone = max(1, max(negDeadZone, posDeadZone)); - - bool okay; - if (posVal > negVal) - okay = negVal <= offVal && offVal <= posVal && totalRange > 3000 && deadZone < 90; - else - okay = posVal <= offVal && offVal <= negVal && totalRange > 3000 && deadZone < 90; - if (okay) - { - JoySettings *commonSettings = GetJoySettings(ANY_JOYSTICK, true); - JoySettings *joySettings = GetJoySettings(joyNum, false); - if (joySettings == NULL) - { - joySettings = new JoySettings(*commonSettings); - m_joySettings.push_back(joySettings); - joySettings->joyNum = joyNum; - } + switch (step) + { + case 0: posVal = (abs(maxVal) >= abs(minVal) ? maxVal : minVal); break; + case 1: negVal = (abs(minVal) >= abs(maxVal) ? minVal : maxVal); break; + case 2: + if (minVal <= 0 && maxVal >= 0) + offVal = 0; + else if (minVal == DEFAULT_JOY_AXISMINVAL) + offVal = DEFAULT_JOY_AXISMINVAL; + else if (maxVal == DEFAULT_JOY_AXISMAXVAL) + offVal = DEFAULT_JOY_AXISMAXVAL; + else + offVal = (minVal + maxVal) / 2; + posRange = abs(posVal - offVal); + negRange = abs(negVal - offVal); + posOffRange = (unsigned)(posVal > offVal ? maxVal - offVal : offVal - minVal); + negOffRange = (unsigned)(posVal > offVal ? offVal - minVal : maxVal - offVal); + break; + } + } + + totalRange = posRange + negRange; + posDeadZone = (unsigned)ceil(100.0 * (double)posOffRange / (double)posRange); + negDeadZone = (unsigned)ceil(100.0 * (double)negOffRange / (double)negRange); + deadZone = max(1, max(negDeadZone, posDeadZone)); + + bool okay; + if (posVal > negVal) + okay = negVal <= offVal && offVal <= posVal && totalRange > 3000 && deadZone < 90; + else + okay = posVal <= offVal && offVal <= negVal && totalRange > 3000 && deadZone < 90; + if (okay) + { + JoySettings *commonSettings = GetJoySettings(ANY_JOYSTICK, true); + JoySettings *joySettings = GetJoySettings(joyNum, false); + if (joySettings == NULL) + { + joySettings = new JoySettings(*commonSettings); + m_joySettings.push_back(joySettings); + joySettings->joyNum = joyNum; + } - printf("Calibrated Axis Settings:\n\n"); - printf(" Min Value = %d\n", negVal); - printf(" Center/Off Value = %d\n", offVal); - printf(" Max Value = %d\n", posVal); - printf(" Dead Zone = %u %%\n", deadZone); - printf("\nAccept these settings: y/n? "); - fflush(stdout); // required on terminals that use buffering - - // Loop until user confirms or declines - while (ReadMapping(mapping, 50, false, READ_KEYBOARD|READ_MERGE, escapeMapping)) - { - if (stricmp(mapping, "KEY_N") == 0) - break; - else if (stricmp(mapping, "KEY_Y") == 0) - { - joySettings->axisMinVals[axisNum] = negVal; - joySettings->axisMaxVals[axisNum] = posVal; - joySettings->axisOffVals[axisNum] = offVal; - joySettings->deadZones[axisNum] = deadZone; - - ClearSourceCache(); + printf("Calibrated Axis Settings:\n\n"); + printf(" Min Value = %d\n", negVal); + printf(" Center/Off Value = %d\n", offVal); + printf(" Max Value = %d\n", posVal); + printf(" Dead Zone = %u %%\n", deadZone); + printf("\nAccept these settings: y/n? "); + fflush(stdout); // required on terminals that use buffering + + // Loop until user confirms or declines + while (ReadMapping(mapping, 50, false, READ_KEYBOARD|READ_MERGE, escapeMapping)) + { + if (stricmp(mapping, "KEY_N") == 0) + break; + else if (stricmp(mapping, "KEY_Y") == 0) + { + joySettings->axisMinVals[axisNum] = negVal; + joySettings->axisMaxVals[axisNum] = posVal; + joySettings->axisOffVals[axisNum] = offVal; + joySettings->deadZones[axisNum] = deadZone; + + ClearSourceCache(); - puts("Accepted"); - goto Finish; - } - } - goto Cancelled; - } - else - { - puts("There was a problem calibrating the axis. This may be because the steps"); - puts("were not followed correctly or the joystick is sending invalid data."); - printf("\nTry calibrating again: y/n? "); - fflush(stdout); // required on terminals that use buffering - - // Loop until user confirms or declines - while (ReadMapping(mapping, 50, false, READ_KEYBOARD|READ_MERGE, escapeMapping)) - { - if (stricmp(mapping, "KEY_N") == 0) - break; - else if (stricmp(mapping, "KEY_Y") == 0) - { - puts("[Cancelled]"); - goto Repeat; - } - } - goto Cancelled; - } - + puts("Accepted"); + goto Finish; + } + } + goto Cancelled; + } + else + { + puts("There was a problem calibrating the axis. This may be because the steps"); + puts("were not followed correctly or the joystick is sending invalid data."); + printf("\nTry calibrating again: y/n? "); + fflush(stdout); // required on terminals that use buffering + + // Loop until user confirms or declines + while (ReadMapping(mapping, 50, false, READ_KEYBOARD|READ_MERGE, escapeMapping)) + { + if (stricmp(mapping, "KEY_N") == 0) + break; + else if (stricmp(mapping, "KEY_Y") == 0) + { + puts("[Cancelled]"); + goto Repeat; + } + } + goto Cancelled; + } + Cancelled: - puts("[Cancelled]"); - cancelled = true; + puts("[Cancelled]"); + cancelled = true; Finish: - if (escape) - escape->Release(); - if (output) - output->Release(); - return !cancelled; + if (escape) + escape->Release(); + if (output) + output->Release(); + return !cancelled; } void CInputSystem::PrintDevices() { - puts("Keyboards:"); - if (m_numKbds == 0) - puts(" None"); - else if (m_numKbds == ANY_KEYBOARD) - puts(" System Keyboard"); - else - { - for (int kbdNum = 0; kbdNum < m_numKbds; kbdNum++) - { - const KeyDetails *keyDetails = GetKeyDetails(kbdNum); - printf(" %d: %s\n", kbdNum + 1, keyDetails->name); - } - } + puts("Keyboards:"); + if (m_numKbds == 0) + puts(" None"); + else if (m_numKbds == ANY_KEYBOARD) + puts(" System Keyboard"); + else + { + for (int kbdNum = 0; kbdNum < m_numKbds; kbdNum++) + { + const KeyDetails *keyDetails = GetKeyDetails(kbdNum); + printf(" %d: %s\n", kbdNum + 1, keyDetails->name); + } + } - puts("Mice:"); - if (m_numMice == 0) - puts(" None"); - else if (m_numMice == ANY_MOUSE) - puts(" System Mouse"); - else - { - for (int mseNum = 0; mseNum < m_numMice; mseNum++) - { - const MouseDetails *mseDetails = GetMouseDetails(mseNum); - printf(" %d: %s\n", mseNum + 1, mseDetails->name); - } - } + puts("Mice:"); + if (m_numMice == 0) + puts(" None"); + else if (m_numMice == ANY_MOUSE) + puts(" System Mouse"); + else + { + for (int mseNum = 0; mseNum < m_numMice; mseNum++) + { + const MouseDetails *mseDetails = GetMouseDetails(mseNum); + printf(" %d: %s\n", mseNum + 1, mseDetails->name); + } + } - puts("Joysticks:"); - if (m_numJoys == 0) - puts(" None"); - else if (m_numJoys == ANY_JOYSTICK) - puts(" System Joystick"); - else - { - for (int joyNum = 0; joyNum < m_numJoys; joyNum++) - { - const JoyDetails *joyDetails = GetJoyDetails(joyNum); - if (joyDetails->hasFFeedback) - printf(" %d: %s [Force Feedback Available]\n", joyNum + 1, joyDetails->name); - else - printf(" %d: %s\n", joyNum + 1, joyDetails->name); - } - } + puts("Joysticks:"); + if (m_numJoys == 0) + puts(" None"); + else if (m_numJoys == ANY_JOYSTICK) + puts(" System Joystick"); + else + { + for (int joyNum = 0; joyNum < m_numJoys; joyNum++) + { + const JoyDetails *joyDetails = GetJoyDetails(joyNum); + if (joyDetails->hasFFeedback) + printf(" %d: %s [Force Feedback Available]\n", joyNum + 1, joyDetails->name); + else + printf(" %d: %s\n", joyNum + 1, joyDetails->name); + } + } } /* * CInputSystem::CKeyInputSource */ CInputSystem::CKeyInputSource::CKeyInputSource(CInputSystem *system, int kbdNum, int keyIndex, unsigned sensitivity, unsigned decaySpeed) : - CInputSource(SourceSwitch), m_system(system), m_kbdNum(kbdNum), m_keyIndex(keyIndex), m_val(0) + CInputSource(SourceSwitch), m_system(system), m_kbdNum(kbdNum), m_keyIndex(keyIndex), m_val(0) { - // Calculate max value and incr and decr values (sensitivity is given as percentage 1-100, with 100 being most sensitive, and - // decay speed given as percentage 1-200 of attack speed) - int s = Clamp((int)sensitivity, 1, 100); - int d = Clamp((int)decaySpeed, 1, 200); - m_incr = 100 * s; - m_decr = d * s; - m_maxVal = 10000; + // Calculate max value and incr and decr values (sensitivity is given as percentage 1-100, with 100 being most sensitive, and + // decay speed given as percentage 1-200 of attack speed) + int s = Clamp((int)sensitivity, 1, 100); + int d = Clamp((int)decaySpeed, 1, 200); + m_incr = 100 * s; + m_decr = d * s; + m_maxVal = 10000; } bool CInputSystem::CKeyInputSource::GetValueAsSwitch(bool &val) { - if (!m_system->IsKeyPressed(m_kbdNum, m_keyIndex)) - return false; - val = true; - return true; + if (!m_system->IsKeyPressed(m_kbdNum, m_keyIndex)) + return false; + val = true; + return true; } bool CInputSystem::CKeyInputSource::GetValueAsAnalog(int &val, int minVal, int offVal, int maxVal) { - if (m_system->IsKeyPressed(m_kbdNum, m_keyIndex)) - m_val = min(m_maxVal, m_val + m_incr); - else - m_val = max(0, m_val - m_decr); - if (m_val == 0) - return false; - val = Scale(m_val, 0, 0, m_maxVal, minVal, offVal, maxVal); - return true; + if (m_system->IsKeyPressed(m_kbdNum, m_keyIndex)) + m_val = min(m_maxVal, m_val + m_incr); + else + m_val = max(0, m_val - m_decr); + if (m_val == 0) + return false; + val = Scale(m_val, 0, 0, m_maxVal, minVal, offVal, maxVal); + return true; } /* * CInputSystem::CMseAxisInputSource */ CInputSystem::CMseAxisInputSource::CMseAxisInputSource(CInputSystem *system, int mseNum, int axisNum, int axisDir, unsigned deadZone) : - CInputSource(axisDir == AXIS_FULL || axisDir == AXIS_INVERTED ? SourceFullAxis : SourceHalfAxis), - m_system(system), m_mseNum(mseNum), m_axisNum(axisNum), m_axisDir(axisDir) + CInputSource(axisDir == AXIS_FULL || axisDir == AXIS_INVERTED ? SourceFullAxis : SourceHalfAxis), + m_system(system), m_mseNum(mseNum), m_axisNum(axisNum), m_axisDir(axisDir) { - // If X- or Y-axis then calculate size of dead pixels region in centre of display (deadzone is given as a percentage 0-99) - if (m_axisNum == AXIS_X || m_axisNum == AXIS_Y) - { - double dDeadZone = (double)Clamp((int)deadZone, 0, 99) / 100.0; - m_deadPixels = (int)(dDeadZone * (double)(m_axisNum == AXIS_X ? m_system->m_dispW : m_system->m_dispH)); - } - else - m_deadPixels = Clamp((int)deadZone, 0, 99); + // If X- or Y-axis then calculate size of dead pixels region in centre of display (deadzone is given as a percentage 0-99) + if (m_axisNum == AXIS_X || m_axisNum == AXIS_Y) + { + double dDeadZone = (double)Clamp((int)deadZone, 0, 99) / 100.0; + m_deadPixels = (int)(dDeadZone * (double)(m_axisNum == AXIS_X ? m_system->m_dispW : m_system->m_dispH)); + } + else + m_deadPixels = Clamp((int)deadZone, 0, 99); } int CInputSystem::CMseAxisInputSource::ScaleAxisValue(int minVal, int offVal, int maxVal) { - int mseVal = m_system->GetMouseAxisValue(m_mseNum, m_axisNum); - // If X- or Y-axis then convert to value centered around zero (ie relative to centre of display) - int mseMin, mseMax; - if (m_axisNum == AXIS_X || m_axisNum == AXIS_Y) - { - int dispExtent = (int)(m_axisNum == AXIS_X ? m_system->m_dispW : m_system->m_dispH); - if (dispExtent == 0) - return offVal; - mseMin = -dispExtent / 2; - mseMax = mseMin + dispExtent - 1; - mseVal = (m_axisNum == AXIS_X ? mseVal - m_system->m_dispX : mseVal - m_system->m_dispY) - dispExtent / 2; - } - else - { - // Z-axis (wheel) is always between -100 and 100 - mseMin = -100; - mseMax = 100; - } - // Check value is not zero - if (mseVal == 0) - return offVal; - // Scale values from dead zone to display edge, taking positive or negative values only or using the whole axis range as required - int dZone = (mseVal > 0 ? m_deadPixels / 2 : m_deadPixels - m_deadPixels / 2); - if (m_axisDir == AXIS_POS) return Scale(mseVal, dZone, dZone, mseMax, minVal, offVal, maxVal); - else if (m_axisDir == AXIS_NEG) return Scale(mseVal, -dZone, -dZone, mseMin, minVal, offVal, maxVal); - else if (m_axisDir == AXIS_FULL) - { - // Full axis range - if (mseVal > 0) return Scale(mseVal, dZone, dZone, mseMax, minVal, offVal, maxVal); - else return Scale(mseVal, mseMin, -dZone, -dZone, minVal, offVal, maxVal); - } - else - { - // Full axis range, but inverted - if (mseVal > 0) return Scale(mseVal, dZone, dZone, mseMax, maxVal, offVal, minVal); - else return Scale(mseVal, mseMin, -dZone, -dZone, maxVal, offVal, minVal); - } + int mseVal = m_system->GetMouseAxisValue(m_mseNum, m_axisNum); + // If X- or Y-axis then convert to value centered around zero (ie relative to centre of display) + int mseMin, mseMax; + if (m_axisNum == AXIS_X || m_axisNum == AXIS_Y) + { + int dispExtent = (int)(m_axisNum == AXIS_X ? m_system->m_dispW : m_system->m_dispH); + if (dispExtent == 0) + return offVal; + mseMin = -dispExtent / 2; + mseMax = mseMin + dispExtent - 1; + mseVal = (m_axisNum == AXIS_X ? mseVal - m_system->m_dispX : mseVal - m_system->m_dispY) - dispExtent / 2; + } + else + { + // Z-axis (wheel) is always between -100 and 100 + mseMin = -100; + mseMax = 100; + } + // Check value is not zero + if (mseVal == 0) + return offVal; + // Scale values from dead zone to display edge, taking positive or negative values only or using the whole axis range as required + int dZone = (mseVal > 0 ? m_deadPixels / 2 : m_deadPixels - m_deadPixels / 2); + if (m_axisDir == AXIS_POS) return Scale(mseVal, dZone, dZone, mseMax, minVal, offVal, maxVal); + else if (m_axisDir == AXIS_NEG) return Scale(mseVal, -dZone, -dZone, mseMin, minVal, offVal, maxVal); + else if (m_axisDir == AXIS_FULL) + { + // Full axis range + if (mseVal > 0) return Scale(mseVal, dZone, dZone, mseMax, minVal, offVal, maxVal); + else return Scale(mseVal, mseMin, -dZone, -dZone, minVal, offVal, maxVal); + } + else + { + // Full axis range, but inverted + if (mseVal > 0) return Scale(mseVal, dZone, dZone, mseMax, maxVal, offVal, minVal); + else return Scale(mseVal, mseMin, -dZone, -dZone, maxVal, offVal, minVal); + } } bool CInputSystem::CMseAxisInputSource::GetValueAsSwitch(bool &val) { - // For Z-axis (wheel), switch value is handled slightly differently - if (m_axisNum == AXIS_Z) - { - int wheelDir = m_system->GetMouseWheelDir(m_mseNum); - if (((m_axisDir == AXIS_POS || m_axisDir == AXIS_FULL) && wheelDir <= 0) || - ((m_axisDir == AXIS_NEG || m_axisDir == AXIS_INVERTED) && wheelDir >= 0)) - return false; - } - else - { - if (ScaleAxisValue(0, 0, 3) < 2) - return false; - } - val = true; - return true; + // For Z-axis (wheel), switch value is handled slightly differently + if (m_axisNum == AXIS_Z) + { + int wheelDir = m_system->GetMouseWheelDir(m_mseNum); + if (((m_axisDir == AXIS_POS || m_axisDir == AXIS_FULL) && wheelDir <= 0) || + ((m_axisDir == AXIS_NEG || m_axisDir == AXIS_INVERTED) && wheelDir >= 0)) + return false; + } + else + { + if (ScaleAxisValue(0, 0, 3) < 2) + return false; + } + val = true; + return true; } bool CInputSystem::CMseAxisInputSource::GetValueAsAnalog(int &val, int minVal, int offVal, int maxVal) { - int axisVal = ScaleAxisValue(minVal, offVal, maxVal); - if (axisVal == offVal) - return false; - val = axisVal; - return true; + int axisVal = ScaleAxisValue(minVal, offVal, maxVal); + if (axisVal == offVal) + return false; + val = axisVal; + return true; } /* * CInputSystem::CMseButInputSource */ CInputSystem::CMseButInputSource::CMseButInputSource(CInputSystem *system, int mseNum, int butNum) : - CInputSource(SourceSwitch), m_system(system), m_mseNum(mseNum), m_butNum(butNum) + CInputSource(SourceSwitch), m_system(system), m_mseNum(mseNum), m_butNum(butNum) { - // + // } bool CInputSystem::CMseButInputSource::GetValueAsSwitch(bool &val) { - if (!m_system->IsMouseButPressed(m_mseNum, m_butNum)) - return false; - val = true; - return true; + if (!m_system->IsMouseButPressed(m_mseNum, m_butNum)) + return false; + val = true; + return true; } bool CInputSystem::CMseButInputSource::GetValueAsAnalog(int &val, int minVal, int offVal, int maxVal) { - if (!m_system->IsMouseButPressed(m_mseNum, m_butNum)) - return false; - val = maxVal; - return true; + if (!m_system->IsMouseButPressed(m_mseNum, m_butNum)) + return false; + val = maxVal; + return true; } /* * CInputSystem::CJoyAxisInputSource */ CInputSystem::CJoyAxisInputSource::CJoyAxisInputSource(CInputSystem *system, int joyNum, int axisNum, int axisDir, - int axisMinVal, int axisOffVal, int axisMaxVal, unsigned deadZone, unsigned saturation) : - CInputSource(axisDir == AXIS_FULL || axisDir == AXIS_INVERTED ? SourceFullAxis : SourceHalfAxis), - m_system(system), m_joyNum(joyNum), m_axisNum(axisNum), m_axisDir(axisDir), m_axisMinVal(axisMinVal), m_axisOffVal(axisOffVal), m_axisMaxVal(axisMaxVal) + int axisMinVal, int axisOffVal, int axisMaxVal, unsigned deadZone, unsigned saturation) : + CInputSource(axisDir == AXIS_FULL || axisDir == AXIS_INVERTED ? SourceFullAxis : SourceHalfAxis), + m_system(system), m_joyNum(joyNum), m_axisNum(axisNum), m_axisDir(axisDir), m_axisMinVal(axisMinVal), m_axisOffVal(axisOffVal), m_axisMaxVal(axisMaxVal) { - m_axisInverted = m_axisMaxVal < m_axisMinVal; - // Calculate pos/neg deadzone and saturation points (joystick raw values range from axisMinVal to axisMasVal (centered/off at axisOffVal), - // deadzone given as percentage 0-99 and saturation given as percentage 1 - 200) - double dDeadZone = (double)Clamp((int)deadZone, 0, 99) / 100.0; - double dSaturation = (double)Clamp((int)saturation, (int)deadZone + 1, 200) / 100.0; - m_posDZone = m_axisOffVal + (int)(dDeadZone * (m_axisMaxVal - m_axisOffVal)); - m_negDZone = m_axisOffVal + (int)(dDeadZone * (m_axisMinVal - m_axisOffVal)); - m_posSat = m_axisOffVal + (int)(dSaturation * (m_axisMaxVal - m_axisOffVal)); - m_negSat = m_axisOffVal + (int)(dSaturation * (m_axisMinVal - m_axisOffVal)); + m_axisInverted = m_axisMaxVal < m_axisMinVal; + // Calculate pos/neg deadzone and saturation points (joystick raw values range from axisMinVal to axisMasVal (centered/off at axisOffVal), + // deadzone given as percentage 0-99 and saturation given as percentage 1 - 200) + double dDeadZone = (double)Clamp((int)deadZone, 0, 99) / 100.0; + double dSaturation = (double)Clamp((int)saturation, (int)deadZone + 1, 200) / 100.0; + m_posDZone = m_axisOffVal + (int)(dDeadZone * (m_axisMaxVal - m_axisOffVal)); + m_negDZone = m_axisOffVal + (int)(dDeadZone * (m_axisMinVal - m_axisOffVal)); + m_posSat = m_axisOffVal + (int)(dSaturation * (m_axisMaxVal - m_axisOffVal)); + m_negSat = m_axisOffVal + (int)(dSaturation * (m_axisMinVal - m_axisOffVal)); } int CInputSystem::CJoyAxisInputSource::ScaleAxisValue(int minVal, int offVal, int maxVal) { - // Get raw axis value from input system - int joyVal = m_system->GetJoyAxisValue(m_joyNum, m_axisNum); - // Check if value is at axis off value - if (joyVal == m_axisOffVal) - return offVal; - // Scale value between deadzone and saturation points, taking positive or negative values only or using the whole axis range as required - if (m_axisDir == AXIS_POS) return Scale(joyVal, m_posDZone, m_posDZone, m_posSat, minVal, offVal, maxVal); - else if (m_axisDir == AXIS_NEG) return Scale(joyVal, m_negDZone, m_negDZone, m_negSat, minVal, offVal, maxVal); - else if (m_axisDir == AXIS_FULL) - { - // Full axis range - if ((!m_axisInverted && joyVal > m_axisOffVal) || (m_axisInverted && joyVal < m_axisOffVal)) - return Scale(joyVal, m_posDZone, m_posDZone, m_posSat, minVal, offVal, maxVal); - else - return Scale(joyVal, m_negSat, m_negDZone, m_negDZone, minVal, offVal, maxVal); - } - else - { - // Full axis range, but inverted - if ((!m_axisInverted && joyVal > m_axisOffVal) || (m_axisInverted && joyVal < m_axisOffVal)) - return Scale(joyVal, m_posDZone, m_posDZone, m_posSat, maxVal, offVal, minVal); - else - return Scale(joyVal, m_negSat, m_negDZone, m_negDZone, maxVal, offVal, minVal); - } + // Get raw axis value from input system + int joyVal = m_system->GetJoyAxisValue(m_joyNum, m_axisNum); + // Check if value is at axis off value + if (joyVal == m_axisOffVal) + return offVal; + // Scale value between deadzone and saturation points, taking positive or negative values only or using the whole axis range as required + if (m_axisDir == AXIS_POS) return Scale(joyVal, m_posDZone, m_posDZone, m_posSat, minVal, offVal, maxVal); + else if (m_axisDir == AXIS_NEG) return Scale(joyVal, m_negDZone, m_negDZone, m_negSat, minVal, offVal, maxVal); + else if (m_axisDir == AXIS_FULL) + { + // Full axis range + if ((!m_axisInverted && joyVal > m_axisOffVal) || (m_axisInverted && joyVal < m_axisOffVal)) + return Scale(joyVal, m_posDZone, m_posDZone, m_posSat, minVal, offVal, maxVal); + else + return Scale(joyVal, m_negSat, m_negDZone, m_negDZone, minVal, offVal, maxVal); + } + else + { + // Full axis range, but inverted + if ((!m_axisInverted && joyVal > m_axisOffVal) || (m_axisInverted && joyVal < m_axisOffVal)) + return Scale(joyVal, m_posDZone, m_posDZone, m_posSat, maxVal, offVal, minVal); + else + return Scale(joyVal, m_negSat, m_negDZone, m_negDZone, maxVal, offVal, minVal); + } } bool CInputSystem::CJoyAxisInputSource::GetValueAsSwitch(bool &val) { - if (ScaleAxisValue(0, 0, 3) < 2) - return false; - val = true; - return true; + if (ScaleAxisValue(0, 0, 3) < 2) + return false; + val = true; + return true; } bool CInputSystem::CJoyAxisInputSource::GetValueAsAnalog(int &val, int minVal, int offVal, int maxVal) { - int axisVal = ScaleAxisValue(minVal, offVal, maxVal); - if (axisVal == offVal) - return false; - val = axisVal; - return true; + int axisVal = ScaleAxisValue(minVal, offVal, maxVal); + if (axisVal == offVal) + return false; + val = axisVal; + return true; } bool CInputSystem::CJoyAxisInputSource::SendForceFeedbackCmd(ForceFeedbackCmd ffCmd) { - return m_system->SendForceFeedbackCmd(m_joyNum, m_axisNum, ffCmd); + return m_system->SendForceFeedbackCmd(m_joyNum, m_axisNum, ffCmd); } /* * CInputSystem::CJoyPOVInputSource */ CInputSystem::CJoyPOVInputSource::CJoyPOVInputSource(CInputSystem *system, int joyNum, int povNum, int povDir) : - CInputSource(SourceSwitch), m_system(system), m_joyNum(joyNum), m_povNum(povNum), m_povDir(povDir) + CInputSource(SourceSwitch), m_system(system), m_joyNum(joyNum), m_povNum(povNum), m_povDir(povDir) { - // + // } bool CInputSystem::CJoyPOVInputSource::GetValueAsSwitch(bool &val) { - if (!m_system->IsJoyPOVInDir(m_joyNum, m_povNum, m_povDir)) - return false; - val = true; - return true; + if (!m_system->IsJoyPOVInDir(m_joyNum, m_povNum, m_povDir)) + return false; + val = true; + return true; } bool CInputSystem::CJoyPOVInputSource::GetValueAsAnalog(int &val, int minVal, int offVal, int maxVal) { - if (!m_system->IsJoyPOVInDir(m_joyNum, m_povNum, m_povDir)) - return false; - val = maxVal; - return true; + if (!m_system->IsJoyPOVInDir(m_joyNum, m_povNum, m_povDir)) + return false; + val = maxVal; + return true; } - + /* * CInputSystem::CJoyButInputSource */ CInputSystem::CJoyButInputSource::CJoyButInputSource(CInputSystem *system, int joyNum, int butNum) : - CInputSource(SourceSwitch), m_system(system), m_joyNum(joyNum), m_butNum(butNum) + CInputSource(SourceSwitch), m_system(system), m_joyNum(joyNum), m_butNum(butNum) { - // + // } bool CInputSystem::CJoyButInputSource::GetValueAsSwitch(bool &val) { - if (!m_system->IsJoyButPressed(m_joyNum, m_butNum)) - return false; - val = true; - return true; + if (!m_system->IsJoyButPressed(m_joyNum, m_butNum)) + return false; + val = true; + return true; } bool CInputSystem::CJoyButInputSource::GetValueAsAnalog(int &val, int minVal, int offVal, int maxVal) { - if (!m_system->IsJoyButPressed(m_joyNum, m_butNum)) - return false; - val = maxVal; - return true; + if (!m_system->IsJoyButPressed(m_joyNum, m_butNum)) + return false; + val = maxVal; + return true; } diff --git a/Src/Inputs/InputSystem.h b/Src/Inputs/InputSystem.h index 9cdb4e8..d4293c9 100644 --- a/Src/Inputs/InputSystem.h +++ b/Src/Inputs/InputSystem.h @@ -35,6 +35,7 @@ using namespace std; #include "MultiInputSource.h" +#include "Util/NewConfig.h" class CInput; class CInputSource; @@ -104,24 +105,24 @@ class CINIFile; */ enum EMousePart { - MouseUnknown = -1, - MouseXAxis = 0, - MouseXAxisInv, - MouseXAxisPos, - MouseXAxisNeg, - MouseYAxis, - MouseYAxisInv, - MouseYAxisPos, - MouseYAxisNeg, - MouseZAxis, - MouseZAxisInv, - MouseZAxisPos, - MouseZAxisNeg, - MouseButtonLeft, - MouseButtonMiddle, - MouseButtonRight, - MouseButtonX1, - MouseButtonX2, + MouseUnknown = -1, + MouseXAxis = 0, + MouseXAxisInv, + MouseXAxisPos, + MouseXAxisNeg, + MouseYAxis, + MouseYAxisInv, + MouseYAxisPos, + MouseYAxisNeg, + MouseZAxis, + MouseZAxisInv, + MouseZAxisPos, + MouseZAxisNeg, + MouseButtonLeft, + MouseButtonMiddle, + MouseButtonRight, + MouseButtonX1, + MouseButtonX2, }; /* @@ -129,99 +130,99 @@ enum EMousePart */ enum EJoyPart { - JoyUnknown = -1, - JoyXAxis = 0, - JoyXAxisInv, - JoyXAxisPos, - JoyXAxisNeg, - JoyYAxis, - JoyYAxisInv, - JoyYAxisPos, - JoyYAxisNeg, - JoyZAxis, - JoyZAxisInv, - JoyZAxisPos, - JoyZAxisNeg, - JoyRXAxis, - JoyRXAxisInv, - JoyRXAxisPos, - JoyRXAxisNeg, - JoyRYAxis, - JoyRYAxisInv, - JoyRYAxisPos, - JoyRYAxisNeg, - JoyRZAxis, - JoyRZAxisInv, - JoyRZAxisPos, - JoyRZAxisNeg, - JoyS1Axis, - JoyS1AxisInv, - JoyS1AxisPos, - JoyS1AxisNeg, - JoyS2Axis, - JoyS2AxisInv, - JoyS2AxisPos, - JoyS2AxisNeg, - JoyPOV0Up, - JoyPOV0Down, - JoyPOV0Left, - JoyPOV0Right, - JoyPOV1Up, - JoyPOV1Down, - JoyPOV1Left, - JoyPOV1Right, - JoyPOV2Up, - JoyPOV2Down, - JoyPOV2Left, - JoyPOV2Right, - JoyPOV3Up, - JoyPOV3Down, - JoyPOV3Left, - JoyPOV3Right, - JoyButton0, - JoyButton1, - JoyButton2, - JoyButton3, - JoyButton4, - JoyButton5, - JoyButton6, - JoyButton7, - JoyButton8, - JoyButton9, - JoyButton10, - JoyButton11, - JoyButton12, - JoyButton13, - JoyButton14, - JoyButton15, - JoyButton16, - JoyButton17, - JoyButton18, - JoyButton19, - JoyButton20, - JoyButton21, - JoyButton22, - JoyButton23, - JoyButton24, - JoyButton25, - JoyButton26, - JoyButton27, - JoyButton28, - JoyButton29, - JoyButton30, - JoyButton31 + JoyUnknown = -1, + JoyXAxis = 0, + JoyXAxisInv, + JoyXAxisPos, + JoyXAxisNeg, + JoyYAxis, + JoyYAxisInv, + JoyYAxisPos, + JoyYAxisNeg, + JoyZAxis, + JoyZAxisInv, + JoyZAxisPos, + JoyZAxisNeg, + JoyRXAxis, + JoyRXAxisInv, + JoyRXAxisPos, + JoyRXAxisNeg, + JoyRYAxis, + JoyRYAxisInv, + JoyRYAxisPos, + JoyRYAxisNeg, + JoyRZAxis, + JoyRZAxisInv, + JoyRZAxisPos, + JoyRZAxisNeg, + JoyS1Axis, + JoyS1AxisInv, + JoyS1AxisPos, + JoyS1AxisNeg, + JoyS2Axis, + JoyS2AxisInv, + JoyS2AxisPos, + JoyS2AxisNeg, + JoyPOV0Up, + JoyPOV0Down, + JoyPOV0Left, + JoyPOV0Right, + JoyPOV1Up, + JoyPOV1Down, + JoyPOV1Left, + JoyPOV1Right, + JoyPOV2Up, + JoyPOV2Down, + JoyPOV2Left, + JoyPOV2Right, + JoyPOV3Up, + JoyPOV3Down, + JoyPOV3Left, + JoyPOV3Right, + JoyButton0, + JoyButton1, + JoyButton2, + JoyButton3, + JoyButton4, + JoyButton5, + JoyButton6, + JoyButton7, + JoyButton8, + JoyButton9, + JoyButton10, + JoyButton11, + JoyButton12, + JoyButton13, + JoyButton14, + JoyButton15, + JoyButton16, + JoyButton17, + JoyButton18, + JoyButton19, + JoyButton20, + JoyButton21, + JoyButton22, + JoyButton23, + JoyButton24, + JoyButton25, + JoyButton26, + JoyButton27, + JoyButton28, + JoyButton29, + JoyButton30, + JoyButton31 }; struct MousePartsStruct { - const char* id; - EMousePart msePart; + const char* id; + EMousePart msePart; }; struct JoyPartsStruct { - const char* id; - EJoyPart joyPart; + const char* id; + EJoyPart joyPart; }; /* @@ -229,19 +230,19 @@ struct JoyPartsStruct */ struct KeySettings { - int kbdNum; // Keyboard number (or ANY_KEYBOARD for settings that apply to all keyboards) - unsigned sensitivity; // Key sensitivity for analog controls as percentage 1-100, where 100 is extremely responsive + int kbdNum; // Keyboard number (or ANY_KEYBOARD for settings that apply to all keyboards) + unsigned sensitivity; // Key sensitivity for analog controls as percentage 1-100, where 100 is extremely responsive unsigned decaySpeed; // Decay speed as percentage 1-200 of on speed - - /* - * Creates a KeySettings with default settings - */ - KeySettings() - { - kbdNum = ANY_KEYBOARD; - sensitivity = DEFAULT_KEY_SENSITIVITY; - decaySpeed = DEFAULT_KEY_DECAYSPEED; - } + + /* + * Creates a KeySettings with default settings + */ + KeySettings() + { + kbdNum = ANY_KEYBOARD; + sensitivity = DEFAULT_KEY_SENSITIVITY; + decaySpeed = DEFAULT_KEY_DECAYSPEED; + } }; /* @@ -249,19 +250,19 @@ struct KeySettings */ struct MouseSettings { - int mseNum; // Mouse number (or ANY_MOUSE for settings that apply to all mice) - unsigned deadZones[NUM_MOUSE_AXES]; // Axis dead zone as a percentage 0-99 of display width (X)/height (Y) or axis range (Z) + int mseNum; // Mouse number (or ANY_MOUSE for settings that apply to all mice) + unsigned deadZones[NUM_MOUSE_AXES]; // Axis dead zone as a percentage 0-99 of display width (X)/height (Y) or axis range (Z) - /* - * Creates a MouseSettings with default settings - */ - MouseSettings() - { - mseNum = ANY_MOUSE; - deadZones[AXIS_X] = DEFAULT_MSE_DEADZONE; - deadZones[AXIS_Y] = DEFAULT_MSE_DEADZONE; - deadZones[AXIS_Z] = 0; - } + /* + * Creates a MouseSettings with default settings + */ + MouseSettings() + { + mseNum = ANY_MOUSE; + deadZones[AXIS_X] = DEFAULT_MSE_DEADZONE; + deadZones[AXIS_Y] = DEFAULT_MSE_DEADZONE; + deadZones[AXIS_Z] = 0; + } }; /* @@ -269,51 +270,51 @@ struct MouseSettings */ struct JoySettings { - int joyNum; // Joystick number (or ANY_JOYSTICK for settings that apply to all joysticks) - int axisMinVals[NUM_JOY_AXES]; // Axis min raw value (default -32768) - int axisOffVals[NUM_JOY_AXES]; // Axis center/off value (default 0) - int axisMaxVals[NUM_JOY_AXES]; // Axis max raw value (default 32767) - unsigned deadZones[NUM_JOY_AXES]; // Axis dead zone as a percentage 0-99 of axis positive/negative ranges - unsigned saturations[NUM_JOY_AXES]; // Axis saturation as a percentage 1-200 of axis positive/negative ranges + int joyNum; // Joystick number (or ANY_JOYSTICK for settings that apply to all joysticks) + int axisMinVals[NUM_JOY_AXES]; // Axis min raw value (default -32768) + int axisOffVals[NUM_JOY_AXES]; // Axis center/off value (default 0) + int axisMaxVals[NUM_JOY_AXES]; // Axis max raw value (default 32767) + unsigned deadZones[NUM_JOY_AXES]; // Axis dead zone as a percentage 0-99 of axis positive/negative ranges + unsigned saturations[NUM_JOY_AXES]; // Axis saturation as a percentage 1-200 of axis positive/negative ranges - /* - * Creates a JoySettings with default settings - */ - JoySettings() - { - joyNum = ANY_JOYSTICK; - for (int axisNum = 0; axisNum < NUM_JOY_AXES; axisNum++) - { - axisMinVals[axisNum] = DEFAULT_JOY_AXISMINVAL; - axisOffVals[axisNum] = DEFAULT_JOY_AXISOFFVAL; - axisMaxVals[axisNum] = DEFAULT_JOY_AXISMAXVAL; - deadZones[axisNum] = DEFAULT_JOY_DEADZONE; - saturations[axisNum] = DEFAULT_JOY_SATURATION; - } - } + /* + * Creates a JoySettings with default settings + */ + JoySettings() + { + joyNum = ANY_JOYSTICK; + for (int axisNum = 0; axisNum < NUM_JOY_AXES; axisNum++) + { + axisMinVals[axisNum] = DEFAULT_JOY_AXISMINVAL; + axisOffVals[axisNum] = DEFAULT_JOY_AXISOFFVAL; + axisMaxVals[axisNum] = DEFAULT_JOY_AXISMAXVAL; + deadZones[axisNum] = DEFAULT_JOY_DEADZONE; + saturations[axisNum] = DEFAULT_JOY_SATURATION; + } + } }; struct KeyDetails { - char name[MAX_NAME_LENGTH + 1]; // Keyboard name (if available) + char name[MAX_NAME_LENGTH + 1]; // Keyboard name (if available) }; struct MouseDetails { - char name[MAX_NAME_LENGTH + 1]; // Mouse name (if available) - bool isAbsolute; // True if uses absolute positions (ie lightgun) + char name[MAX_NAME_LENGTH + 1]; // Mouse name (if available) + bool isAbsolute; // True if uses absolute positions (ie lightgun) }; struct JoyDetails { - char name[MAX_NAME_LENGTH + 1]; // Joystick name (if available) - int numAxes; // Total number of axes on joystick - int numPOVs; // Total number of POV hat controllers on joystick - int numButtons; // Total number of buttons on joystick - bool hasFFeedback; // True if joystick supports force feedback - bool hasAxis[NUM_JOY_AXES]; // Flags to indicate which axes available on joystick - char axisName[NUM_JOY_AXES][MAX_NAME_LENGTH + 1]; // Axis names (if available) - bool axisHasFF[NUM_JOY_AXES]; // Flags to indicate which axes are force feedback enabled + char name[MAX_NAME_LENGTH + 1]; // Joystick name (if available) + int numAxes; // Total number of axes on joystick + int numPOVs; // Total number of POV hat controllers on joystick + int numButtons; // Total number of buttons on joystick + bool hasFFeedback; // True if joystick supports force feedback + bool hasAxis[NUM_JOY_AXES]; // Flags to indicate which axes available on joystick + char axisName[NUM_JOY_AXES][MAX_NAME_LENGTH + 1]; // Axis names (if available) + bool axisHasFF[NUM_JOY_AXES]; // Flags to indicate which axes are force feedback enabled }; /* @@ -321,685 +322,693 @@ struct JoyDetails * mice and joysticks. */ class CInputSystem -{ +{ private: - // Array of valid key names - static const char *s_validKeyNames[]; + // Array of valid key names + static const char *s_validKeyNames[]; - // Lookup table for translating mouse mapping strings to their respective mouse parts - static MousePartsStruct s_mseParts[]; + // Lookup table for translating mouse mapping strings to their respective mouse parts + static MousePartsStruct s_mseParts[]; - // Lookup table for translating joystick mapping strings to their respective joystick parts - static JoyPartsStruct s_joyParts[]; + // Lookup table for translating joystick mapping strings to their respective joystick parts + static JoyPartsStruct s_joyParts[]; - // Ids and names of axes - static const char *s_axisIds[]; - static const char *s_axisNames[]; + // Ids and names of axes + static const char *s_axisIds[]; + static const char *s_axisNames[]; - // Number of keyboards, mice and joysticks - int m_numKbds; - int m_numMice; - int m_numJoys; + // Number of keyboards, mice and joysticks + int m_numKbds; + int m_numMice; + int m_numJoys; - // Cached input sources - CInputSource **m_anyKeySources; - CInputSource **m_anyMseSources; - CInputSource **m_anyJoySources; - CInputSource ***m_keySources; - CInputSource ***m_mseSources; - CInputSource ***m_joySources; - - // Default key, mouse and joystick settings - KeySettings m_defKeySettings; - MouseSettings m_defMseSettings; - JoySettings m_defJoySettings; + // Cached input sources + CInputSource **m_anyKeySources; + CInputSource **m_anyMseSources; + CInputSource **m_anyJoySources; + CInputSource ***m_keySources; + CInputSource ***m_mseSources; + CInputSource ***m_joySources; + + // Default key, mouse and joystick settings + KeySettings m_defKeySettings; + MouseSettings m_defMseSettings; + JoySettings m_defJoySettings; - // Current key, mouse and joystick settings for attached keyboards, mice and joysticks - vector m_keySettings; - vector m_mseSettings; - vector m_joySettings; + // Current key, mouse and joystick settings for attached keyboards, mice and joysticks + vector m_keySettings; + vector m_mseSettings; + vector m_joySettings; - // Empty input source - CMultiInputSource *m_emptySource; + // Empty input source + CMultiInputSource *m_emptySource; - // - // Helper methods - // + // + // Helper methods + // - /* - * Creates source cache. - */ - void CreateSourceCache(); + /* + * Creates source cache. + */ + void CreateSourceCache(); - /* - * Clears cache of all sources and optionally deletes cache itself. - */ - void ClearSourceCache(bool deleteCache = false); + /* + * Clears cache of all sources and optionally deletes cache itself. + */ + void ClearSourceCache(bool deleteCache = false); - /* - * Releases a source from the cache. - */ - void ReleaseSource(CInputSource *&source); - - /* - * Returns a key source for the given keyboard number (or all keyboards if ANY_KEYBOARD supplied) and key index. - * Will check the source cache first and if not found will create the source with CreateAnyKeySource or CreateKeySource. - */ - CInputSource *GetKeySource(int kbdNum, int keyIndex); + /* + * Releases a source from the cache. + */ + void ReleaseSource(CInputSource *&source); + + /* + * Returns a key source for the given keyboard number (or all keyboards if ANY_KEYBOARD supplied) and key index. + * Will check the source cache first and if not found will create the source with CreateAnyKeySource or CreateKeySource. + */ + CInputSource *GetKeySource(int kbdNum, int keyIndex); - /* - * Returns a mouse source for the given mouse number (or all mice if ANY_MOUSE supplied) and mouse index. - * Will check the source cache first and if not found will create the source with CreateAnyMouseSource or CreateMouseSource. - */ - CInputSource *GetMouseSource(int mseNum, EMousePart msePart); + /* + * Returns a mouse source for the given mouse number (or all mice if ANY_MOUSE supplied) and mouse index. + * Will check the source cache first and if not found will create the source with CreateAnyMouseSource or CreateMouseSource. + */ + CInputSource *GetMouseSource(int mseNum, EMousePart msePart); - /* - * Returns a joystick source for the given joystick number (or all joysticks if ANY_JOYSTICK supplied) and joystick index. - * Will check the source cache first and if not found will create the source with CreateAnyJoySource or CreateJoySource. - */ - CInputSource *GetJoySource(int joyNum, EJoyPart joyPart); + /* + * Returns a joystick source for the given joystick number (or all joysticks if ANY_JOYSTICK supplied) and joystick index. + * Will check the source cache first and if not found will create the source with CreateAnyJoySource or CreateJoySource. + */ + CInputSource *GetJoySource(int joyNum, EJoyPart joyPart); - void CheckAllSources(unsigned readFlags, bool fullAxisOnly, bool &mseCentered, vector &sources, string &mapping, vector &badSources); + void CheckAllSources(unsigned readFlags, bool fullAxisOnly, bool &mseCentered, vector &sources, string &mapping, vector &badSources); - /* - * Finds any currently activated key sources for the given keyboard number (or all keyboards if ANY_KEYBOARD supplied) - * and adds them to the sources vector, aswell as constructing the corresponding mapping(s) in the given string. - * If fullAxisOnly is true, then only sources that represent a full axis range (eg MouseXAxis) are considered. - */ - void CheckKeySources(int kbdNum, bool fullAxisOnly, vector &sources, string &mapping, vector &badSources); + /* + * Finds any currently activated key sources for the given keyboard number (or all keyboards if ANY_KEYBOARD supplied) + * and adds them to the sources vector, aswell as constructing the corresponding mapping(s) in the given string. + * If fullAxisOnly is true, then only sources that represent a full axis range (eg MouseXAxis) are considered. + */ + void CheckKeySources(int kbdNum, bool fullAxisOnly, vector &sources, string &mapping, vector &badSources); - /* - * Finds any currently activated mouse sources for the given mouse number (or all mice if ANY_MOUSE supplied) - * and adds them to the sources vector, aswell as constructing the corresponding mapping(s) in the given string. - * If fullAxisOnly is true, then only sources that represent a full axis range (eg MouseXAxis) are considered. - */ - void CheckMouseSources(int mseNum, bool fullAxisOnly, bool mseCentered, vector &sources, string &mapping, vector &badSources); + /* + * Finds any currently activated mouse sources for the given mouse number (or all mice if ANY_MOUSE supplied) + * and adds them to the sources vector, aswell as constructing the corresponding mapping(s) in the given string. + * If fullAxisOnly is true, then only sources that represent a full axis range (eg MouseXAxis) are considered. + */ + void CheckMouseSources(int mseNum, bool fullAxisOnly, bool mseCentered, vector &sources, string &mapping, vector &badSources); - /* - * Finds any currently activated joystick sources for the given joystick number (or all joysticks if ANY_JOYSTICK supplied) - * and adds them to the sources vector, aswell as constructing the corresponding mapping(s) in the given string. - * If fullAxisOnly is true, then only sources that represent a full axis range (eg MouseXAxis) are considered. - */ - void CheckJoySources(int joyNum, bool fullAxisOnly, vector &sources, string &mapping, vector &badSources); + /* + * Finds any currently activated joystick sources for the given joystick number (or all joysticks if ANY_JOYSTICK supplied) + * and adds them to the sources vector, aswell as constructing the corresponding mapping(s) in the given string. + * If fullAxisOnly is true, then only sources that represent a full axis range (eg MouseXAxis) are considered. + */ + void CheckJoySources(int joyNum, bool fullAxisOnly, vector &sources, string &mapping, vector &badSources); - bool ParseInt(string str, int &num); + bool ParseInt(string str, int &num); - string IntToString(int num); + string IntToString(int num); - bool EqualsIgnoreCase(string str1, const char *str2); + bool EqualsIgnoreCase(string str1, const char *str2); - bool StartsWithIgnoreCase(string str1, const char *str2); + bool StartsWithIgnoreCase(string str1, const char *str2); - /* - * Returns true if the given string represents a valid key name. - */ - bool IsValidKeyName(string str); + /* + * Returns true if the given string represents a valid key name. + */ + bool IsValidKeyName(string str); - /* - * Returns the EMousePart with the given mapping name or MouseUnknown if not found. - */ - EMousePart LookupMousePart(string str); + /* + * Returns the EMousePart with the given mapping name or MouseUnknown if not found. + */ + EMousePart LookupMousePart(string str); - /* - * Returns the mapping name for the given EMousePart. - */ - const char *LookupName(EMousePart msePart); + /* + * Returns the mapping name for the given EMousePart. + */ + const char *LookupName(EMousePart msePart); - /* - * Returns the EJoyPart with the given mapping name or JoyUnknown if not found. - */ - EJoyPart LookupJoyPart(string str); + /* + * Returns the EJoyPart with the given mapping name or JoyUnknown if not found. + */ + EJoyPart LookupJoyPart(string str); - /* - * Returns the mapping name for the given EJoyPart. - */ - const char *LookupName(EJoyPart joyPart); + /* + * Returns the mapping name for the given EJoyPart. + */ + const char *LookupName(EJoyPart joyPart); - size_t ParseDevMapping(string str, const char *devType, int &devNum); + size_t ParseDevMapping(string str, const char *devType, int &devNum); - /* - * Parses the given mapping string, possibly representing more than one mapping, and returns an input source for it or NULL if the - * mapping is invalid. - * If fullAxisOnly is true, then only mappings that represent a full axis range (eg MouseXAxis) are parsed. - */ - CInputSource* ParseMultiSource(string str, bool fullAxisOnly, bool isOr); + /* + * Parses the given mapping string, possibly representing more than one mapping, and returns an input source for it or NULL if the + * mapping is invalid. + * If fullAxisOnly is true, then only mappings that represent a full axis range (eg MouseXAxis) are parsed. + */ + CInputSource* ParseMultiSource(string str, bool fullAxisOnly, bool isOr); - /* - * Parses the given single mapping string and returns an input source for it, or NULL if non exists. - */ - CInputSource* ParseSingleSource(string str); + /* + * Parses the given single mapping string and returns an input source for it, or NULL if non exists. + */ + CInputSource* ParseSingleSource(string str); - /* - * Prints the given key settings to stdout. - */ - void PrintKeySettings(int kbdNum, KeySettings *settings); + /* + * Prints the given key settings to stdout. + */ + void PrintKeySettings(int kbdNum, KeySettings *settings); - /* - * Reads key settings from an INI file for the given keyboard number, or common settings if ANY_KEYBOARD specified. - * Returns NULL if no relevant settings were found in the INI file. - */ - KeySettings *ReadKeySettings(CINIFile *ini, const char *section, int kbdNum); + /* + * Reads key settings from an INI file for the given keyboard number, or common settings if ANY_KEYBOARD specified. + * Returns NULL if no relevant settings were found in the INI file. + */ + KeySettings *LoadKeySettings(const Util::Config::Node &config, int kbdNum); + KeySettings *ReadKeySettings(CINIFile *ini, const char *section, int kbdNum); - /* - * Writes the given key settings to an INI file, only writing out settings that are different to their defaults. - */ - void WriteKeySettings(CINIFile *ini, const char *section, KeySettings *settings); + /* + * Writes the given key settings to an INI file, only writing out settings that are different to their defaults. + */ + void StoreKeySettings(Util::Config::Node *config, KeySettings *settings); + void WriteKeySettings(CINIFile *ini, const char *section, KeySettings *settings); - /* - * Prints the given mouse settings to stdout. - */ - void PrintMouseSettings(int mseNum, MouseSettings *settings); + /* + * Prints the given mouse settings to stdout. + */ + void PrintMouseSettings(int mseNum, MouseSettings *settings); - /* - * Reads mouse settings from an INI file for the given mouse number, or common settings if ANY_MOUSE specified. - * Returns NULL if no relevant settings were found in the INI file. - */ - MouseSettings *ReadMouseSettings(CINIFile *ini, const char *section, int mseNum); + /* + * Loads mouse settings from a config object for the given mouse number, or common settings if ANY_MOUSE specified. + * Returns NULL if no relevant settings were found in the config object. + */ + MouseSettings *LoadMouseSettings(const Util::Config::Node &config, int mseNum); + MouseSettings *ReadMouseSettings(CINIFile *ini, const char *section, int mseNum); - /* - * Writes the given mouse settings to an INI file, only writing out settings that are different to their defaults. - */ - void WriteMouseSettings(CINIFile *ini, const char *section, MouseSettings *settings); - - /* - * Prints the given joystick settings to stdout. - */ - void PrintJoySettings(int joyNum, JoySettings *settings); + /* + * Stores the given mouse settings to a config object, only storing settings that differ from their defaults. + */ + void StoreMouseSettings(Util::Config::Node *config, MouseSettings *settings); + void WriteMouseSettings(CINIFile *ini, const char *section, MouseSettings *settings); + + /* + * Prints the given joystick settings to stdout. + */ + void PrintJoySettings(int joyNum, JoySettings *settings); - /* - * Reads joystick settings from an INI file for the given joystick number, or common settings if ANY_JOYSTICK specified. - * Returns NULL if no relevant settings were found in the INI file. - */ - JoySettings *ReadJoySettings(CINIFile *ini, const char *section, int joyNum); + /* + * Loads joystick settings from a config object for the given joystick number, or common settings if ANY_JOYSTICK specified. + * Returns NULL if no relevant settings were found in the config object. + */ + JoySettings *LoadJoySettings(const Util::Config::Node &config, int joyNum); + JoySettings *ReadJoySettings(CINIFile *ini, const char *section, int joyNum); - /* - * Writes the given joystick settings to an INI file, only writing out settings that are different to their defaults. - */ - void WriteJoySettings(CINIFile *ini, const char *section, JoySettings *settings); + /* + * Stores the given joystick settings to a config object, only storing settings that differ from their defaults. + */ + void StoreJoySettings(Util::Config::Node *config, JoySettings *settings); + void WriteJoySettings(CINIFile *ini, const char *section, JoySettings *settings); protected: - // Current display geometry - unsigned m_dispX; - unsigned m_dispY; - unsigned m_dispW; - unsigned m_dispH; + // Current display geometry + unsigned m_dispX; + unsigned m_dispY; + unsigned m_dispW; + unsigned m_dispH; - // Flag to indicate if system has grabbed mouse - bool m_grabMouse; + // Flag to indicate if system has grabbed mouse + bool m_grabMouse; - /* - * Constructs an input system with the given name. - */ - CInputSystem(const char *systemName); + /* + * Constructs an input system with the given name. + */ + CInputSystem(const char *systemName); - /* - * Returns true if the given EMousePart is an axis. - */ - bool IsAxis(EMousePart msePart); + /* + * Returns true if the given EMousePart is an axis. + */ + bool IsAxis(EMousePart msePart); - /* - * Returns true if the given EMousePart represents a full axis, eg MouseXAxis or MouseXAxisInv. - */ - bool IsFullAxis(EMousePart msePart); + /* + * Returns true if the given EMousePart represents a full axis, eg MouseXAxis or MouseXAxisInv. + */ + bool IsFullAxis(EMousePart msePart); - /* - * Returns true if the EMousePart represents an axis and sets axisPart and axisDir as follows: - * axisNum will be the axis number (AXIS_X, AXIS_Y or AXIS_Z) - * axisDir will be AXIS_FULL, AXIS_INVERTED, AXIS_POS or AXIS_POS depending on whether the axis has the full range, has - * the full range but inverted, is negative only, or is positive only. - */ - bool GetAxisDetails(EMousePart msePart, int &axisNum, int &axisDir); + /* + * Returns true if the EMousePart represents an axis and sets axisPart and axisDir as follows: + * axisNum will be the axis number (AXIS_X, AXIS_Y or AXIS_Z) + * axisDir will be AXIS_FULL, AXIS_INVERTED, AXIS_POS or AXIS_POS depending on whether the axis has the full range, has + * the full range but inverted, is negative only, or is positive only. + */ + bool GetAxisDetails(EMousePart msePart, int &axisNum, int &axisDir); - /* - * Returns true if the given EMousePart represets a button, eg MouseButtonLeft. - */ - bool IsButton(EMousePart msePart); + /* + * Returns true if the given EMousePart represets a button, eg MouseButtonLeft. + */ + bool IsButton(EMousePart msePart); - /* - * Returns the button number (indexed from 0) of the given EMousePart if it is a button, or -1 otherwise. - */ - int GetButtonNumber(EMousePart msePart); + /* + * Returns the button number (indexed from 0) of the given EMousePart if it is a button, or -1 otherwise. + */ + int GetButtonNumber(EMousePart msePart); - /* - * Returns the EMousePart that represents the axis component for the given axis number (AXIS_X, AXIS_Y or AXIS_Z) and direction - * (AXIS_FULL, AXIS_INVERTED, AXIS_POS or AXIS_POS), or MouseUnknown otherwise. - */ - EMousePart GetMouseAxis(int axisNum, int axisDir); + /* + * Returns the EMousePart that represents the axis component for the given axis number (AXIS_X, AXIS_Y or AXIS_Z) and direction + * (AXIS_FULL, AXIS_INVERTED, AXIS_POS or AXIS_POS), or MouseUnknown otherwise. + */ + EMousePart GetMouseAxis(int axisNum, int axisDir); - /* - * Returns the EMousePart that represents the mouse button with the given number (0-4), or MouseUnknown otherwise. - */ - EMousePart GetMouseButton(int butNum); + /* + * Returns the EMousePart that represents the mouse button with the given number (0-4), or MouseUnknown otherwise. + */ + EMousePart GetMouseButton(int butNum); - /* - * Returns true if the given EJoyPart is an axis. - */ - bool IsAxis(EJoyPart joyPart); + /* + * Returns true if the given EJoyPart is an axis. + */ + bool IsAxis(EJoyPart joyPart); - /* - * Returns true if the given EJoyPart represents a full axis, eg JoyXAxis. - */ - bool IsFullAxis(EJoyPart joyPart); + /* + * Returns true if the given EJoyPart represents a full axis, eg JoyXAxis. + */ + bool IsFullAxis(EJoyPart joyPart); - /* - * Returns true if the given EJoyPart represents a slider axis, eg JoyS1Axis. - */ - bool IsSliderAxis(EJoyPart joyPart); + /* + * Returns true if the given EJoyPart represents a slider axis, eg JoyS1Axis. + */ + bool IsSliderAxis(EJoyPart joyPart); - /* - * Returns true if joystick part represents an axis and sets axisPart and axisDir as follows: - * axisNum will be the axis number (AXIS_X, AXIS_Y, AXIS_Z, AXIS_RX, AXIS_RY or AXIS_RZ) - * axisDir is AXIS_FULL, AXIS_INVERTED, AXIS_POS or AXIS_POS depending on whether the axis has the full range, has - * the full range but inverted, is negative only, or is positive only. - */ - bool GetAxisDetails(EJoyPart joyPart, int &axisNum, int &axisDir); + /* + * Returns true if joystick part represents an axis and sets axisPart and axisDir as follows: + * axisNum will be the axis number (AXIS_X, AXIS_Y, AXIS_Z, AXIS_RX, AXIS_RY or AXIS_RZ) + * axisDir is AXIS_FULL, AXIS_INVERTED, AXIS_POS or AXIS_POS depending on whether the axis has the full range, has + * the full range but inverted, is negative only, or is positive only. + */ + bool GetAxisDetails(EJoyPart joyPart, int &axisNum, int &axisDir); - /* - * Returns true if the given EJoyPart represents a POV hat direction, eg JoyPOV0Left. - */ - bool IsPOV(EJoyPart joyPart); + /* + * Returns true if the given EJoyPart represents a POV hat direction, eg JoyPOV0Left. + */ + bool IsPOV(EJoyPart joyPart); - /* - * Returns true if the EJoyPart represents a POV hat direction and sets povNum and povDir as follows: - * povNum will be the POV hat number 0-4, - * povDir will be POV_UP, POV_DOWN, POV_LEFT or POV_RIGHT. - */ - bool GetPOVDetails(EJoyPart joyPart, int &povNum, int &povDir); + /* + * Returns true if the EJoyPart represents a POV hat direction and sets povNum and povDir as follows: + * povNum will be the POV hat number 0-4, + * povDir will be POV_UP, POV_DOWN, POV_LEFT or POV_RIGHT. + */ + bool GetPOVDetails(EJoyPart joyPart, int &povNum, int &povDir); - /* - * Returns true if the given EJoyPart is a button - */ - bool IsButton(EJoyPart joyPart); + /* + * Returns true if the given EJoyPart is a button + */ + bool IsButton(EJoyPart joyPart); - /* - * Returns the button number (indexed from 0) of the given EJoyPart if it is a button, or -1 otherwise. - */ - int GetButtonNumber(EJoyPart joyPart); + /* + * Returns the button number (indexed from 0) of the given EJoyPart if it is a button, or -1 otherwise. + */ + int GetButtonNumber(EJoyPart joyPart); - /* - * Returns the EJoyPart that represents the axis component for the given axis number (AXIS_X, AXIS_Y, AXIS_Z, AXIS_RX, AXIS_RY or AXIS_RZ) and - * direction (AXIS_FULL, AXIS_INVERTED, AXIS_POS or AXIS_POS), or JoyUnknown otherwise. - */ - EJoyPart GetJoyAxis(int axisNum, int axisDir); + /* + * Returns the EJoyPart that represents the axis component for the given axis number (AXIS_X, AXIS_Y, AXIS_Z, AXIS_RX, AXIS_RY or AXIS_RZ) and + * direction (AXIS_FULL, AXIS_INVERTED, AXIS_POS or AXIS_POS), or JoyUnknown otherwise. + */ + EJoyPart GetJoyAxis(int axisNum, int axisDir); - /* - * Returns the EJoyPart that represents the POV hot direction for the given POV number (0-4) and direction (POV_UP, POV_DOWN, - * POV_LEFT or POV_RIGHT), JoyUnknown otherwise. - */ - EJoyPart GetJoyPOV(int povNum, int povDir); + /* + * Returns the EJoyPart that represents the POV hot direction for the given POV number (0-4) and direction (POV_UP, POV_DOWN, + * POV_LEFT or POV_RIGHT), JoyUnknown otherwise. + */ + EJoyPart GetJoyPOV(int povNum, int povDir); - /* - * Returns the EJoyPart that represents the joystick button with the given number (0-31), or JoyUnknown otherwise. - */ - EJoyPart GetJoyButton(int butNum); + /* + * Returns the EJoyPart that represents the joystick button with the given number (0-31), or JoyUnknown otherwise. + */ + EJoyPart GetJoyButton(int butNum); - // - // Abstract methods subclass must implement (ie system-specific code) - // + // + // Abstract methods subclass must implement (ie system-specific code) + // - virtual bool InitializeSystem() = 0; + virtual bool InitializeSystem() = 0; - /* - * Returns the system-specific key index that represents the given key name. - */ - virtual int GetKeyIndex(const char *keyName) = 0; + /* + * Returns the system-specific key index that represents the given key name. + */ + virtual int GetKeyIndex(const char *keyName) = 0; - /* - * Returns the key name of the given system-specific integer key index. - */ - virtual const char *GetKeyName(int keyIndex) = 0; + /* + * Returns the key name of the given system-specific integer key index. + */ + virtual const char *GetKeyName(int keyIndex) = 0; - /* - * Returns true if for the given keyboard the key with the system-specific key index is currently pressed. - */ - virtual bool IsKeyPressed(int kbdNum, int keyIndex) = 0; + /* + * Returns true if for the given keyboard the key with the system-specific key index is currently pressed. + */ + virtual bool IsKeyPressed(int kbdNum, int keyIndex) = 0; - /* - * Returns the current axis value for the given mouse and axis number (AXIS_X, AXIS_Y or AXIS_Z). - */ - virtual int GetMouseAxisValue(int mseNum, int axisNum) = 0; + /* + * Returns the current axis value for the given mouse and axis number (AXIS_X, AXIS_Y or AXIS_Z). + */ + virtual int GetMouseAxisValue(int mseNum, int axisNum) = 0; - /* - * Returns the current direction (-1, 0 or 1) the Z-axis (wheel) is moving in for the given mouse. - */ - virtual int GetMouseWheelDir(int mseNum) = 0; + /* + * Returns the current direction (-1, 0 or 1) the Z-axis (wheel) is moving in for the given mouse. + */ + virtual int GetMouseWheelDir(int mseNum) = 0; - /* - * Returns true if for the given mouse the button with the given number is currently pressed. - */ - virtual bool IsMouseButPressed(int mseNum, int butNum) = 0; + /* + * Returns true if for the given mouse the button with the given number is currently pressed. + */ + virtual bool IsMouseButPressed(int mseNum, int butNum) = 0; - /* - * Returns the current axis value for the given joystick and axis number (AXIS_X, AXIS_Y, AXIS_Z, AXIS_RX, AXIS_RY or AXIS_RZ). - */ - virtual int GetJoyAxisValue(int joyNum, int axisNum) = 0; + /* + * Returns the current axis value for the given joystick and axis number (AXIS_X, AXIS_Y, AXIS_Z, AXIS_RX, AXIS_RY or AXIS_RZ). + */ + virtual int GetJoyAxisValue(int joyNum, int axisNum) = 0; - /* - * Returns true if for the given joystick the POV-hat controller with the given number is pointing in a particular direction (POV_UP, POV_DOWN, - * POV_LEFT or POV_RIGHT) - */ - virtual bool IsJoyPOVInDir(int joyNum, int povNum, int povDir) = 0; + /* + * Returns true if for the given joystick the POV-hat controller with the given number is pointing in a particular direction (POV_UP, POV_DOWN, + * POV_LEFT or POV_RIGHT) + */ + virtual bool IsJoyPOVInDir(int joyNum, int povNum, int povDir) = 0; - /* - * Returns true if for the given joystick the button with the given number is currently pressed. - */ - virtual bool IsJoyButPressed(int joyNum, int butNum) = 0; + /* + * Returns true if for the given joystick the button with the given number is currently pressed. + */ + virtual bool IsJoyButPressed(int joyNum, int butNum) = 0; - /* - * Processes the given force feedback command for the given joystick and axis number. - */ - virtual bool ProcessForceFeedbackCmd(int joyNum, int axisNum, ForceFeedbackCmd ffCmd) = 0; + /* + * Processes the given force feedback command for the given joystick and axis number. + */ + virtual bool ProcessForceFeedbackCmd(int joyNum, int axisNum, ForceFeedbackCmd ffCmd) = 0; - // - // Virtual methods subclass can override if required - // + // + // Virtual methods subclass can override if required + // - /* - * Returns true if the mouse is currently centered in the display during configuration. - */ - virtual bool ConfigMouseCentered(); + /* + * Returns true if the mouse is currently centered in the display during configuration. + */ + virtual bool ConfigMouseCentered(); - /* - * Creates an input source combining all keyboards for the given key index. - */ - virtual CInputSource *CreateAnyKeySource(int keyIndex); + /* + * Creates an input source combining all keyboards for the given key index. + */ + virtual CInputSource *CreateAnyKeySource(int keyIndex); - /* - * Creates an input source combining all mice for the given EMousePart. - */ - virtual CInputSource *CreateAnyMouseSource(EMousePart msePart); + /* + * Creates an input source combining all mice for the given EMousePart. + */ + virtual CInputSource *CreateAnyMouseSource(EMousePart msePart); - /* - * Creates an input source combining all joysticks for the given EJoyPart. - */ - virtual CInputSource *CreateAnyJoySource(EJoyPart joyPart); - - /* - * Creates an input source for the given keyboard number and key index. - */ - virtual CInputSource *CreateKeySource(int kbdNum, int keyIndex); + /* + * Creates an input source combining all joysticks for the given EJoyPart. + */ + virtual CInputSource *CreateAnyJoySource(EJoyPart joyPart); + + /* + * Creates an input source for the given keyboard number and key index. + */ + virtual CInputSource *CreateKeySource(int kbdNum, int keyIndex); - /* - * Creates an input source for the given mouse number and EMousePart. - */ - virtual CInputSource *CreateMouseSource(int mseNum, EMousePart msePart); + /* + * Creates an input source for the given mouse number and EMousePart. + */ + virtual CInputSource *CreateMouseSource(int mseNum, EMousePart msePart); - /* - * Creates an input source for the given joystick number and EJoyPart. - */ - virtual CInputSource *CreateJoySource(int joyNum, EJoyPart joyPart); + /* + * Creates an input source for the given joystick number and EJoyPart. + */ + virtual CInputSource *CreateJoySource(int joyNum, EJoyPart joyPart); public: #ifdef DEBUG - static unsigned totalSrcsAcquired; - static unsigned totalSrcsReleased; + static unsigned totalSrcsAcquired; + static unsigned totalSrcsReleased; #endif - static const char *GetDefaultAxisName(int axisNum); + static const char *GetDefaultAxisName(int axisNum); - // Name of this input system - const char *name; + // Name of this input system + const char *name; - virtual ~CInputSystem(); + virtual ~CInputSystem(); - /* - * Initializes the input system. Must be called before any other methods are used. - * Returns false if unable to initialize the system. - */ - bool Initialize(); + /* + * Initializes the input system. Must be called before any other methods are used. + * Returns false if unable to initialize the system. + */ + bool Initialize(); - /* - * Sets the current display geometry so that mouse movements can be scaled properly. - */ - void SetDisplayGeom(unsigned dispX, unsigned dispY, unsigned dispW, unsigned dispH); + /* + * Sets the current display geometry so that mouse movements can be scaled properly. + */ + void SetDisplayGeom(unsigned dispX, unsigned dispY, unsigned dispW, unsigned dispH); - /* - * Returns the number of attached keyboards (or 0 if the system cannot handle keyboards at all or ANY_KEYBOARD if the system cannot - * handle multiple keyboards). - */ - virtual int GetNumKeyboards() = 0; - - /* - * Returns the number of attached mice (or 0 if the system cannot handle mice at all or ANY_MOUSE if the system cannot handle - * multiple mice). - */ - virtual int GetNumMice() = 0; - - /* - * Returns number of attached joysticks (or 0 if the system cannot handle joysticks at all or ANY_JOYSTICK if the system cannot - * handle multiple joysticks). - */ - virtual int GetNumJoysticks() = 0; + /* + * Returns the number of attached keyboards (or 0 if the system cannot handle keyboards at all or ANY_KEYBOARD if the system cannot + * handle multiple keyboards). + */ + virtual int GetNumKeyboards() = 0; + + /* + * Returns the number of attached mice (or 0 if the system cannot handle mice at all or ANY_MOUSE if the system cannot handle + * multiple mice). + */ + virtual int GetNumMice() = 0; + + /* + * Returns number of attached joysticks (or 0 if the system cannot handle joysticks at all or ANY_JOYSTICK if the system cannot + * handle multiple joysticks). + */ + virtual int GetNumJoysticks() = 0; - /* - * Returns details about the keyboard with the given number, or NULL if it does not exist. - */ - virtual const KeyDetails *GetKeyDetails(int kbdNum) = 0; + /* + * Returns details about the keyboard with the given number, or NULL if it does not exist. + */ + virtual const KeyDetails *GetKeyDetails(int kbdNum) = 0; - /* - * Returns details about the mouse with the given number, or NULL if it does not exist. - */ - virtual const MouseDetails *GetMouseDetails(int mseNum) = 0; + /* + * Returns details about the mouse with the given number, or NULL if it does not exist. + */ + virtual const MouseDetails *GetMouseDetails(int mseNum) = 0; - /* - * Returns details about the joystick with the given number, or NULL if it does not exist. - */ - virtual const JoyDetails *GetJoyDetails(int joyNum) = 0; + /* + * Returns details about the joystick with the given number, or NULL if it does not exist. + */ + virtual const JoyDetails *GetJoyDetails(int joyNum) = 0; - /* - * Clears all keyboard, mouse and joystick settings. + /* + * Clears all keyboard, mouse and joystick settings. */ - void ClearSettings(); + void ClearSettings(); - /* - * Prints current keyboard, mouse and joystick settings to stdout. - */ - void PrintSettings(); + /* + * Prints current keyboard, mouse and joystick settings to stdout. + */ + void PrintSettings(); - /* - * Reads all keyboard, mouse and joystick settings (and any additional system-specific additional settings) from the given INI file. - */ - virtual void ReadFromINIFile(CINIFile *ini, const char *section); + /* + * Reads all keyboard, mouse and joystick settings (and any additional system-specific additional settings) from the given config object. + */ + virtual void LoadFromConfig(const Util::Config::Node &config); + virtual void ReadFromINIFile(CINIFile *ini, const char *section); - /* - * Writes all keyboard, mouse and joystick settings (and any additional system-specific settings) to the given INI file. - */ - virtual void WriteToINIFile(CINIFile *ini, const char *section); + /* + * Stores all keyboard, mouse and joystick settings (and any additional system-specific settings) to the given config object. + */ + virtual void StoreToConfig(Util::Config::Node *config); + virtual void WriteToINIFile(CINIFile *ini, const char *section); - /* - * Returns the current key settings for given keyboard number, or common settings if ANY_KEYBOARD specified. - * If no settings are found and useDefault is false, NULL is returned. If useDefault is true then default settings are returned. - */ - KeySettings *GetKeySettings(int kbdNum, bool useDefault); + /* + * Returns the current key settings for given keyboard number, or common settings if ANY_KEYBOARD specified. + * If no settings are found and useDefault is false, NULL is returned. If useDefault is true then default settings are returned. + */ + KeySettings *GetKeySettings(int kbdNum, bool useDefault); - /* - * Returns the current mouse settings for given mouse number, or common settings if ANY_MOUSE specified. - * If no settings are found and useDefault is false, NULL is returned. If useDefault is true then default settings are returned. - */ - MouseSettings *GetMouseSettings(int mseNum, bool useDefault); + /* + * Returns the current mouse settings for given mouse number, or common settings if ANY_MOUSE specified. + * If no settings are found and useDefault is false, NULL is returned. If useDefault is true then default settings are returned. + */ + MouseSettings *GetMouseSettings(int mseNum, bool useDefault); - /* - * Returns the current joystick settings for given joystick number, or common settings if ANY_JOYSTICK specified. - * If no settings are found and useDefault is false, NULL is returned. If useDefault is true then default settings are returned. - */ - JoySettings *GetJoySettings(int joyNum, bool useDefault); - - /* - * Returns the input source for the given mapping, or NULL if mapping is not valid. - */ - CInputSource* ParseSource(const char *mapping, bool fullAxisOnly = false); + /* + * Returns the current joystick settings for given joystick number, or common settings if ANY_JOYSTICK specified. + * If no settings are found and useDefault is false, NULL is returned. If useDefault is true then default settings are returned. + */ + JoySettings *GetJoySettings(int joyNum, bool useDefault); + + /* + * Returns the input source for the given mapping, or NULL if mapping is not valid. + */ + CInputSource* ParseSource(const char *mapping, bool fullAxisOnly = false); - /* - * Waits for any input from the user and once received copies a mapping configuration representing the input (eg KEY_A or JOY1_AXIS_POS) - * into the given buffer. - * Returns true if input was successfully received or false if the user activated the given escape mapping or closed the window. - * readFlags specifies which types of inputs (keyboards, mice, joysticks) are to be read and whether to merge the inputs to a common - * mapping, eg return MOUSE_XAXIS rather than MOUSE3_XAXIS. - * If fullAxisOnly is true, then only mappings representing a full axis are returned, eg JOY1_XAXIS is allowed but not JOY1_XAXIS_POS. - */ - bool ReadMapping(char *buffer, unsigned bufSize, bool fullAxisOnly = false, unsigned readFlags = READ_ALL, const char *escapeMapping = "KEY_ESCAPE"); + /* + * Waits for any input from the user and once received copies a mapping configuration representing the input (eg KEY_A or JOY1_AXIS_POS) + * into the given buffer. + * Returns true if input was successfully received or false if the user activated the given escape mapping or closed the window. + * readFlags specifies which types of inputs (keyboards, mice, joysticks) are to be read and whether to merge the inputs to a common + * mapping, eg return MOUSE_XAXIS rather than MOUSE3_XAXIS. + * If fullAxisOnly is true, then only mappings representing a full axis are returned, eg JOY1_XAXIS is allowed but not JOY1_XAXIS_POS. + */ + bool ReadMapping(char *buffer, unsigned bufSize, bool fullAxisOnly = false, unsigned readFlags = READ_ALL, const char *escapeMapping = "KEY_ESCAPE"); - /* - * Updates the current state of the input system (called by CInputs.Poll). - */ - virtual bool Poll() = 0; + /* + * Updates the current state of the input system (called by CInputs.Poll). + */ + virtual bool Poll() = 0; - virtual void GrabMouse(); + virtual void GrabMouse(); - virtual void UngrabMouse(); + virtual void UngrabMouse(); - /* - * Sets the mouse visibility (some systems may choose to ignore this). - */ - virtual void SetMouseVisibility(bool visible) = 0; + /* + * Sets the mouse visibility (some systems may choose to ignore this). + */ + virtual void SetMouseVisibility(bool visible) = 0; - virtual bool SendForceFeedbackCmd(int joyNum, int axisNum, ForceFeedbackCmd ffCmd); + virtual bool SendForceFeedbackCmd(int joyNum, int axisNum, ForceFeedbackCmd ffCmd); - bool DetectJoystickAxis(unsigned joyNum, unsigned &axisNum, const char *escapeMapping = "KEY_ESCAPE", const char *confirmMapping = "KEY_RETURN"); + bool DetectJoystickAxis(unsigned joyNum, unsigned &axisNum, const char *escapeMapping = "KEY_ESCAPE", const char *confirmMapping = "KEY_RETURN"); - bool CalibrateJoystickAxis(unsigned joyNum, unsigned axisNum, const char *escapeMapping = "KEY_ESCAPE", const char *confirmMapping = "KEY_RETURN"); + bool CalibrateJoystickAxis(unsigned joyNum, unsigned axisNum, const char *escapeMapping = "KEY_ESCAPE", const char *confirmMapping = "KEY_RETURN"); - void PrintDevices(); + void PrintDevices(); - // - // Nested Classes - // + // + // Nested Classes + // - /* - * Input source for a key on a keyboard. - */ - class CKeyInputSource : public CInputSource - { - private: - CInputSystem *m_system; // Parent input system - int m_kbdNum; // Keyboard number - int m_keyIndex; // Key index - int m_incr; // Key increment for analog values - int m_decr; // Key decrement for analog values - int m_val; // Current analog key value - int m_maxVal; // Maximum analog key value + /* + * Input source for a key on a keyboard. + */ + class CKeyInputSource : public CInputSource + { + private: + CInputSystem *m_system; // Parent input system + int m_kbdNum; // Keyboard number + int m_keyIndex; // Key index + int m_incr; // Key increment for analog values + int m_decr; // Key decrement for analog values + int m_val; // Current analog key value + int m_maxVal; // Maximum analog key value - public: - CKeyInputSource(CInputSystem *system, int kbdNum, int keyIndex, unsigned sensitivity, unsigned decaySpeed); + public: + CKeyInputSource(CInputSystem *system, int kbdNum, int keyIndex, unsigned sensitivity, unsigned decaySpeed); - bool GetValueAsSwitch(bool &val); + bool GetValueAsSwitch(bool &val); - bool GetValueAsAnalog(int &val, int minVal, int offVal, int maxVal); - }; + bool GetValueAsAnalog(int &val, int minVal, int offVal, int maxVal); + }; - /* - * Input source for the X- or Y-axis of a mouse. - */ - class CMseAxisInputSource : public CInputSource - { - private: - CInputSystem *m_system; // Parent input system - int m_mseNum; // Mouse number - int m_axisNum; // Axis number (AXIS_X, AXIS_Y or AXIS_Z) - int m_axisDir; // Axis direction (AXIS_FULL, AXIS_INVERTED, AXIS_POSITIVE or AXIS_NEGATIVE) - int m_deadPixels; // Size in pixels of dead zone in centre of axis + /* + * Input source for the X- or Y-axis of a mouse. + */ + class CMseAxisInputSource : public CInputSource + { + private: + CInputSystem *m_system; // Parent input system + int m_mseNum; // Mouse number + int m_axisNum; // Axis number (AXIS_X, AXIS_Y or AXIS_Z) + int m_axisDir; // Axis direction (AXIS_FULL, AXIS_INVERTED, AXIS_POSITIVE or AXIS_NEGATIVE) + int m_deadPixels; // Size in pixels of dead zone in centre of axis - /* - * Scales the mouse axis value to the given range. - */ - int ScaleAxisValue(int minVal, int offVal, int maxVal); + /* + * Scales the mouse axis value to the given range. + */ + int ScaleAxisValue(int minVal, int offVal, int maxVal); - public: - CMseAxisInputSource(CInputSystem *system, int mseNum, int axisNum, int axisDir, unsigned deadZone); + public: + CMseAxisInputSource(CInputSystem *system, int mseNum, int axisNum, int axisDir, unsigned deadZone); - bool GetValueAsSwitch(bool &val); + bool GetValueAsSwitch(bool &val); - bool GetValueAsAnalog(int &val, int minVal, int offVal, int maxVal); - }; + bool GetValueAsAnalog(int &val, int minVal, int offVal, int maxVal); + }; - /* - * Input source for the button of a mouse. - */ - class CMseButInputSource : public CInputSource - { - private: - CInputSystem *m_system; // Parent input system - int m_mseNum; // Mouse number - int m_butNum; // Button number + /* + * Input source for the button of a mouse. + */ + class CMseButInputSource : public CInputSource + { + private: + CInputSystem *m_system; // Parent input system + int m_mseNum; // Mouse number + int m_butNum; // Button number - public: - CMseButInputSource(CInputSystem *system, int mseNum, int butNum); + public: + CMseButInputSource(CInputSystem *system, int mseNum, int butNum); - bool GetValueAsSwitch(bool &val); + bool GetValueAsSwitch(bool &val); - bool GetValueAsAnalog(int &val, int minVal, int offVal, int maxVal); - }; + bool GetValueAsAnalog(int &val, int minVal, int offVal, int maxVal); + }; - /* - * Input source for the axis of a joystick. - */ - class CJoyAxisInputSource : public CInputSource - { - private: - CInputSystem *m_system; // Parent input system - int m_joyNum; // Joystick number - int m_axisNum; // Axis number (AXIS_X, AXIS_Y, AXIS_Z, AXIS_RX, AXIS_RY or AXIS_RZ) - int m_axisDir; // Axis direction (AXIS_FULL, AXIS_INVERTED, AXIS_POSITIVE or AXIS_NEGATIVE) - int m_axisMinVal; // Axis min raw value (default -32768) - int m_axisOffVal; // Axis center/off raw value (default 0) - int m_axisMaxVal; // Axis max raw value (default 32767) - bool m_axisInverted; // True if axis max raw value less than axis min raw value - int m_posDZone; // Dead zone for positive range (0-99%) - int m_negDZone; // Dead zone for negative range (0-99%) - int m_posSat; // Saturation for positive range (1-100%) - int m_negSat; // Saturation for negative range (1-100%) + /* + * Input source for the axis of a joystick. + */ + class CJoyAxisInputSource : public CInputSource + { + private: + CInputSystem *m_system; // Parent input system + int m_joyNum; // Joystick number + int m_axisNum; // Axis number (AXIS_X, AXIS_Y, AXIS_Z, AXIS_RX, AXIS_RY or AXIS_RZ) + int m_axisDir; // Axis direction (AXIS_FULL, AXIS_INVERTED, AXIS_POSITIVE or AXIS_NEGATIVE) + int m_axisMinVal; // Axis min raw value (default -32768) + int m_axisOffVal; // Axis center/off raw value (default 0) + int m_axisMaxVal; // Axis max raw value (default 32767) + bool m_axisInverted; // True if axis max raw value less than axis min raw value + int m_posDZone; // Dead zone for positive range (0-99%) + int m_negDZone; // Dead zone for negative range (0-99%) + int m_posSat; // Saturation for positive range (1-100%) + int m_negSat; // Saturation for negative range (1-100%) - /* - * Scales the joystick axis value to the given range. - */ - int ScaleAxisValue(int minVal, int offVal, int maxVal); + /* + * Scales the joystick axis value to the given range. + */ + int ScaleAxisValue(int minVal, int offVal, int maxVal); - public: - CJoyAxisInputSource(CInputSystem *system, int joyNum, int axisNum, int axisDir, int axisMinVal, int axisOffVal, int axisMaxVal, - unsigned deadZone, unsigned saturation); + public: + CJoyAxisInputSource(CInputSystem *system, int joyNum, int axisNum, int axisDir, int axisMinVal, int axisOffVal, int axisMaxVal, + unsigned deadZone, unsigned saturation); - bool GetValueAsSwitch(bool &val); + bool GetValueAsSwitch(bool &val); - bool GetValueAsAnalog(int &val, int minVal, int offVal, int maxVal); + bool GetValueAsAnalog(int &val, int minVal, int offVal, int maxVal); - bool SendForceFeedbackCmd(ForceFeedbackCmd ffCmd); - }; + bool SendForceFeedbackCmd(ForceFeedbackCmd ffCmd); + }; - /* - * Input source for a particular direction of a POV hat controller of a joystick. - */ - class CJoyPOVInputSource : public CInputSource - { - private: - CInputSystem *m_system; // Parent input system - int m_joyNum; // Joystick number - int m_povNum; // POV hat number - int m_povDir; // POV hat direction (POV_UP, POV_LEFT, POV_RIGHT, POV_DOWN) + /* + * Input source for a particular direction of a POV hat controller of a joystick. + */ + class CJoyPOVInputSource : public CInputSource + { + private: + CInputSystem *m_system; // Parent input system + int m_joyNum; // Joystick number + int m_povNum; // POV hat number + int m_povDir; // POV hat direction (POV_UP, POV_LEFT, POV_RIGHT, POV_DOWN) - public: - CJoyPOVInputSource(CInputSystem *system, int joyNum, int povNum, int povDir); + public: + CJoyPOVInputSource(CInputSystem *system, int joyNum, int povNum, int povDir); - bool GetValueAsSwitch(bool &val); + bool GetValueAsSwitch(bool &val); - bool GetValueAsAnalog(int &val, int minVal, int offVal, int maxVal); - }; + bool GetValueAsAnalog(int &val, int minVal, int offVal, int maxVal); + }; - /* - * Input source for the button of a joystick. - */ - class CJoyButInputSource : public CInputSource - { - private: - CInputSystem *m_system; // Parent input system - int m_joyNum; // Joystick number - int m_butNum; // Button number + /* + * Input source for the button of a joystick. + */ + class CJoyButInputSource : public CInputSource + { + private: + CInputSystem *m_system; // Parent input system + int m_joyNum; // Joystick number + int m_butNum; // Button number - public: - CJoyButInputSource(CInputSystem *system, int joyNum, int butNum); + public: + CJoyButInputSource(CInputSystem *system, int joyNum, int butNum); - bool GetValueAsSwitch(bool &val); + bool GetValueAsSwitch(bool &val); - bool GetValueAsAnalog(int &val, int minVal, int offVal, int maxVal); - }; + bool GetValueAsAnalog(int &val, int minVal, int offVal, int maxVal); + }; }; -#endif // INCLUDED_INPUTSYSTEM_H +#endif // INCLUDED_INPUTSYSTEM_H diff --git a/Src/Inputs/Inputs.cpp b/Src/Inputs/Inputs.cpp index da3f1a1..1f57688 100644 --- a/Src/Inputs/Inputs.cpp +++ b/Src/Inputs/Inputs.cpp @@ -27,6 +27,7 @@ */ #include "Supermodel.h" +#include "Game.h" #include #include @@ -34,240 +35,241 @@ #include using namespace std; -CInputs::CInputs(CInputSystem *system) : m_system(system) +CInputs::CInputs(CInputSystem *system) + : m_system(system) { // UI controls are hard coded here, everything else is initialized to NONE so that it can be loaded from // the config file. // UI Controls - uiExit = AddSwitchInput("UIExit", "Exit UI", GAME_INPUT_UI, "KEY_ESCAPE"); - uiReset = AddSwitchInput("UIReset", "Reset", GAME_INPUT_UI, "KEY_ALT+KEY_R"); - uiPause = AddSwitchInput("UIPause", "Pause", GAME_INPUT_UI, "KEY_ALT+KEY_P"); - uiFullScreen = AddSwitchInput("UIFullScreen", "Toggle Fullscreen", GAME_INPUT_UI, "KEY_ALT+KEY_RETURN"); - uiSaveState = AddSwitchInput("UISaveState", "Save State", GAME_INPUT_UI, "KEY_F5"); - uiChangeSlot = AddSwitchInput("UIChangeSlot", "Change Save Slot", GAME_INPUT_UI, "KEY_F6"); - uiLoadState = AddSwitchInput("UILoadState", "Load State", GAME_INPUT_UI, "KEY_F7"); - uiMusicVolUp = AddSwitchInput("UIMusicVolUp", "Increase Music Volume", GAME_INPUT_UI, "KEY_F10"); - uiMusicVolDown = AddSwitchInput("UIMusicVolDown", "Decrease Music Volume", GAME_INPUT_UI, "KEY_F9"); - uiSoundVolUp = AddSwitchInput("UISoundVolUp", "Increase Sound Volume", GAME_INPUT_UI, "KEY_F12"); - uiSoundVolDown = AddSwitchInput("UISoundVolDown", "Decrease Sound Volume", GAME_INPUT_UI, "KEY_F11"); - uiClearNVRAM = AddSwitchInput("UIClearNVRAM", "Clear NVRAM", GAME_INPUT_UI, "KEY_ALT+KEY_N"); - uiSelectCrosshairs = AddSwitchInput("UISelectCrosshairs", "Select Crosshairs", GAME_INPUT_UI, "KEY_ALT+KEY_I"); - uiToggleFrLimit = AddSwitchInput("UIToggleFrameLimit", "Toggle Frame Limiting", GAME_INPUT_UI, "KEY_ALT+KEY_T"); - uiDumpInpState = AddSwitchInput("UIDumpInputState", "Dump Input State", GAME_INPUT_UI, "KEY_ALT+KEY_U"); - uiDumpTimings = AddSwitchInput("UIDumpTimings", "Dump Frame Timings", GAME_INPUT_UI, "KEY_ALT+KEY_O"); + uiExit = AddSwitchInput("UIExit", "Exit UI", Game::INPUT_UI, "KEY_ESCAPE"); + uiReset = AddSwitchInput("UIReset", "Reset", Game::INPUT_UI, "KEY_ALT+KEY_R"); + uiPause = AddSwitchInput("UIPause", "Pause", Game::INPUT_UI, "KEY_ALT+KEY_P"); + uiFullScreen = AddSwitchInput("UIFullScreen", "Toggle Fullscreen", Game::INPUT_UI, "KEY_ALT+KEY_RETURN"); + uiSaveState = AddSwitchInput("UISaveState", "Save State", Game::INPUT_UI, "KEY_F5"); + uiChangeSlot = AddSwitchInput("UIChangeSlot", "Change Save Slot", Game::INPUT_UI, "KEY_F6"); + uiLoadState = AddSwitchInput("UILoadState", "Load State", Game::INPUT_UI, "KEY_F7"); + uiMusicVolUp = AddSwitchInput("UIMusicVolUp", "Increase Music Volume", Game::INPUT_UI, "KEY_F10"); + uiMusicVolDown = AddSwitchInput("UIMusicVolDown", "Decrease Music Volume", Game::INPUT_UI, "KEY_F9"); + uiSoundVolUp = AddSwitchInput("UISoundVolUp", "Increase Sound Volume", Game::INPUT_UI, "KEY_F12"); + uiSoundVolDown = AddSwitchInput("UISoundVolDown", "Decrease Sound Volume", Game::INPUT_UI, "KEY_F11"); + uiClearNVRAM = AddSwitchInput("UIClearNVRAM", "Clear NVRAM", Game::INPUT_UI, "KEY_ALT+KEY_N"); + uiSelectCrosshairs = AddSwitchInput("UISelectCrosshairs", "Select Crosshairs", Game::INPUT_UI, "KEY_ALT+KEY_I"); + uiToggleFrLimit = AddSwitchInput("UIToggleFrameLimit", "Toggle Frame Limiting", Game::INPUT_UI, "KEY_ALT+KEY_T"); + uiDumpInpState = AddSwitchInput("UIDumpInputState", "Dump Input State", Game::INPUT_UI, "KEY_ALT+KEY_U"); + uiDumpTimings = AddSwitchInput("UIDumpTimings", "Dump Frame Timings", Game::INPUT_UI, "KEY_ALT+KEY_O"); #ifdef SUPERMODEL_DEBUGGER - uiEnterDebugger = AddSwitchInput("UIEnterDebugger", "Enter Debugger", GAME_INPUT_UI, "KEY_ALT+KEY_B"); + uiEnterDebugger = AddSwitchInput("UIEnterDebugger", "Enter Debugger", Game::INPUT_UI, "KEY_ALT+KEY_B"); #endif // Common Controls - start[0] = AddSwitchInput("Start1", "P1 Start", GAME_INPUT_COMMON, "NONE"); - start[1] = AddSwitchInput("Start2", "P2 Start", GAME_INPUT_COMMON, "NONE"); - coin[0] = AddSwitchInput("Coin1", "P1 Coin", GAME_INPUT_COMMON, "NONE"); - coin[1] = AddSwitchInput("Coin2", "P2 Coin", GAME_INPUT_COMMON, "NONE"); - service[0] = AddSwitchInput("ServiceA", "Service A", GAME_INPUT_COMMON, "NONE"); - service[1] = AddSwitchInput("ServiceB", "Service B", GAME_INPUT_COMMON, "NONE"); - test[0] = AddSwitchInput("TestA", "Test A", GAME_INPUT_COMMON, "NONE"); - test[1] = AddSwitchInput("TestB", "Test B", GAME_INPUT_COMMON, "NONE"); + start[0] = AddSwitchInput("Start1", "P1 Start", Game::INPUT_COMMON, "NONE"); + start[1] = AddSwitchInput("Start2", "P2 Start", Game::INPUT_COMMON, "NONE"); + coin[0] = AddSwitchInput("Coin1", "P1 Coin", Game::INPUT_COMMON, "NONE"); + coin[1] = AddSwitchInput("Coin2", "P2 Coin", Game::INPUT_COMMON, "NONE"); + service[0] = AddSwitchInput("ServiceA", "Service A", Game::INPUT_COMMON, "NONE"); + service[1] = AddSwitchInput("ServiceB", "Service B", Game::INPUT_COMMON, "NONE"); + test[0] = AddSwitchInput("TestA", "Test A", Game::INPUT_COMMON, "NONE"); + test[1] = AddSwitchInput("TestB", "Test B", Game::INPUT_COMMON, "NONE"); // 4-Way Joysticks - up[0] = AddSwitchInput("JoyUp", "P1 Joystick Up", GAME_INPUT_JOYSTICK1, "NONE"); - down[0] = AddSwitchInput("JoyDown", "P1 Joystick Down", GAME_INPUT_JOYSTICK1, "NONE"); - left[0] = AddSwitchInput("JoyLeft", "P1 Joystick Left", GAME_INPUT_JOYSTICK1, "NONE"); - right[0] = AddSwitchInput("JoyRight", "P1 Joystick Right", GAME_INPUT_JOYSTICK1, "NONE"); - up[1] = AddSwitchInput("JoyUp2", "P2 Joystick Up", GAME_INPUT_JOYSTICK2, "NONE"); - down[1] = AddSwitchInput("JoyDown2", "P2 Joystick Down", GAME_INPUT_JOYSTICK2, "NONE"); - left[1] = AddSwitchInput("JoyLeft2", "P2 Joystick Left", GAME_INPUT_JOYSTICK2, "NONE"); - right[1] = AddSwitchInput("JoyRight2", "P2 Joystick Right", GAME_INPUT_JOYSTICK2, "NONE"); + up[0] = AddSwitchInput("JoyUp", "P1 Joystick Up", Game::INPUT_JOYSTICK1, "NONE"); + down[0] = AddSwitchInput("JoyDown", "P1 Joystick Down", Game::INPUT_JOYSTICK1, "NONE"); + left[0] = AddSwitchInput("JoyLeft", "P1 Joystick Left", Game::INPUT_JOYSTICK1, "NONE"); + right[0] = AddSwitchInput("JoyRight", "P1 Joystick Right", Game::INPUT_JOYSTICK1, "NONE"); + up[1] = AddSwitchInput("JoyUp2", "P2 Joystick Up", Game::INPUT_JOYSTICK2, "NONE"); + down[1] = AddSwitchInput("JoyDown2", "P2 Joystick Down", Game::INPUT_JOYSTICK2, "NONE"); + left[1] = AddSwitchInput("JoyLeft2", "P2 Joystick Left", Game::INPUT_JOYSTICK2, "NONE"); + right[1] = AddSwitchInput("JoyRight2", "P2 Joystick Right", Game::INPUT_JOYSTICK2, "NONE"); // Fighting Game Buttons - punch[0] = AddSwitchInput("Punch", "P1 Punch", GAME_INPUT_FIGHTING, "NONE"); - kick[0] = AddSwitchInput("Kick", "P1 Kick", GAME_INPUT_FIGHTING, "NONE"); - guard[0] = AddSwitchInput("Guard", "P1 Guard", GAME_INPUT_FIGHTING, "NONE"); - escape[0] = AddSwitchInput("Escape", "P1 Escape", GAME_INPUT_FIGHTING, "NONE"); - punch[1] = AddSwitchInput("Punch2", "P2 Punch", GAME_INPUT_FIGHTING, "NONE"); - kick[1] = AddSwitchInput("Kick2", "P2 Kick", GAME_INPUT_FIGHTING, "NONE"); - guard[1] = AddSwitchInput("Guard2", "P2 Guard", GAME_INPUT_FIGHTING, "NONE"); - escape[1] = AddSwitchInput("Escape2", "P2 Escape", GAME_INPUT_FIGHTING, "NONE"); + punch[0] = AddSwitchInput("Punch", "P1 Punch", Game::INPUT_FIGHTING, "NONE"); + kick[0] = AddSwitchInput("Kick", "P1 Kick", Game::INPUT_FIGHTING, "NONE"); + guard[0] = AddSwitchInput("Guard", "P1 Guard", Game::INPUT_FIGHTING, "NONE"); + escape[0] = AddSwitchInput("Escape", "P1 Escape", Game::INPUT_FIGHTING, "NONE"); + punch[1] = AddSwitchInput("Punch2", "P2 Punch", Game::INPUT_FIGHTING, "NONE"); + kick[1] = AddSwitchInput("Kick2", "P2 Kick", Game::INPUT_FIGHTING, "NONE"); + guard[1] = AddSwitchInput("Guard2", "P2 Guard", Game::INPUT_FIGHTING, "NONE"); + escape[1] = AddSwitchInput("Escape2", "P2 Escape", Game::INPUT_FIGHTING, "NONE"); // Spikeout Buttons - shift = AddSwitchInput("Shift", "Shift", GAME_INPUT_SPIKEOUT, "NONE"); - beat = AddSwitchInput("Beat", "Beat", GAME_INPUT_SPIKEOUT, "NONE"); - charge = AddSwitchInput("Charge", "Charge",GAME_INPUT_SPIKEOUT, "NONE"); - jump = AddSwitchInput("Jump", "Jump", GAME_INPUT_SPIKEOUT, "NONE"); + shift = AddSwitchInput("Shift", "Shift", Game::INPUT_SPIKEOUT, "NONE"); + beat = AddSwitchInput("Beat", "Beat", Game::INPUT_SPIKEOUT, "NONE"); + charge = AddSwitchInput("Charge", "Charge",Game::INPUT_SPIKEOUT, "NONE"); + jump = AddSwitchInput("Jump", "Jump", Game::INPUT_SPIKEOUT, "NONE"); // Virtua Striker Buttons - shortPass[0] = AddSwitchInput("ShortPass", "P1 Short Pass", GAME_INPUT_SOCCER, "NONE"); - longPass[0] = AddSwitchInput("LongPass", "P1 Long Pass", GAME_INPUT_SOCCER, "NONE"); - shoot[0] = AddSwitchInput("Shoot", "P1 Shoot", GAME_INPUT_SOCCER, "NONE"); - shortPass[1] = AddSwitchInput("ShortPass2", "P2 Short Pass", GAME_INPUT_SOCCER, "NONE"); - longPass[1] = AddSwitchInput("LongPass2", "P2 Long Pass", GAME_INPUT_SOCCER, "NONE"); - shoot[1] = AddSwitchInput("Shoot2", "P2 Shoot", GAME_INPUT_SOCCER, "NONE"); + shortPass[0] = AddSwitchInput("ShortPass", "P1 Short Pass", Game::INPUT_SOCCER, "NONE"); + longPass[0] = AddSwitchInput("LongPass", "P1 Long Pass", Game::INPUT_SOCCER, "NONE"); + shoot[0] = AddSwitchInput("Shoot", "P1 Shoot", Game::INPUT_SOCCER, "NONE"); + shortPass[1] = AddSwitchInput("ShortPass2", "P2 Short Pass", Game::INPUT_SOCCER, "NONE"); + longPass[1] = AddSwitchInput("LongPass2", "P2 Long Pass", Game::INPUT_SOCCER, "NONE"); + shoot[1] = AddSwitchInput("Shoot2", "P2 Shoot", Game::INPUT_SOCCER, "NONE"); // Racing Game Steering Controls - CAnalogInput *steeringLeft = AddAnalogInput("SteeringLeft", "Steer Left", GAME_INPUT_VEHICLE, "NONE"); - CAnalogInput *steeringRight = AddAnalogInput("SteeringRight", "Steer Right", GAME_INPUT_VEHICLE, "NONE"); + CAnalogInput *steeringLeft = AddAnalogInput("SteeringLeft", "Steer Left", Game::INPUT_VEHICLE, "NONE"); + CAnalogInput *steeringRight = AddAnalogInput("SteeringRight", "Steer Right", Game::INPUT_VEHICLE, "NONE"); - steering = AddAxisInput ("Steering", "Full Steering", GAME_INPUT_VEHICLE, "NONE", steeringLeft, steeringRight); - accelerator = AddAnalogInput("Accelerator", "Accelerator Pedal", GAME_INPUT_VEHICLE, "NONE"); - brake = AddAnalogInput("Brake", "Brake Pedal/Front Brake", GAME_INPUT_VEHICLE, "NONE"); - gearShiftUp = AddSwitchInput("GearShiftUp", "Shift Up", GAME_INPUT_VEHICLE, "NONE"); - gearShiftDown = AddSwitchInput("GearShiftDown", "Shift Down", GAME_INPUT_VEHICLE, "NONE"); + steering = AddAxisInput ("Steering", "Full Steering", Game::INPUT_VEHICLE, "NONE", steeringLeft, steeringRight); + accelerator = AddAnalogInput("Accelerator", "Accelerator Pedal", Game::INPUT_VEHICLE, "NONE"); + brake = AddAnalogInput("Brake", "Brake Pedal/Front Brake", Game::INPUT_VEHICLE, "NONE"); + gearShiftUp = AddSwitchInput("GearShiftUp", "Shift Up", Game::INPUT_VEHICLE, "NONE"); + gearShiftDown = AddSwitchInput("GearShiftDown", "Shift Down", Game::INPUT_VEHICLE, "NONE"); // Racing Game Gear Shift - CSwitchInput *shift1 = AddSwitchInput("GearShift1", "Shift 1", GAME_INPUT_SHIFT4, "NONE"); - CSwitchInput *shift2 = AddSwitchInput("GearShift2", "Shift 2", GAME_INPUT_SHIFT4, "NONE"); - CSwitchInput *shift3 = AddSwitchInput("GearShift3", "Shift 3", GAME_INPUT_SHIFT4, "NONE"); - CSwitchInput *shift4 = AddSwitchInput("GearShift4", "Shift 4", GAME_INPUT_SHIFT4, "NONE"); - CSwitchInput *shiftN = AddSwitchInput("GearShiftN", "Shift Neutral", GAME_INPUT_SHIFT4, "NONE"); + CSwitchInput *shift1 = AddSwitchInput("GearShift1", "Shift 1", Game::INPUT_SHIFT4, "NONE"); + CSwitchInput *shift2 = AddSwitchInput("GearShift2", "Shift 2", Game::INPUT_SHIFT4, "NONE"); + CSwitchInput *shift3 = AddSwitchInput("GearShift3", "Shift 3", Game::INPUT_SHIFT4, "NONE"); + CSwitchInput *shift4 = AddSwitchInput("GearShift4", "Shift 4", Game::INPUT_SHIFT4, "NONE"); + CSwitchInput *shiftN = AddSwitchInput("GearShiftN", "Shift Neutral", Game::INPUT_SHIFT4, "NONE"); - gearShift4 = AddGearShift4Input("GearShift", "Gear Shift", GAME_INPUT_SHIFT4, shift1, shift2, shift3, shift4, shiftN, gearShiftUp, gearShiftDown); + gearShift4 = AddGearShift4Input("GearShift", "Gear Shift", Game::INPUT_SHIFT4, shift1, shift2, shift3, shift4, shiftN, gearShiftUp, gearShiftDown); // Racing Game 4 VR View Buttons - vr[0] = AddSwitchInput("VR1", "VR1", GAME_INPUT_VR4, "NONE"); - vr[1] = AddSwitchInput("VR2", "VR2", GAME_INPUT_VR4, "NONE"); - vr[2] = AddSwitchInput("VR3", "VR3", GAME_INPUT_VR4, "NONE"); - vr[3] = AddSwitchInput("VR4", "VR4", GAME_INPUT_VR4, "NONE"); + vr[0] = AddSwitchInput("VR1", "VR1", Game::INPUT_VR4, "NONE"); + vr[1] = AddSwitchInput("VR2", "VR2", Game::INPUT_VR4, "NONE"); + vr[2] = AddSwitchInput("VR3", "VR3", Game::INPUT_VR4, "NONE"); + vr[3] = AddSwitchInput("VR4", "VR4", Game::INPUT_VR4, "NONE"); // Racing Game Single View Change Button - viewChange = AddSwitchInput("ViewChange", "View Change", GAME_INPUT_VIEWCHANGE, "NONE"); + viewChange = AddSwitchInput("ViewChange", "View Change", Game::INPUT_VIEWCHANGE, "NONE"); // Racing Game Handbrake - handBrake = AddSwitchInput("HandBrake", "Hand Brake", GAME_INPUT_HANDBRAKE, "NONE"); + handBrake = AddSwitchInput("HandBrake", "Hand Brake", Game::INPUT_HANDBRAKE, "NONE"); // Harley Davidson Controls - rearBrake = AddAnalogInput("RearBrake", "Rear Brake", GAME_INPUT_HARLEY, "NONE"); - musicSelect = AddSwitchInput("MusicSelect", "Music Selection", GAME_INPUT_HARLEY, "NONE"); + rearBrake = AddAnalogInput("RearBrake", "Rear Brake", Game::INPUT_HARLEY, "NONE"); + musicSelect = AddSwitchInput("MusicSelect", "Music Selection", Game::INPUT_HARLEY, "NONE"); // Virtual On Controls - twinJoyTurnLeft = AddSwitchInput("TwinJoyTurnLeft", "Macro Turn Left", GAME_INPUT_TWIN_JOYSTICKS, "NONE"); - twinJoyTurnRight = AddSwitchInput("TwinJoyTurnRight", "Macro Turn Right", GAME_INPUT_TWIN_JOYSTICKS, "NONE"); - twinJoyForward = AddSwitchInput("TwinJoyForward", "Macro Forward", GAME_INPUT_TWIN_JOYSTICKS, "NONE"); - twinJoyReverse = AddSwitchInput("TwinJoyReverse", "Macro Reverse", GAME_INPUT_TWIN_JOYSTICKS, "NONE"); - twinJoyStrafeLeft = AddSwitchInput("TwinJoyStrafeLeft", "Macro Strafe Left", GAME_INPUT_TWIN_JOYSTICKS, "NONE"); - twinJoyStrafeRight = AddSwitchInput("TwinJoyStrafeRight", "Macro Strafe Right", GAME_INPUT_TWIN_JOYSTICKS, "NONE"); - twinJoyJump = AddSwitchInput("TwinJoyJump", "Macro Jump", GAME_INPUT_TWIN_JOYSTICKS, "NONE"); - twinJoyCrouch = AddSwitchInput("TwinJoyCrouch", "Macro Crouch", GAME_INPUT_TWIN_JOYSTICKS, "NONE"); - twinJoyLeft1 = AddSwitchInput("TwinJoyLeft1", "Left Joystick Left", GAME_INPUT_TWIN_JOYSTICKS, "NONE"); - twinJoyLeft2 = AddSwitchInput("TwinJoyLeft2", "Right Joystick Left", GAME_INPUT_TWIN_JOYSTICKS, "NONE"); - twinJoyRight1 = AddSwitchInput("TwinJoyRight1", "Left Joystick Right", GAME_INPUT_TWIN_JOYSTICKS, "NONE"); - twinJoyRight2 = AddSwitchInput("TwinJoyRight2", "Right Joystick Right", GAME_INPUT_TWIN_JOYSTICKS, "NONE"); - twinJoyUp1 = AddSwitchInput("TwinJoyUp1", "Left Joystick Up", GAME_INPUT_TWIN_JOYSTICKS, "NONE"); - twinJoyUp2 = AddSwitchInput("TwinJoyUp2", "Right Joystick Up", GAME_INPUT_TWIN_JOYSTICKS, "NONE"); - twinJoyDown1 = AddSwitchInput("TwinJoyDown1", "Left Joystick Down", GAME_INPUT_TWIN_JOYSTICKS, "NONE"); - twinJoyDown2 = AddSwitchInput("TwinJoyDown2", "Right Joystick Down", GAME_INPUT_TWIN_JOYSTICKS, "NONE"); - twinJoyShot1 = AddSwitchInput("TwinJoyShot1", "Left Shot Trigger", GAME_INPUT_TWIN_JOYSTICKS, "NONE"); - twinJoyShot2 = AddSwitchInput("TwinJoyShot2", "Right Shot Trigger", GAME_INPUT_TWIN_JOYSTICKS, "NONE"); - twinJoyTurbo1 = AddSwitchInput("TwinJoyTurbo1", "Left Turbo", GAME_INPUT_TWIN_JOYSTICKS, "NONE"); - twinJoyTurbo2 = AddSwitchInput("TwinJoyTurbo2", "Right Turbo", GAME_INPUT_TWIN_JOYSTICKS, "NONE"); + twinJoyTurnLeft = AddSwitchInput("TwinJoyTurnLeft", "Macro Turn Left", Game::INPUT_TWIN_JOYSTICKS, "NONE"); + twinJoyTurnRight = AddSwitchInput("TwinJoyTurnRight", "Macro Turn Right", Game::INPUT_TWIN_JOYSTICKS, "NONE"); + twinJoyForward = AddSwitchInput("TwinJoyForward", "Macro Forward", Game::INPUT_TWIN_JOYSTICKS, "NONE"); + twinJoyReverse = AddSwitchInput("TwinJoyReverse", "Macro Reverse", Game::INPUT_TWIN_JOYSTICKS, "NONE"); + twinJoyStrafeLeft = AddSwitchInput("TwinJoyStrafeLeft", "Macro Strafe Left", Game::INPUT_TWIN_JOYSTICKS, "NONE"); + twinJoyStrafeRight = AddSwitchInput("TwinJoyStrafeRight", "Macro Strafe Right", Game::INPUT_TWIN_JOYSTICKS, "NONE"); + twinJoyJump = AddSwitchInput("TwinJoyJump", "Macro Jump", Game::INPUT_TWIN_JOYSTICKS, "NONE"); + twinJoyCrouch = AddSwitchInput("TwinJoyCrouch", "Macro Crouch", Game::INPUT_TWIN_JOYSTICKS, "NONE"); + twinJoyLeft1 = AddSwitchInput("TwinJoyLeft1", "Left Joystick Left", Game::INPUT_TWIN_JOYSTICKS, "NONE"); + twinJoyLeft2 = AddSwitchInput("TwinJoyLeft2", "Right Joystick Left", Game::INPUT_TWIN_JOYSTICKS, "NONE"); + twinJoyRight1 = AddSwitchInput("TwinJoyRight1", "Left Joystick Right", Game::INPUT_TWIN_JOYSTICKS, "NONE"); + twinJoyRight2 = AddSwitchInput("TwinJoyRight2", "Right Joystick Right", Game::INPUT_TWIN_JOYSTICKS, "NONE"); + twinJoyUp1 = AddSwitchInput("TwinJoyUp1", "Left Joystick Up", Game::INPUT_TWIN_JOYSTICKS, "NONE"); + twinJoyUp2 = AddSwitchInput("TwinJoyUp2", "Right Joystick Up", Game::INPUT_TWIN_JOYSTICKS, "NONE"); + twinJoyDown1 = AddSwitchInput("TwinJoyDown1", "Left Joystick Down", Game::INPUT_TWIN_JOYSTICKS, "NONE"); + twinJoyDown2 = AddSwitchInput("TwinJoyDown2", "Right Joystick Down", Game::INPUT_TWIN_JOYSTICKS, "NONE"); + twinJoyShot1 = AddSwitchInput("TwinJoyShot1", "Left Shot Trigger", Game::INPUT_TWIN_JOYSTICKS, "NONE"); + twinJoyShot2 = AddSwitchInput("TwinJoyShot2", "Right Shot Trigger", Game::INPUT_TWIN_JOYSTICKS, "NONE"); + twinJoyTurbo1 = AddSwitchInput("TwinJoyTurbo1", "Left Turbo", Game::INPUT_TWIN_JOYSTICKS, "NONE"); + twinJoyTurbo2 = AddSwitchInput("TwinJoyTurbo2", "Right Turbo", Game::INPUT_TWIN_JOYSTICKS, "NONE"); // Analog Joystick - CAnalogInput *analogJoyLeft = AddAnalogInput("AnalogJoyLeft", "Analog Left", GAME_INPUT_ANALOG_JOYSTICK, "NONE"); - CAnalogInput *analogJoyRight = AddAnalogInput("AnalogJoyRight", "Analog Right", GAME_INPUT_ANALOG_JOYSTICK, "NONE"); - CAnalogInput *analogJoyUp = AddAnalogInput("AnalogJoyUp", "Analog Up", GAME_INPUT_ANALOG_JOYSTICK, "NONE"); - CAnalogInput *analogJoyDown = AddAnalogInput("AnalogJoyDown", "Analog Down", GAME_INPUT_ANALOG_JOYSTICK, "NONE"); + CAnalogInput *analogJoyLeft = AddAnalogInput("AnalogJoyLeft", "Analog Left", Game::INPUT_ANALOG_JOYSTICK, "NONE"); + CAnalogInput *analogJoyRight = AddAnalogInput("AnalogJoyRight", "Analog Right", Game::INPUT_ANALOG_JOYSTICK, "NONE"); + CAnalogInput *analogJoyUp = AddAnalogInput("AnalogJoyUp", "Analog Up", Game::INPUT_ANALOG_JOYSTICK, "NONE"); + CAnalogInput *analogJoyDown = AddAnalogInput("AnalogJoyDown", "Analog Down", Game::INPUT_ANALOG_JOYSTICK, "NONE"); - analogJoyX = AddAxisInput ("AnalogJoyX", "Analog X-Axis", GAME_INPUT_ANALOG_JOYSTICK, "NONE", analogJoyLeft, analogJoyRight); - analogJoyY = AddAxisInput ("AnalogJoyY", "Analog Y-Axis", GAME_INPUT_ANALOG_JOYSTICK, "NONE", analogJoyUp, analogJoyDown); - analogJoyTrigger1 = AddSwitchInput("AnalogJoyTrigger", "Trigger Button 1", GAME_INPUT_ANALOG_JOYSTICK, "NONE"); - analogJoyTrigger2 = AddSwitchInput("AnalogJoyTrigger2", "Trigger Button 2", GAME_INPUT_ANALOG_JOYSTICK, "NONE"); - analogJoyEvent1 = AddSwitchInput("AnalogJoyEvent", "Event Button 1", GAME_INPUT_ANALOG_JOYSTICK, "NONE"); - analogJoyEvent2 = AddSwitchInput("AnalogJoyEvent2", "Event Button 2", GAME_INPUT_ANALOG_JOYSTICK, "NONE"); + analogJoyX = AddAxisInput ("AnalogJoyX", "Analog X-Axis", Game::INPUT_ANALOG_JOYSTICK, "NONE", analogJoyLeft, analogJoyRight); + analogJoyY = AddAxisInput ("AnalogJoyY", "Analog Y-Axis", Game::INPUT_ANALOG_JOYSTICK, "NONE", analogJoyUp, analogJoyDown); + analogJoyTrigger1 = AddSwitchInput("AnalogJoyTrigger", "Trigger Button 1", Game::INPUT_ANALOG_JOYSTICK, "NONE"); + analogJoyTrigger2 = AddSwitchInput("AnalogJoyTrigger2", "Trigger Button 2", Game::INPUT_ANALOG_JOYSTICK, "NONE"); + analogJoyEvent1 = AddSwitchInput("AnalogJoyEvent", "Event Button 1", Game::INPUT_ANALOG_JOYSTICK, "NONE"); + analogJoyEvent2 = AddSwitchInput("AnalogJoyEvent2", "Event Button 2", Game::INPUT_ANALOG_JOYSTICK, "NONE"); // Light guns - CAnalogInput *gun1Left = AddAnalogInput("GunLeft", "P1 Gun Left", GAME_INPUT_GUN1, "NONE"); - CAnalogInput *gun1Right = AddAnalogInput("GunRight", "P1 Gun Right", GAME_INPUT_GUN1, "NONE"); - CAnalogInput *gun1Up = AddAnalogInput("GunUp", "P1 Gun Up", GAME_INPUT_GUN1, "NONE"); - CAnalogInput *gun1Down = AddAnalogInput("GunDown", "P1 Gun Down", GAME_INPUT_GUN1, "NONE"); + CAnalogInput *gun1Left = AddAnalogInput("GunLeft", "P1 Gun Left", Game::INPUT_GUN1, "NONE"); + CAnalogInput *gun1Right = AddAnalogInput("GunRight", "P1 Gun Right", Game::INPUT_GUN1, "NONE"); + CAnalogInput *gun1Up = AddAnalogInput("GunUp", "P1 Gun Up", Game::INPUT_GUN1, "NONE"); + CAnalogInput *gun1Down = AddAnalogInput("GunDown", "P1 Gun Down", Game::INPUT_GUN1, "NONE"); - gunX[0] = AddAxisInput("GunX", "P1 Gun X-Axis", GAME_INPUT_GUN1, "NONE", gun1Left, gun1Right, 150, 400, 651); // normalize to [150,651] - gunY[0] = AddAxisInput("GunY", "P1 Gun Y-Axis", GAME_INPUT_GUN1, "NONE", gun1Up, gun1Down, 80, 272, 465); // normalize to [80,465] + gunX[0] = AddAxisInput("GunX", "P1 Gun X-Axis", Game::INPUT_GUN1, "NONE", gun1Left, gun1Right, 150, 400, 651); // normalize to [150,651] + gunY[0] = AddAxisInput("GunY", "P1 Gun Y-Axis", Game::INPUT_GUN1, "NONE", gun1Up, gun1Down, 80, 272, 465); // normalize to [80,465] - CSwitchInput *gun1Trigger = AddSwitchInput("Trigger", "P1 Trigger", GAME_INPUT_GUN1, "NONE"); - CSwitchInput *gun1Offscreen = AddSwitchInput("Offscreen", "P1 Point Off-screen", GAME_INPUT_GUN1, "NONE"); + CSwitchInput *gun1Trigger = AddSwitchInput("Trigger", "P1 Trigger", Game::INPUT_GUN1, "NONE"); + CSwitchInput *gun1Offscreen = AddSwitchInput("Offscreen", "P1 Point Off-screen", Game::INPUT_GUN1, "NONE"); - trigger[0] = AddTriggerInput("AutoTrigger", "P1 Auto Trigger", GAME_INPUT_GUN1, gun1Trigger, gun1Offscreen); + trigger[0] = AddTriggerInput("AutoTrigger", "P1 Auto Trigger", Game::INPUT_GUN1, gun1Trigger, gun1Offscreen); - CAnalogInput *gun2Left = AddAnalogInput("GunLeft2", "P2 Gun Left", GAME_INPUT_GUN2, "NONE"); - CAnalogInput *gun2Right = AddAnalogInput("GunRight2", "P2 Gun Right", GAME_INPUT_GUN2, "NONE"); - CAnalogInput *gun2Up = AddAnalogInput("GunUp2", "P2 Gun Up", GAME_INPUT_GUN2, "NONE"); - CAnalogInput *gun2Down = AddAnalogInput("GunDown2", "P2 Gun Down", GAME_INPUT_GUN2, "NONE"); + CAnalogInput *gun2Left = AddAnalogInput("GunLeft2", "P2 Gun Left", Game::INPUT_GUN2, "NONE"); + CAnalogInput *gun2Right = AddAnalogInput("GunRight2", "P2 Gun Right", Game::INPUT_GUN2, "NONE"); + CAnalogInput *gun2Up = AddAnalogInput("GunUp2", "P2 Gun Up", Game::INPUT_GUN2, "NONE"); + CAnalogInput *gun2Down = AddAnalogInput("GunDown2", "P2 Gun Down", Game::INPUT_GUN2, "NONE"); - gunX[1] = AddAxisInput("GunX2", "P2 Gun X-Axis", GAME_INPUT_GUN2, "NONE", gun2Left, gun2Right, 150, 400, 651); // normalize to [150,651] - gunY[1] = AddAxisInput("GunY2", "P2 Gun Y-Axis", GAME_INPUT_GUN2, "NONE", gun2Up, gun2Down, 80, 272, 465); // normalize to [80,465] + gunX[1] = AddAxisInput("GunX2", "P2 Gun X-Axis", Game::INPUT_GUN2, "NONE", gun2Left, gun2Right, 150, 400, 651); // normalize to [150,651] + gunY[1] = AddAxisInput("GunY2", "P2 Gun Y-Axis", Game::INPUT_GUN2, "NONE", gun2Up, gun2Down, 80, 272, 465); // normalize to [80,465] - CSwitchInput *gun2Trigger = AddSwitchInput("Trigger2", "P2 Trigger", GAME_INPUT_GUN2, "NONE"); - CSwitchInput *gun2Offscreen = AddSwitchInput("Offscreen2", "P2 Point Off-screen", GAME_INPUT_GUN2, "NONE"); + CSwitchInput *gun2Trigger = AddSwitchInput("Trigger2", "P2 Trigger", Game::INPUT_GUN2, "NONE"); + CSwitchInput *gun2Offscreen = AddSwitchInput("Offscreen2", "P2 Point Off-screen", Game::INPUT_GUN2, "NONE"); - trigger[1] = AddTriggerInput("AutoTrigger2", "P2 Auto Trigger", GAME_INPUT_GUN2, gun2Trigger, gun2Offscreen); + trigger[1] = AddTriggerInput("AutoTrigger2", "P2 Auto Trigger", Game::INPUT_GUN2, gun2Trigger, gun2Offscreen); // Analog guns - CAnalogInput *analogGun1Left = AddAnalogInput("AnalogGunLeft", "P1 Analog Gun Left", GAME_INPUT_ANALOG_GUN1, "NONE"); - CAnalogInput *analogGun1Right = AddAnalogInput("AnalogGunRight", "P1 Analog Gun Right", GAME_INPUT_ANALOG_GUN1, "NONE"); - CAnalogInput *analogGun1Up = AddAnalogInput("AnalogGunUp", "P1 Analog Gun Up", GAME_INPUT_ANALOG_GUN1, "NONE"); - CAnalogInput *analogGun1Down = AddAnalogInput("AnalogGunDown", "P1 Analog Gun Down", GAME_INPUT_ANALOG_GUN1, "NONE"); + CAnalogInput *analogGun1Left = AddAnalogInput("AnalogGunLeft", "P1 Analog Gun Left", Game::INPUT_ANALOG_GUN1, "NONE"); + CAnalogInput *analogGun1Right = AddAnalogInput("AnalogGunRight", "P1 Analog Gun Right", Game::INPUT_ANALOG_GUN1, "NONE"); + CAnalogInput *analogGun1Up = AddAnalogInput("AnalogGunUp", "P1 Analog Gun Up", Game::INPUT_ANALOG_GUN1, "NONE"); + CAnalogInput *analogGun1Down = AddAnalogInput("AnalogGunDown", "P1 Analog Gun Down", Game::INPUT_ANALOG_GUN1, "NONE"); - analogGunX[0] = AddAxisInput("AnalogGunX", "P1 Analog Gun X-Axis", GAME_INPUT_ANALOG_GUN1, "NONE", analogGun1Left, analogGun1Right, 0, 0x80, 0xFF); - analogGunY[0] = AddAxisInput("AnalogGunY", "P1 Analog Gun Y-Axis", GAME_INPUT_ANALOG_GUN1, "NONE", analogGun1Up, analogGun1Down, 0xFF, 0x80, 0); + analogGunX[0] = AddAxisInput("AnalogGunX", "P1 Analog Gun X-Axis", Game::INPUT_ANALOG_GUN1, "NONE", analogGun1Left, analogGun1Right, 0, 0x80, 0xFF); + analogGunY[0] = AddAxisInput("AnalogGunY", "P1 Analog Gun Y-Axis", Game::INPUT_ANALOG_GUN1, "NONE", analogGun1Up, analogGun1Down, 0xFF, 0x80, 0); - analogTriggerLeft[0] = AddSwitchInput("AnalogTriggerLeft", "P1 Analog Gun Left Trigger", GAME_INPUT_ANALOG_GUN1, "NONE"); - analogTriggerRight[0] = AddSwitchInput("AnalogTriggerRight", "P1 Analog Gun Right Trigger", GAME_INPUT_ANALOG_GUN1, "NONE"); + analogTriggerLeft[0] = AddSwitchInput("AnalogTriggerLeft", "P1 Analog Gun Left Trigger", Game::INPUT_ANALOG_GUN1, "NONE"); + analogTriggerRight[0] = AddSwitchInput("AnalogTriggerRight", "P1 Analog Gun Right Trigger", Game::INPUT_ANALOG_GUN1, "NONE"); - CAnalogInput *analogGun2Left = AddAnalogInput("AnalogGunLeft2", "P2 Analog Gun Left", GAME_INPUT_ANALOG_GUN2, "NONE"); - CAnalogInput *analogGun2Right = AddAnalogInput("AnalogGunRight2", "P2 Analog Gun Right", GAME_INPUT_ANALOG_GUN2, "NONE"); - CAnalogInput *analogGun2Up = AddAnalogInput("AnalogGunUp2", "P2 Analog Gun Up", GAME_INPUT_ANALOG_GUN2, "NONE"); - CAnalogInput *analogGun2Down = AddAnalogInput("AnalogGunDown2", "P2 Analog Gun Down", GAME_INPUT_ANALOG_GUN2, "NONE"); + CAnalogInput *analogGun2Left = AddAnalogInput("AnalogGunLeft2", "P2 Analog Gun Left", Game::INPUT_ANALOG_GUN2, "NONE"); + CAnalogInput *analogGun2Right = AddAnalogInput("AnalogGunRight2", "P2 Analog Gun Right", Game::INPUT_ANALOG_GUN2, "NONE"); + CAnalogInput *analogGun2Up = AddAnalogInput("AnalogGunUp2", "P2 Analog Gun Up", Game::INPUT_ANALOG_GUN2, "NONE"); + CAnalogInput *analogGun2Down = AddAnalogInput("AnalogGunDown2", "P2 Analog Gun Down", Game::INPUT_ANALOG_GUN2, "NONE"); - analogGunX[1] = AddAxisInput("AnalogGunX2", "P2 Analog Gun X-Axis", GAME_INPUT_ANALOG_GUN2, "NONE", analogGun2Left, analogGun2Right, 0, 0x80, 0xFF); - analogGunY[1] = AddAxisInput("AnalogGunY2", "P2 Analog Gun Y-Axis", GAME_INPUT_ANALOG_GUN2, "NONE", analogGun2Up, analogGun2Down, 0xFF, 0x80, 0); + analogGunX[1] = AddAxisInput("AnalogGunX2", "P2 Analog Gun X-Axis", Game::INPUT_ANALOG_GUN2, "NONE", analogGun2Left, analogGun2Right, 0, 0x80, 0xFF); + analogGunY[1] = AddAxisInput("AnalogGunY2", "P2 Analog Gun Y-Axis", Game::INPUT_ANALOG_GUN2, "NONE", analogGun2Up, analogGun2Down, 0xFF, 0x80, 0); - analogTriggerLeft[1] = AddSwitchInput("AnalogTriggerLeft2", "P2 Analog Gun Left Trigger", GAME_INPUT_ANALOG_GUN2, "NONE"); - analogTriggerRight[1] = AddSwitchInput("AnalogTriggerRight2", "P2 Analog Gun Right Trigger", GAME_INPUT_ANALOG_GUN2, "NONE"); + analogTriggerLeft[1] = AddSwitchInput("AnalogTriggerLeft2", "P2 Analog Gun Left Trigger", Game::INPUT_ANALOG_GUN2, "NONE"); + analogTriggerRight[1] = AddSwitchInput("AnalogTriggerRight2", "P2 Analog Gun Right Trigger", Game::INPUT_ANALOG_GUN2, "NONE"); // Ski controls - CAnalogInput *skiLeft = AddAnalogInput("SkiLeft", "Ski Champ Left", GAME_INPUT_SKI, "NONE"); - CAnalogInput *skiRight = AddAnalogInput("SkiRight", "Ski Champ Right", GAME_INPUT_SKI, "NONE"); - CAnalogInput *skiUp = AddAnalogInput("SkiUp", "Ski Champ Up", GAME_INPUT_SKI, "NONE"); - CAnalogInput *skiDown = AddAnalogInput("SkiDown", "Ski Champ Down", GAME_INPUT_SKI, "NONE"); + CAnalogInput *skiLeft = AddAnalogInput("SkiLeft", "Ski Champ Left", Game::INPUT_SKI, "NONE"); + CAnalogInput *skiRight = AddAnalogInput("SkiRight", "Ski Champ Right", Game::INPUT_SKI, "NONE"); + CAnalogInput *skiUp = AddAnalogInput("SkiUp", "Ski Champ Up", Game::INPUT_SKI, "NONE"); + CAnalogInput *skiDown = AddAnalogInput("SkiDown", "Ski Champ Down", Game::INPUT_SKI, "NONE"); - skiX = AddAxisInput ("SkiX", "Ski Champ X-Axis", GAME_INPUT_SKI, "NONE", skiLeft, skiRight, 0xFF, 0x80, 0); - skiY = AddAxisInput ("SkiY", "Ski Champ Y-Axis", GAME_INPUT_SKI, "NONE", skiUp, skiDown); - skiPollLeft = AddSwitchInput("SkiPollLeft", "Ski Champ Poll Left", GAME_INPUT_SKI, "NONE"); - skiPollRight = AddSwitchInput("SkiPollRight", "Ski Champ Poll Right", GAME_INPUT_SKI, "NONE"); - skiSelect1 = AddSwitchInput("SkiSelect1", "Ski Champ Select 1", GAME_INPUT_SKI, "NONE"); - skiSelect2 = AddSwitchInput("SkiSelect2", "Ski Champ Select 2", GAME_INPUT_SKI, "NONE"); - skiSelect3 = AddSwitchInput("SkiSelect3", "Ski Champ Select 3", GAME_INPUT_SKI, "NONE"); + skiX = AddAxisInput ("SkiX", "Ski Champ X-Axis", Game::INPUT_SKI, "NONE", skiLeft, skiRight, 0xFF, 0x80, 0); + skiY = AddAxisInput ("SkiY", "Ski Champ Y-Axis", Game::INPUT_SKI, "NONE", skiUp, skiDown); + skiPollLeft = AddSwitchInput("SkiPollLeft", "Ski Champ Poll Left", Game::INPUT_SKI, "NONE"); + skiPollRight = AddSwitchInput("SkiPollRight", "Ski Champ Poll Right", Game::INPUT_SKI, "NONE"); + skiSelect1 = AddSwitchInput("SkiSelect1", "Ski Champ Select 1", Game::INPUT_SKI, "NONE"); + skiSelect2 = AddSwitchInput("SkiSelect2", "Ski Champ Select 2", Game::INPUT_SKI, "NONE"); + skiSelect3 = AddSwitchInput("SkiSelect3", "Ski Champ Select 3", Game::INPUT_SKI, "NONE"); // Magical truck controls - CAnalogInput *magicalLeverUp1 = AddAnalogInput("MagicalLeverUp1", "P1 Magical Lever Up", GAME_INPUT_MAGTRUCK, "NONE"); - CAnalogInput *magicalLeverDown1 = AddAnalogInput("MagicalLeverDown1", "P1 Magical Lever Down", GAME_INPUT_MAGTRUCK, "NONE"); - CAnalogInput *magicalLeverUp2 = AddAnalogInput("MagicalLeverUp2", "P2 Magical Lever Up", GAME_INPUT_MAGTRUCK, "NONE"); - CAnalogInput *magicalLeverDown2 = AddAnalogInput("MagicalLeverDown2", "P2 Magical Lever Down", GAME_INPUT_MAGTRUCK, "NONE"); + CAnalogInput *magicalLeverUp1 = AddAnalogInput("MagicalLeverUp1", "P1 Magical Lever Up", Game::INPUT_MAGTRUCK, "NONE"); + CAnalogInput *magicalLeverDown1 = AddAnalogInput("MagicalLeverDown1", "P1 Magical Lever Down", Game::INPUT_MAGTRUCK, "NONE"); + CAnalogInput *magicalLeverUp2 = AddAnalogInput("MagicalLeverUp2", "P2 Magical Lever Up", Game::INPUT_MAGTRUCK, "NONE"); + CAnalogInput *magicalLeverDown2 = AddAnalogInput("MagicalLeverDown2", "P2 Magical Lever Down", Game::INPUT_MAGTRUCK, "NONE"); - magicalLever1 = AddAxisInput( "MagicalLever1", "P1 Magical Lever", GAME_INPUT_MAGTRUCK, "NONE", magicalLeverUp1, magicalLeverDown1, 0xFF, 0x80, 0); - magicalLever2 = AddAxisInput( "MagicalLever2", "P2 Magical Lever", GAME_INPUT_MAGTRUCK, "NONE", magicalLeverUp2, magicalLeverDown2, 0xFF, 0x80, 0); - magicalPedal1 = AddSwitchInput( "MagicalPedal1", "P1 Magical Pedal", GAME_INPUT_MAGTRUCK, "NONE"); - magicalPedal2 = AddSwitchInput( "MagicalPedal2", "P2 Magical Pedal", GAME_INPUT_MAGTRUCK, "NONE"); + magicalLever1 = AddAxisInput( "MagicalLever1", "P1 Magical Lever", Game::INPUT_MAGTRUCK, "NONE", magicalLeverUp1, magicalLeverDown1, 0xFF, 0x80, 0); + magicalLever2 = AddAxisInput( "MagicalLever2", "P2 Magical Lever", Game::INPUT_MAGTRUCK, "NONE", magicalLeverUp2, magicalLeverDown2, 0xFF, 0x80, 0); + magicalPedal1 = AddSwitchInput( "MagicalPedal1", "P1 Magical Pedal", Game::INPUT_MAGTRUCK, "NONE"); + magicalPedal2 = AddSwitchInput( "MagicalPedal2", "P2 Magical Pedal", Game::INPUT_MAGTRUCK, "NONE"); // Sega Bass Fishing controls - CAnalogInput *fishingRodLeft = AddAnalogInput("FishingRodLeft", "Rod Left", GAME_INPUT_FISHING, "NONE"); - CAnalogInput *fishingRodRight = AddAnalogInput("FishingRodRight", "Rod Right", GAME_INPUT_FISHING, "NONE"); - CAnalogInput *fishingRodUp = AddAnalogInput("FishingRodUp", "Rod Up", GAME_INPUT_FISHING, "NONE"); - CAnalogInput *fishingRodDown = AddAnalogInput("FishingRodDown", "Rod Down", GAME_INPUT_FISHING, "NONE"); - CAnalogInput *fishingReelFaster = AddAnalogInput("FishingReelFaster", "Reel Faster", GAME_INPUT_FISHING, "NONE"); - CAnalogInput *fishingReelSlower = AddAnalogInput("FishingReelSlower", "Reel Slower", GAME_INPUT_FISHING, "NONE"); - CAnalogInput *fishingStickLeft = AddAnalogInput("FishingStickLeft", "Stick Left", GAME_INPUT_FISHING, "NONE"); - CAnalogInput *fishingStickRight = AddAnalogInput("FishingStickRight", "Stick Right", GAME_INPUT_FISHING, "NONE"); - CAnalogInput *fishingStickUp = AddAnalogInput("FishingStickUp", "Stick Up", GAME_INPUT_FISHING, "NONE"); - CAnalogInput *fishingStickDown = AddAnalogInput("FishingStickDown", "Stick Down", GAME_INPUT_FISHING, "NONE"); + CAnalogInput *fishingRodLeft = AddAnalogInput("FishingRodLeft", "Rod Left", Game::INPUT_FISHING, "NONE"); + CAnalogInput *fishingRodRight = AddAnalogInput("FishingRodRight", "Rod Right", Game::INPUT_FISHING, "NONE"); + CAnalogInput *fishingRodUp = AddAnalogInput("FishingRodUp", "Rod Up", Game::INPUT_FISHING, "NONE"); + CAnalogInput *fishingRodDown = AddAnalogInput("FishingRodDown", "Rod Down", Game::INPUT_FISHING, "NONE"); + CAnalogInput *fishingReelFaster = AddAnalogInput("FishingReelFaster", "Reel Faster", Game::INPUT_FISHING, "NONE"); + CAnalogInput *fishingReelSlower = AddAnalogInput("FishingReelSlower", "Reel Slower", Game::INPUT_FISHING, "NONE"); + CAnalogInput *fishingStickLeft = AddAnalogInput("FishingStickLeft", "Stick Left", Game::INPUT_FISHING, "NONE"); + CAnalogInput *fishingStickRight = AddAnalogInput("FishingStickRight", "Stick Right", Game::INPUT_FISHING, "NONE"); + CAnalogInput *fishingStickUp = AddAnalogInput("FishingStickUp", "Stick Up", Game::INPUT_FISHING, "NONE"); + CAnalogInput *fishingStickDown = AddAnalogInput("FishingStickDown", "Stick Down", Game::INPUT_FISHING, "NONE"); - fishingRodX = AddAxisInput( "FishingRodX", "Rod X-Axis", GAME_INPUT_FISHING, "NONE", fishingRodLeft, fishingRodRight, 0, 0x80, 0xFF); - fishingRodY = AddAxisInput( "FishingRodY", "Rod Y-Axis", GAME_INPUT_FISHING, "NONE", fishingRodUp, fishingRodDown, 0xFF, 0x80, 0); - fishingReel = AddAxisInput( "FishingReel", "Reel Speed", GAME_INPUT_FISHING, "NONE", fishingReelSlower, fishingReelFaster, 0, 0x80, 0xFF); - fishingStickX = AddAxisInput( "FishingStickX", "Stick X-Axis", GAME_INPUT_FISHING, "NONE", fishingStickLeft, fishingStickRight, 0, 0x80, 0xFF); - fishingStickY = AddAxisInput( "FishingStickY", "Stick Y-Axis", GAME_INPUT_FISHING, "NONE", fishingStickUp, fishingStickDown, 0xFF, 0x80, 0); - fishingCast = AddSwitchInput( "FishingCast", "Cast", GAME_INPUT_FISHING, "NONE"); - fishingSelect = AddSwitchInput( "FishingSelect", "Select", GAME_INPUT_FISHING, "NONE"); + fishingRodX = AddAxisInput( "FishingRodX", "Rod X-Axis", Game::INPUT_FISHING, "NONE", fishingRodLeft, fishingRodRight, 0, 0x80, 0xFF); + fishingRodY = AddAxisInput( "FishingRodY", "Rod Y-Axis", Game::INPUT_FISHING, "NONE", fishingRodUp, fishingRodDown, 0xFF, 0x80, 0); + fishingReel = AddAxisInput( "FishingReel", "Reel Speed", Game::INPUT_FISHING, "NONE", fishingReelSlower, fishingReelFaster, 0, 0x80, 0xFF); + fishingStickX = AddAxisInput( "FishingStickX", "Stick X-Axis", Game::INPUT_FISHING, "NONE", fishingStickLeft, fishingStickRight, 0, 0x80, 0xFF); + fishingStickY = AddAxisInput( "FishingStickY", "Stick Y-Axis", Game::INPUT_FISHING, "NONE", fishingStickUp, fishingStickDown, 0xFF, 0x80, 0); + fishingCast = AddSwitchInput( "FishingCast", "Cast", Game::INPUT_FISHING, "NONE"); + fishingSelect = AddSwitchInput( "FishingSelect", "Select", Game::INPUT_FISHING, "NONE"); } CInputs::~CInputs() @@ -399,9 +401,26 @@ bool CInputs::Initialize() // Initialize all the inputs for (vector::iterator it = m_inputs.begin(); it != m_inputs.end(); it++) (*it)->Initialize(m_system); + return true; } +void CInputs::LoadFromConfig(const Util::Config::Node &config) +{ + m_system->LoadFromConfig(config); + + for (vector::iterator it = m_inputs.begin(); it != m_inputs.end(); it++) + (*it)->LoadFromConfig(config); +} + +void CInputs::StoreToConfig(Util::Config::Node *config) +{ + m_system->StoreToConfig(config); + + for (vector::iterator it = m_inputs.begin(); it != m_inputs.end(); it++) + (*it)->StoreToConfig(config); +} + void CInputs::ReadFromINIFile(CINIFile *ini, const char *section) { m_system->ReadFromINIFile(ini, section); @@ -418,21 +437,21 @@ void CInputs::WriteToINIFile(CINIFile *ini, const char *section) (*it)->WriteToINIFile(ini, section); } -bool CInputs::ConfigureInputs(const GameInfo *game) +bool CInputs::ConfigureInputs(const Game *game) { m_system->UngrabMouse(); // Print header and help message - int gameFlags; - if (game != NULL) + uint32_t gameFlags; + if (game) { - PrintHeader("Configure Inputs for %s", game->title); - gameFlags = game->inputFlags; + PrintHeader("Configure Inputs for %s", game->title.c_str()); + gameFlags = game->inputs; } else { PrintHeader("Configure Inputs"); - gameFlags = GAME_INPUT_ALL; + gameFlags = Game::INPUT_ALL; } PrintConfigureInputsHelp(); @@ -599,7 +618,7 @@ Finish: return !cancelled; } -bool CInputs::ConfigureInputs(const GameInfo *game, unsigned dispX, unsigned dispY, unsigned dispW, unsigned dispH) +bool CInputs::ConfigureInputs(const Game *game, unsigned dispX, unsigned dispY, unsigned dispW, unsigned dispH) { // Let the input system know the display geometry m_system->SetDisplayGeom(dispX, dispY, dispW, dispH); @@ -697,19 +716,19 @@ void CInputs::CalibrateJoystick(int joyNum) } } -void CInputs::PrintInputs(const GameInfo *game) +void CInputs::PrintInputs(const Game *game) { // Print header int gameFlags; if (game != NULL) { - PrintHeader("Input Assignments for %s", game->title); - gameFlags = game->inputFlags; + PrintHeader("Input Assignments for %s", game->title.c_str()); + gameFlags = game->inputs; } else { PrintHeader("Input Assignments"); - gameFlags = GAME_INPUT_ALL; + gameFlags = Game::INPUT_ALL; } const char *groupLabel = NULL; @@ -731,7 +750,7 @@ void CInputs::PrintInputs(const GameInfo *game) puts(""); } -bool CInputs::Poll(const GameInfo *game, unsigned dispX, unsigned dispY, unsigned dispW, unsigned dispH) +bool CInputs::Poll(const Game *game, unsigned dispX, unsigned dispY, unsigned dispW, unsigned dispH) { // Update the input system with the current display geometry m_system->SetDisplayGeom(dispX, dispY, dispW, dispH); @@ -741,7 +760,7 @@ bool CInputs::Poll(const GameInfo *game, unsigned dispX, unsigned dispY, unsigne return false; // Poll all UI inputs and all the inputs used by the current game, or all inputs if game is NULL - int gameFlags = (game != NULL ? game->inputFlags : GAME_INPUT_ALL); + uint32_t gameFlags = game ? game->inputs : Game::INPUT_ALL; for (vector::iterator it = m_inputs.begin(); it != m_inputs.end(); it++) { if ((*it)->IsUIInput() || ((*it)->gameFlags & gameFlags)) @@ -750,19 +769,19 @@ bool CInputs::Poll(const GameInfo *game, unsigned dispX, unsigned dispY, unsigne return true; } -void CInputs::DumpState(const GameInfo *game) +void CInputs::DumpState(const Game *game) { // Print header int gameFlags; if (game != NULL) { - PrintHeader("Input States for %s", game->title); - gameFlags = game->inputFlags; + PrintHeader("Input States for %s", game->title.c_str()); + gameFlags = game->inputs; } else { PrintHeader("Input States"); - gameFlags = GAME_INPUT_ALL; + gameFlags = Game::INPUT_ALL; } // Loop through the inputs used by the current game, or all inputs if game is NULL, and dump their values to stdout diff --git a/Src/Inputs/Inputs.h b/Src/Inputs/Inputs.h index d0d90d4..938ebd3 100644 --- a/Src/Inputs/Inputs.h +++ b/Src/Inputs/Inputs.h @@ -29,6 +29,7 @@ #define INCLUDED_INPUTS_H #include "Types.h" +#include "Util/NewConfig.h" #include using namespace std; @@ -41,7 +42,7 @@ class CSwitchInput; class CGearShift4Input; class CTriggerInput; class CINIFile; -struct GameInfo; +struct Game; /* * Represents the collection of Model3 inputs. @@ -266,27 +267,29 @@ public: bool Initialize(); /* - * Reads the input mapping assignments from the given INI file. + * Loads the input mapping assignments from the given config object. */ + void LoadFromConfig(const Util::Config::Node &config); void ReadFromINIFile(CINIFile *ini, const char *section); /* - * Writes the current input mapping assignments to the given INI file. + * Stores the current input mapping assignments to the given config object. */ + void StoreToConfig(Util::Config::Node *config); void WriteToINIFile(CINIFile *ini, const char *section); /* * Configures the current input mapping assignments for the given game, or all inputs if game is NULL, by asking the user for input. * Returns true if the inputs were configured okay or false if the user exited without requesting to save changes. */ - bool ConfigureInputs(const GameInfo *game); + bool ConfigureInputs(const Game *game); /* * Configures the current input mapping assignments for the given game, or all inputs if game is NULL, by asking the user for input. * Takes display geometry if this has not been set previously by a call to Poll(). * Returns true if the inputs were configured okay or false if the user exited without requesting to save changes. */ - bool ConfigureInputs(const GameInfo *game, unsigned dispX, unsigned dispY, unsigned dispW, unsigned dispH); + bool ConfigureInputs(const Game *game, unsigned dispX, unsigned dispY, unsigned dispW, unsigned dispH); void CalibrateJoysticks(); @@ -295,18 +298,18 @@ public: /* * Prints to stdout the current input mapping assignments for the given game, or all inputs if game is NULL. */ - void PrintInputs(const GameInfo *game); + void PrintInputs(const Game *game); /* * Polls (updates) the inputs for the given game, or all inputs if game is NULL, updating their values from their respective input sources. * First the input system is polled (CInputSystem.Poll()) and then each input is polled (CInput.Poll()). */ - bool Poll(const GameInfo *game, unsigned dispX, unsigned dispY, unsigned dispW, unsigned dispH); + bool Poll(const Game *game, unsigned dispX, unsigned dispY, unsigned dispW, unsigned dispH); /* * Prints the current values of the inputs for the given game, or all inputs if game is NULL, to stdout for debugging purposes. */ - void DumpState(const GameInfo *game); + void DumpState(const Game *game); }; #endif // INCLUDED_INPUTS_H diff --git a/Src/Model3/DSB.cpp b/Src/Model3/DSB.cpp index 002b229..322cce1 100644 --- a/Src/Model3/DSB.cpp +++ b/Src/Model3/DSB.cpp @@ -144,8 +144,8 @@ int CDSBResampler::UpSampleAndMix(INT16 *outL, INT16 *outR, INT16 *inL, INT16 *i INT32 v[2], musicVol, soundVol; // Obtain program volume settings and convert to 24.8 fixed point (0-200 -> 0x00-0x200) - musicVol = g_Config.GetMusicVolume(); - soundVol = g_Config.GetSoundVolume(); + musicVol = m_config["MusicVolume"].ValueAs(); + soundVol = m_config["SoundVolume"].ValueAs(); musicVol = (INT32) ((float) 0x100 * (float) musicVol / 100.0f); soundVol = (INT32) ((float) 0x100 * (float) soundVol / 100.0f); @@ -426,7 +426,7 @@ void CDSB1::RunFrame(INT16 *audioL, INT16 *audioR) int cycles; UINT8 v; - if (!g_Config.emulateDSB) + if (!m_config["EmulateDSB"].ValueAs()) { // DSB code applies SCSP volume, too, so we must still mix memset(mpegL, 0, (32000/60+2)*sizeof(INT16)); @@ -603,7 +603,9 @@ CZ80 *CDSB1::GetZ80(void) return &Z80; } -CDSB1::CDSB1(void) +CDSB1::CDSB1(const Util::Config::Node &config) + : m_config(config), + Resampler(config) { progROM = NULL; mpegROM = NULL; @@ -981,7 +983,7 @@ void CDSB2::SendCommand(UINT8 data) void CDSB2::RunFrame(INT16 *audioL, INT16 *audioR) { - if (!g_Config.emulateDSB) + if (!m_config["EmulateDSB"].ValueAs()) { // DSB code applies SCSP volume, too, so we must still mix memset(mpegL, 0, (32000/60+2)*sizeof(INT16)); @@ -1184,7 +1186,9 @@ M68KCtx *CDSB2::GetM68K(void) return &M68K; } -CDSB2::CDSB2(void) +CDSB2::CDSB2(const Util::Config::Node &config) + : m_config(config), + Resampler(config) { progROM = NULL; mpegROM = NULL; diff --git a/Src/Model3/DSB.h b/Src/Model3/DSB.h index e8bc711..0addf51 100644 --- a/Src/Model3/DSB.h +++ b/Src/Model3/DSB.h @@ -33,83 +33,7 @@ #include "Types.h" #include "CPU/Bus.h" - - -/****************************************************************************** - Configuration - - Because DSB code mixes both the sound board SCSP and MPEG audio together, both - volume settings are stored here (for now). -******************************************************************************/ - -/* - * CDSBConfig: - * - * Settings used by CDSB. - */ -class CDSBConfig -{ -public: - bool emulateDSB; // DSB emulation (enabled if true) - - // Sound (SCSP) volume (0-200, 100 being full amplitude) - inline void SetSoundVolume(int vol) - { - if (vol > 200) - { - ErrorLog("Sound volume cannot exceed 200%%; setting to 100%%.\n"); - vol = 100; - } - - if (vol < 0) - { - ErrorLog("Sound volume cannot be negative; setting to 0%%.\n"); - vol = 0; - } - - soundVol = (unsigned) vol; - } - - inline unsigned GetSoundVolume(void) - { - return soundVol; - } - - // Music (DSB MPEG) volume (0-200) - inline void SetMusicVolume(int vol) - { - if (vol > 200) - { - ErrorLog("Music volume cannot exceed 200%%; setting to 100%%.\n"); - vol = 100; - } - - if (vol < 0) - { - ErrorLog("Music volume cannot be negative; setting to 0%%.\n"); - vol = 0; - } - - musicVol = (unsigned) vol; - } - - inline unsigned GetMusicVolume(void) - { - return musicVol; - } - - // Defaults - CDSBConfig(void) - { - emulateDSB = true; - soundVol = 100; - musicVol = 100; - } - -private: - unsigned soundVol; - unsigned musicVol; -}; +#include "Util/NewConfig.h" /****************************************************************************** @@ -142,7 +66,12 @@ class CDSBResampler public: int UpSampleAndMix(INT16 *outL, INT16 *outR, INT16 *inL, INT16 *inR, UINT8 volumeL, UINT8 volumeR, int sizeOut, int sizeIn, int outRate, int inRate); void Reset(void); + CDSBResampler(const Util::Config::Node &config) + : m_config(config) + { + } private: + const Util::Config::Node &m_config; int nFrac; int pFrac; }; @@ -261,10 +190,12 @@ public: CZ80 *GetZ80(void); // Constructor and destructor - CDSB1(void); + CDSB1(const Util::Config::Node &config); ~CDSB1(void); private: + const Util::Config::Node &m_config; + // Resampler CDSBResampler Resampler; int retainedSamples; // how many MPEG samples carried over from previous frame @@ -336,10 +267,12 @@ public: M68KCtx *GetM68K(void); // Constructor and destructor - CDSB2(void); + CDSB2(const Util::Config::Node &config); ~CDSB2(void); private: + const Util::Config::Node &m_config; + // Private helper functions void WriteMPEGFIFO(UINT8 byte); diff --git a/Src/Model3/DriveBoard.cpp b/Src/Model3/DriveBoard.cpp index d293169..d05bce8 100644 --- a/Src/Model3/DriveBoard.cpp +++ b/Src/Model3/DriveBoard.cpp @@ -34,809 +34,822 @@ #include #include -#define RAM_SIZE 0x2000 // Z80 RAM +#define RAM_SIZE 0x2000 // Z80 RAM bool CDriveBoard::IsAttached(void) { - return m_attached && !m_tmpDisabled; + return m_attached && !m_tmpDisabled; } bool CDriveBoard::IsSimulated(void) { - return m_simulated; + return m_simulated; } void CDriveBoard::GetDIPSwitches(UINT8 &dip1, UINT8 &dip2) { - dip1 = m_dip1; - dip2 = m_dip2; + dip1 = m_dip1; + dip2 = m_dip2; } void CDriveBoard::SetDIPSwitches(UINT8 dip1, UINT8 dip2) { - m_dip1 = dip1; - m_dip2 = dip2; + m_dip1 = dip1; + m_dip2 = dip2; } unsigned CDriveBoard::GetSteeringStrength() { - return ((~(m_dip1>>2))&7) + 1; + return ((~(m_dip1>>2))&7) + 1; } void CDriveBoard::SetSteeringStrength(unsigned steeringStrength) { - m_dip1 = (m_dip1&0xE3) | (((~(steeringStrength - 1))&7)<<2); + m_dip1 = (m_dip1&0xE3) | (((~(steeringStrength - 1))&7)<<2); } void CDriveBoard::Get7SegDisplays(UINT8 &seg1Digit1, UINT8 &seg1Digit2, UINT8 &seg2Digit1, UINT8 &seg2Digit2) { - seg1Digit1 = m_seg1Digit1; - seg1Digit2 = m_seg1Digit2; - seg2Digit1 = m_seg2Digit1; - seg2Digit2 = m_seg2Digit2; + seg1Digit1 = m_seg1Digit1; + seg1Digit2 = m_seg1Digit2; + seg2Digit1 = m_seg2Digit1; + seg2Digit2 = m_seg2Digit2; } CZ80 *CDriveBoard::GetZ80(void) { - return &m_z80; + return &m_z80; } void CDriveBoard::SaveState(CBlockFile *SaveState) { - SaveState->NewBlock("DriveBoard", __FILE__); - - // Check board is attached and not temporarily disabled - bool attached = m_attached && !m_tmpDisabled; - SaveState->Write(&attached, sizeof(attached)); - if (attached) - { - // Check if simulated - SaveState->Write(&m_simulated, sizeof(m_simulated)); - if (m_simulated) - { - // TODO - save board simulation state - } - else - { - // Save DIP switches and digit displays - SaveState->Write(&m_dip1, sizeof(m_dip1)); - SaveState->Write(&m_dip2, sizeof(m_dip2)); - //SaveState->Write(&m_seg1Digit1, sizeof(m_seg1Digit1)); // No point in saving these - //SaveState->Write(&m_seg1Digit2, sizeof(m_seg1Digit2)); - //SaveState->Write(&m_seg2Digit1, sizeof(m_seg2Digit1)); - //SaveState->Write(&m_seg2Digit2, sizeof(m_seg2Digit2)); + SaveState->NewBlock("DriveBoard", __FILE__); + + // Check board is attached and not temporarily disabled + bool attached = m_attached && !m_tmpDisabled; + SaveState->Write(&attached, sizeof(attached)); + if (attached) + { + // Check if simulated + SaveState->Write(&m_simulated, sizeof(m_simulated)); + if (m_simulated) + { + // TODO - save board simulation state + } + else + { + // Save DIP switches and digit displays + SaveState->Write(&m_dip1, sizeof(m_dip1)); + SaveState->Write(&m_dip2, sizeof(m_dip2)); + //SaveState->Write(&m_seg1Digit1, sizeof(m_seg1Digit1)); // No point in saving these + //SaveState->Write(&m_seg1Digit2, sizeof(m_seg1Digit2)); + //SaveState->Write(&m_seg2Digit1, sizeof(m_seg2Digit1)); + //SaveState->Write(&m_seg2Digit2, sizeof(m_seg2Digit2)); - // Save RAM state - SaveState->Write(m_ram, RAM_SIZE); - - // Save interrupt and input/output state - SaveState->Write(&m_initialized, sizeof(m_initialized)); - SaveState->Write(&m_allowInterrupts, sizeof(m_allowInterrupts)); - SaveState->Write(&m_dataSent, sizeof(m_dataSent)); - SaveState->Write(&m_dataReceived, sizeof(m_dataReceived)); - SaveState->Write(&m_adcPortRead, sizeof(m_adcPortRead)); - SaveState->Write(&m_adcPortBit, sizeof(m_adcPortBit)); - SaveState->Write(&m_uncenterVal1, sizeof(m_uncenterVal1)); - SaveState->Write(&m_uncenterVal2, sizeof(m_uncenterVal2)); - - // Save CPU state - m_z80.SaveState(SaveState, "DriveBoard Z80"); - } - } + // Save RAM state + SaveState->Write(m_ram, RAM_SIZE); + + // Save interrupt and input/output state + SaveState->Write(&m_initialized, sizeof(m_initialized)); + SaveState->Write(&m_allowInterrupts, sizeof(m_allowInterrupts)); + SaveState->Write(&m_dataSent, sizeof(m_dataSent)); + SaveState->Write(&m_dataReceived, sizeof(m_dataReceived)); + SaveState->Write(&m_adcPortRead, sizeof(m_adcPortRead)); + SaveState->Write(&m_adcPortBit, sizeof(m_adcPortBit)); + SaveState->Write(&m_uncenterVal1, sizeof(m_uncenterVal1)); + SaveState->Write(&m_uncenterVal2, sizeof(m_uncenterVal2)); + + // Save CPU state + m_z80.SaveState(SaveState, "DriveBoard Z80"); + } + } } void CDriveBoard::LoadState(CBlockFile *SaveState) { - if (SaveState->FindBlock("DriveBoard") != OKAY) - { - ErrorLog("Unable to load drive board state. Save state file is corrupt."); - return; - } - - // Check that board was attached in saved state - bool wasAttached; - SaveState->Read(&wasAttached, sizeof(wasAttached)); - if (wasAttached) - { - // Check that board configuration exactly matches current configuration - bool wasSimulated; - SaveState->Read(&wasSimulated, sizeof(wasSimulated)); - if (wasAttached == m_attached && wasSimulated == m_simulated) - { - // Check if board was simulated - if (wasSimulated) - { - // TODO - load board simulation state - } - else - { - // Load DIP switches and digit displays - SaveState->Read(&m_dip1, sizeof(m_dip1)); - SaveState->Read(&m_dip2, sizeof(m_dip2)); - //SaveState->Read(&m_seg1Digit1, sizeof(m_seg1Digit1)); - //SaveState->Read(&m_seg1Digit2, sizeof(m_seg1Digit2)); - //SaveState->Read(&m_seg2Digit1, sizeof(m_seg2Digit1)); - //SaveState->Read(&m_seg2Digit2, sizeof(m_seg2Digit2)); + if (SaveState->FindBlock("DriveBoard") != OKAY) + { + ErrorLog("Unable to load drive board state. Save state file is corrupt."); + return; + } + + // Check that board was attached in saved state + bool wasAttached; + SaveState->Read(&wasAttached, sizeof(wasAttached)); + if (wasAttached) + { + // Check that board configuration exactly matches current configuration + bool wasSimulated; + SaveState->Read(&wasSimulated, sizeof(wasSimulated)); + if (wasAttached == m_attached && wasSimulated == m_simulated) + { + // Check if board was simulated + if (wasSimulated) + { + // TODO - load board simulation state + } + else + { + // Load DIP switches and digit displays + SaveState->Read(&m_dip1, sizeof(m_dip1)); + SaveState->Read(&m_dip2, sizeof(m_dip2)); + //SaveState->Read(&m_seg1Digit1, sizeof(m_seg1Digit1)); + //SaveState->Read(&m_seg1Digit2, sizeof(m_seg1Digit2)); + //SaveState->Read(&m_seg2Digit1, sizeof(m_seg2Digit1)); + //SaveState->Read(&m_seg2Digit2, sizeof(m_seg2Digit2)); - // Load RAM state - SaveState->Read(m_ram, RAM_SIZE); - - // Load interrupt and input/output state - SaveState->Read(&m_initialized, sizeof(m_initialized)); - SaveState->Read(&m_allowInterrupts, sizeof(m_allowInterrupts)); - SaveState->Read(&m_dataSent, sizeof(m_dataSent)); - SaveState->Read(&m_dataReceived, sizeof(m_dataReceived)); - SaveState->Read(&m_adcPortRead, sizeof(m_adcPortRead)); - SaveState->Read(&m_adcPortBit, sizeof(m_adcPortBit)); - SaveState->Read(&m_uncenterVal1, sizeof(m_uncenterVal1)); - SaveState->Read(&m_uncenterVal2, sizeof(m_uncenterVal2)); - - // Load CPU state - m_z80.LoadState(SaveState, "DriveBoard Z80"); - } + // Load RAM state + SaveState->Read(m_ram, RAM_SIZE); + + // Load interrupt and input/output state + SaveState->Read(&m_initialized, sizeof(m_initialized)); + SaveState->Read(&m_allowInterrupts, sizeof(m_allowInterrupts)); + SaveState->Read(&m_dataSent, sizeof(m_dataSent)); + SaveState->Read(&m_dataReceived, sizeof(m_dataReceived)); + SaveState->Read(&m_adcPortRead, sizeof(m_adcPortRead)); + SaveState->Read(&m_adcPortBit, sizeof(m_adcPortBit)); + SaveState->Read(&m_uncenterVal1, sizeof(m_uncenterVal1)); + SaveState->Read(&m_uncenterVal2, sizeof(m_uncenterVal2)); + + // Load CPU state + m_z80.LoadState(SaveState, "DriveBoard Z80"); + } - // Enable board - m_tmpDisabled = false; - } - else - { - // Otherwise, disable board as it can't be used with a mismatching configuratin - m_tmpDisabled = true; - } - } - else - // Disable board if it was not attached - m_tmpDisabled = true; + // Enable board + m_tmpDisabled = false; + } + else + { + // Otherwise, disable board as it can't be used with a mismatching configuratin + m_tmpDisabled = true; + } + } + else + // Disable board if it was not attached + m_tmpDisabled = true; - if (m_attached) - { - if (m_tmpDisabled) - printf("Disabled drive board due to incompatible save state.\n"); + if (m_attached) + { + if (m_tmpDisabled) + printf("Disabled drive board due to incompatible save state.\n"); - SendStopAll(); - } + SendStopAll(); + } } bool CDriveBoard::Init(const UINT8 *romPtr) -{ - // Assign ROM (note that the ROM data has not yet been loaded) - m_rom = romPtr; +{ + // Assign ROM (note that the ROM data has not yet been loaded) + m_rom = romPtr; - // Check have a valid ROM - m_attached = (m_rom != NULL); - if (!m_attached) - return OKAY; + // Check have a valid ROM + m_attached = (m_rom != NULL); + if (!m_attached) + return OKAY; - // Allocate memory for RAM - m_ram = new (std::nothrow) UINT8[RAM_SIZE]; - if (NULL == m_ram) - { - float ramSizeMB = (float)RAM_SIZE/(float)0x100000; - return ErrorLog("Insufficient memoy for drive board (needs %1.1f MB).", ramSizeMB); - } - memset(m_ram, 0, RAM_SIZE); + // Allocate memory for RAM + m_ram = new (std::nothrow) UINT8[RAM_SIZE]; + if (NULL == m_ram) + { + float ramSizeMB = (float)RAM_SIZE/(float)0x100000; + return ErrorLog("Insufficient memoy for drive board (needs %1.1f MB).", ramSizeMB); + } + memset(m_ram, 0, RAM_SIZE); - // Initialize Z80 - m_z80.Init(this, NULL); + // Initialize Z80 + m_z80.Init(this, NULL); - return OKAY; + return OKAY; } void CDriveBoard::AttachInputs(CInputs *inputs, unsigned gameInputFlags) { - m_inputs = inputs; - m_inputFlags = gameInputFlags; + m_inputs = inputs; + m_inputFlags = gameInputFlags; - DebugLog("DriveBoard attached inputs\n"); + DebugLog("DriveBoard attached inputs\n"); } void CDriveBoard::AttachOutputs(COutputs *outputs) { - m_outputs = outputs; + m_outputs = outputs; - DebugLog("DriveBoard attached outputs\n"); + DebugLog("DriveBoard attached outputs\n"); } void CDriveBoard::Reset(void) { - m_tmpDisabled = false; + m_tmpDisabled = false; - m_initialized = false; - m_allowInterrupts = false; + m_initialized = false; + m_allowInterrupts = false; - m_seg1Digit1 = 0xFF; - m_seg1Digit2 = 0xFF; - m_seg2Digit1 = 0xFF; - m_seg2Digit2 = 0xFF; + m_seg1Digit1 = 0xFF; + m_seg1Digit2 = 0xFF; + m_seg2Digit1 = 0xFF; + m_seg2Digit2 = 0xFF; - m_dataSent = 0; - m_dataReceived = 0; - m_adcPortRead = 0; - m_adcPortBit = 0; - m_port42Out = 0; - m_port46Out = 0; - m_prev42Out = 0; - m_prev46Out = 0; + m_dataSent = 0; + m_dataReceived = 0; + m_adcPortRead = 0; + m_adcPortBit = 0; + m_port42Out = 0; + m_port46Out = 0; + m_prev42Out = 0; + m_prev46Out = 0; - m_initState = 0; - m_boardMode = 0; - m_readMode = 0; - m_wheelCenter = 0x80; - m_uncenterVal1 = 0; - m_uncenterVal2 = 0; + m_initState = 0; + m_boardMode = 0; + m_readMode = 0; + m_wheelCenter = 0x80; + m_uncenterVal1 = 0; + m_uncenterVal2 = 0; - m_lastConstForce = 0; - m_lastSelfCenter = 0; - m_lastFriction = 0; - m_lastVibrate = 0; + m_lastConstForce = 0; + m_lastSelfCenter = 0; + m_lastFriction = 0; + m_lastVibrate = 0; - // Configure options (cannot be done in Init() because command line settings weren't yet parsed) - m_simulated = g_Config.simulateDrvBoard; - SetSteeringStrength(g_Config.steeringStrength); + // Configure options (cannot be done in Init() because command line settings weren't yet parsed) + m_simulated = false; //TODO: make this run-time configurable when simulation mode is supported + SetSteeringStrength(m_config["SteeringStrength"].ValueAsDefault(5)); - m_z80.Reset(); // always reset to provide a valid Z80 state - - if (!g_Config.forceFeedback) - m_attached = false; + m_z80.Reset(); // always reset to provide a valid Z80 state + +#ifdef SUPERMODEL_WIN32 + if (!m_config["ForceFeedback"].ValueAsDefault(false)) + m_attached = false; +#else + m_attached = false; +#endif - // Stop any effects that may still be playing - if (m_attached) - SendStopAll(); + // Stop any effects that may still be playing + if (m_attached) + SendStopAll(); } UINT8 CDriveBoard::Read(void) { - // TODO - simulate initialization sequence even when emulating to get rid of long pause at boot up (drive board can - // carry on booting whilst game starts) - if (m_simulated) - return SimulateRead(); - else - return m_dataReceived; + // TODO - simulate initialization sequence even when emulating to get rid of long pause at boot up (drive board can + // carry on booting whilst game starts) + if (m_simulated) + return SimulateRead(); + else + return m_dataReceived; } void CDriveBoard::Write(UINT8 data) { - //if (data >= 0x01 && data <= 0x0F || - // data >= 0x20 && data <= 0x2F || - // data >= 0x30 && data <= 0x3F || - // data >= 0x40 && data <= 0x4F || - // data >= 0x70 && data <= 0x7F) - // printf("DriveBoard.Write(%02X)\n", data); - if (m_simulated) - SimulateWrite(data); - else - { - m_dataSent = data; - if (data == 0xCB) - m_initialized = false; - } + //if (data >= 0x01 && data <= 0x0F || + // data >= 0x20 && data <= 0x2F || + // data >= 0x30 && data <= 0x3F || + // data >= 0x40 && data <= 0x4F || + // data >= 0x70 && data <= 0x7F) + // printf("DriveBoard.Write(%02X)\n", data); + if (m_simulated) + SimulateWrite(data); + else + { + m_dataSent = data; + if (data == 0xCB) + m_initialized = false; + } } UINT8 CDriveBoard::SimulateRead(void) { - if (m_initialized) - { - switch (m_readMode) - { - case 0x0: return m_statusFlags; // Status flags - case 0x1: return m_dip1; // DIP switch 1 value - case 0x2: return m_dip2; // DIP switch 2 value - case 0x3: return m_wheelCenter; // Wheel center - case 0x4: return 0x80; // Cockpit banking center - case 0x5: return m_inputs->steering->value; // Wheel position - case 0x6: return 0x80; // Cockpit banking position - case 0x7: return m_echoVal; // Init status/echo test - default: return 0xFF; - } - } - else - { - switch (m_initState / 5) - { - case 0: return 0xCF; // Initiate start - case 1: return 0xCE; - case 2: return 0xCD; - case 3: return 0xCC; // Centering wheel - default: - m_initialized = true; - return 0x80; - } - } + if (m_initialized) + { + switch (m_readMode) + { + case 0x0: return m_statusFlags; // Status flags + case 0x1: return m_dip1; // DIP switch 1 value + case 0x2: return m_dip2; // DIP switch 2 value + case 0x3: return m_wheelCenter; // Wheel center + case 0x4: return 0x80; // Cockpit banking center + case 0x5: return m_inputs->steering->value; // Wheel position + case 0x6: return 0x80; // Cockpit banking position + case 0x7: return m_echoVal; // Init status/echo test + default: return 0xFF; + } + } + else + { + switch (m_initState / 5) + { + case 0: return 0xCF; // Initiate start + case 1: return 0xCE; + case 2: return 0xCD; + case 3: return 0xCC; // Centering wheel + default: + m_initialized = true; + return 0x80; + } + } } void CDriveBoard::SimulateWrite(UINT8 cmd) { - // Following are commands for Scud Race. Daytona 2 has a compatible command set while Sega Rally 2 is completely different - // TODO - finish for Scud Race and Daytona 2 - // TODO - implement for Sega Rally 2 - UINT8 type = cmd>>4; - UINT8 val = cmd&0xF; - switch (type) - { - case 0: // 0x00-0F Play sequence - /* TODO */ - break; - case 1: // 0x10-1F Set centering strength - if (val == 0) - // Disable auto-centering - // TODO - is 0x10 for disable? - SendSelfCenter(0); - else - // Enable auto-centering (0x1 = weakest, 0xF = strongest) - SendSelfCenter(val * 0x11); - break; - case 2: // 0x20-2F Friction strength - if (val == 0) - // Disable friction - // TODO - is 0x20 for disable? - SendFriction(0); - else - // Enable friction (0x1 = weakest, 0xF = strongest) - SendFriction(val * 0x11); - break; - case 3: // 0x30-3F Uncentering (vibrate) - if (val == 0) - // Disable uncentering - SendVibrate(0); - else - // Enable uncentering (0x1 = weakest, 0xF = strongest) - SendVibrate(val * 0x11); - break; - case 4: // 0x40-4F Play power-slide sequence - /* TODO */ - break; - case 5: // 0x50-5F Rotate wheel right - SendConstantForce((val + 1) * 0x5); - break; - case 6: // 0x60-6F Rotate wheel left - SendConstantForce(-(val + 1) * 0x5); - break; - case 7: // 0x70-7F Set steering parameters - /* TODO */ - break; - case 8: // 0x80-8F Test Mode - switch (val&0x7) - { - case 0: SendStopAll(); break; // 0x80 Stop motor - case 1: SendConstantForce(20); break; // 0x81 Roll wheel right - case 2: SendConstantForce(-20); break; // 0x82 Roll wheel left - case 3: /* Ignore - no clutch */ break; // 0x83 Clutch on - case 4: /* Ignore - no clutch */ break; // 0x84 Clutch off - case 5: m_wheelCenter = m_inputs->steering->value; break; // 0x85 Set wheel center position - case 6: /* Ignore */ break; // 0x86 Set cockpit banking position - case 7: /* Ignore */ break; // 0x87 Lamp on/off - } - case 0x9: // 0x90-9F ??? Don't appear to have any effect with Scud Race ROM - /* TODO */ - break; - case 0xA: // 0xA0-AF ??? Don't appear to have any effect with Scud Race ROM - /* TODO */ - break; - case 0xB: // 0xB0-BF Invalid command (reserved for use by PPC to send cabinet type 0xB0 or 0xB1 during initialization) - /* Ignore */ - break; - case 0xC: // 0xC0-CF Set board mode (0xCB = reset board) - SendStopAll(); - if (val >= 0xB) - { - // Reset board - m_initialized = false; - m_initState = 0; - } - else - m_boardMode = val; - break; - case 0xD: // 0xD0-DF Set read mode - m_readMode = val&0x7; - break; - case 0xE: // 0xE0-EF Invalid command - /* Ignore */ - break; - case 0xF: // 0xF0-FF Echo test - m_echoVal = val; - break; - } + // Following are commands for Scud Race. Daytona 2 has a compatible command set while Sega Rally 2 is completely different + // TODO - finish for Scud Race and Daytona 2 + // TODO - implement for Sega Rally 2 + UINT8 type = cmd>>4; + UINT8 val = cmd&0xF; + switch (type) + { + case 0: // 0x00-0F Play sequence + /* TODO */ + break; + case 1: // 0x10-1F Set centering strength + if (val == 0) + // Disable auto-centering + // TODO - is 0x10 for disable? + SendSelfCenter(0); + else + // Enable auto-centering (0x1 = weakest, 0xF = strongest) + SendSelfCenter(val * 0x11); + break; + case 2: // 0x20-2F Friction strength + if (val == 0) + // Disable friction + // TODO - is 0x20 for disable? + SendFriction(0); + else + // Enable friction (0x1 = weakest, 0xF = strongest) + SendFriction(val * 0x11); + break; + case 3: // 0x30-3F Uncentering (vibrate) + if (val == 0) + // Disable uncentering + SendVibrate(0); + else + // Enable uncentering (0x1 = weakest, 0xF = strongest) + SendVibrate(val * 0x11); + break; + case 4: // 0x40-4F Play power-slide sequence + /* TODO */ + break; + case 5: // 0x50-5F Rotate wheel right + SendConstantForce((val + 1) * 0x5); + break; + case 6: // 0x60-6F Rotate wheel left + SendConstantForce(-(val + 1) * 0x5); + break; + case 7: // 0x70-7F Set steering parameters + /* TODO */ + break; + case 8: // 0x80-8F Test Mode + switch (val&0x7) + { + case 0: SendStopAll(); break; // 0x80 Stop motor + case 1: SendConstantForce(20); break; // 0x81 Roll wheel right + case 2: SendConstantForce(-20); break; // 0x82 Roll wheel left + case 3: /* Ignore - no clutch */ break; // 0x83 Clutch on + case 4: /* Ignore - no clutch */ break; // 0x84 Clutch off + case 5: m_wheelCenter = m_inputs->steering->value; break; // 0x85 Set wheel center position + case 6: /* Ignore */ break; // 0x86 Set cockpit banking position + case 7: /* Ignore */ break; // 0x87 Lamp on/off + } + case 0x9: // 0x90-9F ??? Don't appear to have any effect with Scud Race ROM + /* TODO */ + break; + case 0xA: // 0xA0-AF ??? Don't appear to have any effect with Scud Race ROM + /* TODO */ + break; + case 0xB: // 0xB0-BF Invalid command (reserved for use by PPC to send cabinet type 0xB0 or 0xB1 during initialization) + /* Ignore */ + break; + case 0xC: // 0xC0-CF Set board mode (0xCB = reset board) + SendStopAll(); + if (val >= 0xB) + { + // Reset board + m_initialized = false; + m_initState = 0; + } + else + m_boardMode = val; + break; + case 0xD: // 0xD0-DF Set read mode + m_readMode = val&0x7; + break; + case 0xE: // 0xE0-EF Invalid command + /* Ignore */ + break; + case 0xF: // 0xF0-FF Echo test + m_echoVal = val; + break; + } } void CDriveBoard::RunFrame(void) { - if (m_simulated) - SimulateFrame(); - else - EmulateFrame(); + if (m_simulated) + SimulateFrame(); + else + EmulateFrame(); } void CDriveBoard::SimulateFrame(void) { - if (!m_initialized) - m_initState++; - // TODO - update m_statusFlags and play preset scripts according to board mode -} + if (!m_initialized) + m_initState++; + // TODO - update m_statusFlags and play preset scripts according to board mode +} void CDriveBoard::EmulateFrame(void) { - // Assuming Z80 runs @ 4.0MHz and NMI triggers @ 60.0KHz - // TODO - find out if Z80 frequency is correct and exact frequency of NMI interrupts (just guesswork at the moment!) - int cycles = (int)(4.0 * 1000000 / 60); - int loopCycles = 10000; - while (cycles > 0) - { - if (m_allowInterrupts) - m_z80.TriggerNMI(); - cycles -= m_z80.Run(std::min(loopCycles, cycles)); - } + // Assuming Z80 runs @ 4.0MHz and NMI triggers @ 60.0KHz + // TODO - find out if Z80 frequency is correct and exact frequency of NMI interrupts (just guesswork at the moment!) + int cycles = (int)(4.0 * 1000000 / 60); + int loopCycles = 10000; + while (cycles > 0) + { + if (m_allowInterrupts) + m_z80.TriggerNMI(); + cycles -= m_z80.Run(std::min(loopCycles, cycles)); + } } UINT8 CDriveBoard::Read8(UINT32 addr) { - // TODO - shouldn't end of ROM be 0x7FFF not 0x8FFF? - if (addr < 0x9000) // ROM is 0x0000-0x8FFF - return m_rom[addr]; - else if (addr >= 0xE000) // RAM is 0xE000-0xFFFF - return m_ram[(addr-0xE000)&0x1FFF]; - else - { - //printf("Unhandled Z80 read of %08X (at PC = %04X)\n", addr, m_z80.GetPC()); - return 0xFF; - } + // TODO - shouldn't end of ROM be 0x7FFF not 0x8FFF? + if (addr < 0x9000) // ROM is 0x0000-0x8FFF + return m_rom[addr]; + else if (addr >= 0xE000) // RAM is 0xE000-0xFFFF + return m_ram[(addr-0xE000)&0x1FFF]; + else + { + //printf("Unhandled Z80 read of %08X (at PC = %04X)\n", addr, m_z80.GetPC()); + return 0xFF; + } } void CDriveBoard::Write8(UINT32 addr, UINT8 data) { - if (addr >= 0xE000) // RAM is 0xE000-0xFFFF - m_ram[(addr-0xE000)&0x1FFF] = data; + if (addr >= 0xE000) // RAM is 0xE000-0xFFFF + m_ram[(addr-0xE000)&0x1FFF] = data; #ifdef DEBUG - else - printf("Unhandled Z80 write to %08X (at PC = %04X)\n", addr, m_z80.GetPC()); + else + printf("Unhandled Z80 write to %08X (at PC = %04X)\n", addr, m_z80.GetPC()); #endif } UINT8 CDriveBoard::IORead8(UINT32 portNum) { - UINT8 adcVal; - switch (portNum) - { - case 32: // DIP 1 value - return m_dip1; - case 33: // DIP 2 value - return m_dip2; - case 36: // ADC channel 1 - not connected - case 37: // ADC channel 2 - steering wheel position (0x00 = full left, 0x80 = center, 0xFF = full right) - case 38: // ADC channel 3 - cockpit bank position (deluxe cabinets) (0x00 = full left, 0x80 = center, 0xFF = full right) - case 39: // ADC channel 4 - not connected - if (portNum == m_adcPortRead && m_adcPortBit-- > 0) - { - switch (portNum) - { - case 36: // Not connected - adcVal = 0x00; - break; - case 37: // Steering wheel for twin racing cabinets - TODO - check actual range of steering, suspect it is not really 0x00-0xFF - if (m_initialized) - adcVal = (UINT8)m_inputs->steering->value; - else - adcVal = 0x80; // If not initialized, return 0x80 so that wheel centering test does not fail - break; - case 38: // Cockpit bank position for deluxe racing cabinets - adcVal = 0x80; - break; - case 39: // Not connected - adcVal = 0x00; - break; - default: -#ifdef DEBUG - printf("Unhandled Z80 input on ADC port %u (at PC = %04X)\n", portNum, m_z80.GetPC()); + UINT8 adcVal; + switch (portNum) + { + case 32: // DIP 1 value + return m_dip1; + case 33: // DIP 2 value + return m_dip2; + case 36: // ADC channel 1 - not connected + case 37: // ADC channel 2 - steering wheel position (0x00 = full left, 0x80 = center, 0xFF = full right) + case 38: // ADC channel 3 - cockpit bank position (deluxe cabinets) (0x00 = full left, 0x80 = center, 0xFF = full right) + case 39: // ADC channel 4 - not connected + if (portNum == m_adcPortRead && m_adcPortBit-- > 0) + { + switch (portNum) + { + case 36: // Not connected + adcVal = 0x00; + break; + case 37: // Steering wheel for twin racing cabinets - TODO - check actual range of steering, suspect it is not really 0x00-0xFF + if (m_initialized) + adcVal = (UINT8)m_inputs->steering->value; + else + adcVal = 0x80; // If not initialized, return 0x80 so that wheel centering test does not fail + break; + case 38: // Cockpit bank position for deluxe racing cabinets + adcVal = 0x80; + break; + case 39: // Not connected + adcVal = 0x00; + break; + default: +#ifdef DEBUG + printf("Unhandled Z80 input on ADC port %u (at PC = %04X)\n", portNum, m_z80.GetPC()); #endif - return 0xFF; - } - return (adcVal>>m_adcPortBit)&0x01; - } - else - { + return 0xFF; + } + return (adcVal>>m_adcPortBit)&0x01; + } + else + { #ifdef DEBUG - printf("Unhandled Z80 input on ADC port %u (at PC = %04X)\n", portNum, m_z80.GetPC()); + printf("Unhandled Z80 input on ADC port %u (at PC = %04X)\n", portNum, m_z80.GetPC()); #endif - return 0xFF; - } - case 40: // PPC command - return m_dataSent; - case 44: // Encoder error reporting (kept at 0x00 for no error) - // Bit 1 0 - // 0 0 = encoder okay, no error - // 0 1 = encoder error 1 - overcurrent error - // 1 0 = encoder error 2 - overheat error - // 1 1 = encoder error 3 - encoder error, reinitializes board - return 0x00; - default: + return 0xFF; + } + case 40: // PPC command + return m_dataSent; + case 44: // Encoder error reporting (kept at 0x00 for no error) + // Bit 1 0 + // 0 0 = encoder okay, no error + // 0 1 = encoder error 1 - overcurrent error + // 1 0 = encoder error 2 - overheat error + // 1 1 = encoder error 3 - encoder error, reinitializes board + return 0x00; + default: #ifdef DEBUG - printf("Unhandled Z80 input on port %u (at PC = %04X)\n", portNum, m_z80.GetPC()); + printf("Unhandled Z80 input on port %u (at PC = %04X)\n", portNum, m_z80.GetPC()); #endif - return 0xFF; - } + return 0xFF; + } } void CDriveBoard::IOWrite8(UINT32 portNum, UINT8 data) { - switch (portNum) - { - case 16: // Unsure? - single byte 0x03 sent at initialization, then occasionally writes 0x07 & 0xFA to port - return; - case 17: // Interrupt control - if (data == 0x57) - m_allowInterrupts = true; - else if (data == 0x53) // Strictly speaking 0x53 then 0x04 - m_allowInterrupts = false; - return; - case 28: // Unsure? - two bytes 0xFF, 0xFF sent at initialization only - case 29: // Unsure? - two bytes 0x0F, 0x17 sent at initialization only - case 30: // Unsure? - same as port 28 - case 31: // Unsure? - same as port 31 - return; - case 32: // Left digit of 7-segment display 1 - m_seg1Digit1 = data; - return; - case 33: // Right digit of 7-segment display 1 - m_seg1Digit2 = data; - return; - case 34: // Left digit of 7-segment display 2 - m_seg2Digit1 = data; - return; - case 35: // Right digit of 7-segment display 2 - m_seg2Digit2 = data; - return; - case 36: // ADC channel 1 control - case 37: // ADC channel 2 control - case 38: // ADC channel 3 control - case 39: // ADC channel 4 control - m_adcPortRead = portNum; - m_adcPortBit = 8; - return; - case 41: // Reply for PPC - m_dataReceived = data; - if (data == 0xCC) - m_initialized = true; - return; - case 42: // Encoder motor data - m_port42Out = data; - ProcessEncoderCmd(); - return; - case 45: // Clutch/lamp control (deluxe cabinets) - return; - case 46: // Encoder motor control - m_port46Out = data; - return; - case 240: // Unsure? - single byte 0xBB sent at initialization only - return; - case 241: // Unsure? - single byte 0x4E sent regularly - some sort of watchdog? - return; - default: + switch (portNum) + { + case 16: // Unsure? - single byte 0x03 sent at initialization, then occasionally writes 0x07 & 0xFA to port + return; + case 17: // Interrupt control + if (data == 0x57) + m_allowInterrupts = true; + else if (data == 0x53) // Strictly speaking 0x53 then 0x04 + m_allowInterrupts = false; + return; + case 28: // Unsure? - two bytes 0xFF, 0xFF sent at initialization only + case 29: // Unsure? - two bytes 0x0F, 0x17 sent at initialization only + case 30: // Unsure? - same as port 28 + case 31: // Unsure? - same as port 31 + return; + case 32: // Left digit of 7-segment display 1 + m_seg1Digit1 = data; + return; + case 33: // Right digit of 7-segment display 1 + m_seg1Digit2 = data; + return; + case 34: // Left digit of 7-segment display 2 + m_seg2Digit1 = data; + return; + case 35: // Right digit of 7-segment display 2 + m_seg2Digit2 = data; + return; + case 36: // ADC channel 1 control + case 37: // ADC channel 2 control + case 38: // ADC channel 3 control + case 39: // ADC channel 4 control + m_adcPortRead = portNum; + m_adcPortBit = 8; + return; + case 41: // Reply for PPC + m_dataReceived = data; + if (data == 0xCC) + m_initialized = true; + return; + case 42: // Encoder motor data + m_port42Out = data; + ProcessEncoderCmd(); + return; + case 45: // Clutch/lamp control (deluxe cabinets) + return; + case 46: // Encoder motor control + m_port46Out = data; + return; + case 240: // Unsure? - single byte 0xBB sent at initialization only + return; + case 241: // Unsure? - single byte 0x4E sent regularly - some sort of watchdog? + return; + default: #ifdef DEBUG - printf("Unhandled Z80 output on port %u (at PC = %04X)\n", portNum, m_z80.GetPC()); + printf("Unhandled Z80 output on port %u (at PC = %04X)\n", portNum, m_z80.GetPC()); #endif - return; - } + return; + } } void CDriveBoard::ProcessEncoderCmd(void) { - if (m_prev42Out != m_port42Out || m_prev46Out != m_port46Out) - { - //printf("46 [%02X] / 42 [%02X]\n", m_port46Out, m_port42Out); - switch (m_port46Out) - { - case 0xFB: - // TODO - friction? Sent during power slide. 0xFF = strongest or 0x00? - //SendFriction(m_port42Out); - break; + if (m_prev42Out != m_port42Out || m_prev46Out != m_port46Out) + { + //printf("46 [%02X] / 42 [%02X]\n", m_port46Out, m_port42Out); + switch (m_port46Out) + { + case 0xFB: + // TODO - friction? Sent during power slide. 0xFF = strongest or 0x00? + //SendFriction(m_port42Out); + break; - case 0xFC: - // Centering / uncentering (vibrate) - // Bit 2 = on for centering, off for uncentering - if (m_port42Out&0x04) - { - // Centering - // Bit 7 = on for disable, off for enable - if (m_port42Out&0x80) - { - // Disable centering - SendSelfCenter(0); - } - else - { - // Bits 3-6 = centering strength 0x0-0xF. This is scaled to range 0x0F-0xFF - UINT8 strength = ((m_port42Out&0x78)>>3) * 0x10 + 0xF; - SendSelfCenter(strength); - } - } - else - { - // Uncentering - // Bits 0-1 = data sequence number 0-3 - UINT8 seqNum = m_port42Out&0x03; - // Bits 4-7 = data values - UINT16 data = (m_port42Out&0xF0)>>4; - switch (seqNum) - { - case 0: m_uncenterVal1 = data<<4; break; - case 1: m_uncenterVal1 |= data; break; - case 2: m_uncenterVal2 = data<<4; break; - case 3: m_uncenterVal2 |= data; break; - } - if (seqNum == 0 && m_uncenterVal1 == 0) - { - // Disable uncentering - SendVibrate(0); - } - else if (seqNum == 3 && m_uncenterVal1 > 0) - { - // Uncentering - unsure exactly how values sent map to strength or whether they specify some other attributes of effect - // For now just attempting to map them to a sensible value in range 0x00-0xFF - UINT8 strength = ((m_uncenterVal1>>1) - 7) * 0x50 + ((m_uncenterVal2>>1) - 5) * 0x10 + 0xF; - SendVibrate(strength); - } - } - break; - - case 0xFD: - // TODO - unsure? Sent as velocity changes, similar to self-centering - break; - - case 0xFE: - // Apply constant force to wheel - // Value is: 0x80 = stop motor, 0x81-0xC0 = roll wheel left, 0x40-0x7F = roll wheel right, scale to range -0x80-0x7F - // Note: seems to often output 0x7F or 0x81 for stop motor, so narrowing wheel ranges to 0x40-0x7E and 0x82-0xC0 - if (m_port42Out > 0x81) - { - if (m_port42Out <= 0xC0) - SendConstantForce(2 * (0x81 - m_port42Out)); - else - SendConstantForce(-0x80); - } - else if (m_port42Out < 0x7F) - { - if (m_port42Out >= 0x40) - SendConstantForce(2 * (0x7F - m_port42Out)); - else - SendConstantForce(0x7F); - } - else - SendConstantForce(0); - break; - - case 0xFF: - // Stop all effects - if (m_port42Out == 0) - SendStopAll(); - break; + case 0xFC: + // Centering / uncentering (vibrate) + // Bit 2 = on for centering, off for uncentering + if (m_port42Out&0x04) + { + // Centering + // Bit 7 = on for disable, off for enable + if (m_port42Out&0x80) + { + // Disable centering + SendSelfCenter(0); + } + else + { + // Bits 3-6 = centering strength 0x0-0xF. This is scaled to range 0x0F-0xFF + UINT8 strength = ((m_port42Out&0x78)>>3) * 0x10 + 0xF; + SendSelfCenter(strength); + } + } + else + { + // Uncentering + // Bits 0-1 = data sequence number 0-3 + UINT8 seqNum = m_port42Out&0x03; + // Bits 4-7 = data values + UINT16 data = (m_port42Out&0xF0)>>4; + switch (seqNum) + { + case 0: m_uncenterVal1 = data<<4; break; + case 1: m_uncenterVal1 |= data; break; + case 2: m_uncenterVal2 = data<<4; break; + case 3: m_uncenterVal2 |= data; break; + } + if (seqNum == 0 && m_uncenterVal1 == 0) + { + // Disable uncentering + SendVibrate(0); + } + else if (seqNum == 3 && m_uncenterVal1 > 0) + { + // Uncentering - unsure exactly how values sent map to strength or whether they specify some other attributes of effect + // For now just attempting to map them to a sensible value in range 0x00-0xFF + UINT8 strength = ((m_uncenterVal1>>1) - 7) * 0x50 + ((m_uncenterVal2>>1) - 5) * 0x10 + 0xF; + SendVibrate(strength); + } + } + break; + + case 0xFD: + // TODO - unsure? Sent as velocity changes, similar to self-centering + break; + + case 0xFE: + // Apply constant force to wheel + // Value is: 0x80 = stop motor, 0x81-0xC0 = roll wheel left, 0x40-0x7F = roll wheel right, scale to range -0x80-0x7F + // Note: seems to often output 0x7F or 0x81 for stop motor, so narrowing wheel ranges to 0x40-0x7E and 0x82-0xC0 + if (m_port42Out > 0x81) + { + if (m_port42Out <= 0xC0) + SendConstantForce(2 * (0x81 - m_port42Out)); + else + SendConstantForce(-0x80); + } + else if (m_port42Out < 0x7F) + { + if (m_port42Out >= 0x40) + SendConstantForce(2 * (0x7F - m_port42Out)); + else + SendConstantForce(0x7F); + } + else + SendConstantForce(0); + break; + + case 0xFF: + // Stop all effects + if (m_port42Out == 0) + SendStopAll(); + break; - default: - //printf("Unknown = 46 [%02X] / 42 [%02X]\n", m_port46Out, m_port42Out); - break; - } + default: + //printf("Unknown = 46 [%02X] / 42 [%02X]\n", m_port46Out, m_port42Out); + break; + } - m_prev42Out = m_port42Out; - m_prev46Out = m_port46Out; - } + m_prev42Out = m_port42Out; + m_prev46Out = m_port46Out; + } } void CDriveBoard::SendStopAll(void) { - //printf(">> Stop All Effects\n"); + //printf(">> Stop All Effects\n"); - ForceFeedbackCmd ffCmd; - ffCmd.id = FFStop; - m_inputs->steering->SendForceFeedbackCmd(ffCmd); + ForceFeedbackCmd ffCmd; + ffCmd.id = FFStop; + m_inputs->steering->SendForceFeedbackCmd(ffCmd); - m_lastConstForce = 0; - m_lastSelfCenter = 0; - m_lastFriction = 0; - m_lastVibrate = 0; + m_lastConstForce = 0; + m_lastSelfCenter = 0; + m_lastFriction = 0; + m_lastVibrate = 0; } void CDriveBoard::SendConstantForce(INT8 val) { - if (val == m_lastConstForce) - return; - /* - if (val > 0) - { - printf(">> Force Right %02X [%8s", val, ""); - for (unsigned i = 0; i < 8; i++) - printf(i == 0 || i <= (val + 1) / 16 ? ">" : " "); - printf("]\n"); - } - else if (val < 0) - { - printf(">> Force Left %02X [", -val); - for (unsigned i = 0; i < 8; i++) - printf(i == 7 || i >= (val + 128) / 16 ? "<" : " "); - printf("%8s]\n", ""); - } - else - printf(">> Stop Force [%16s]\n", ""); - */ - - ForceFeedbackCmd ffCmd; - ffCmd.id = FFConstantForce; - ffCmd.force = (float)val / (val >= 0 ? 127.0f : 128.0f); - m_inputs->steering->SendForceFeedbackCmd(ffCmd); + if (val == m_lastConstForce) + return; + /* + if (val > 0) + { + printf(">> Force Right %02X [%8s", val, ""); + for (unsigned i = 0; i < 8; i++) + printf(i == 0 || i <= (val + 1) / 16 ? ">" : " "); + printf("]\n"); + } + else if (val < 0) + { + printf(">> Force Left %02X [", -val); + for (unsigned i = 0; i < 8; i++) + printf(i == 7 || i >= (val + 128) / 16 ? "<" : " "); + printf("%8s]\n", ""); + } + else + printf(">> Stop Force [%16s]\n", ""); + */ + + ForceFeedbackCmd ffCmd; + ffCmd.id = FFConstantForce; + ffCmd.force = (float)val / (val >= 0 ? 127.0f : 128.0f); + m_inputs->steering->SendForceFeedbackCmd(ffCmd); - m_lastConstForce = val; + m_lastConstForce = val; } void CDriveBoard::SendSelfCenter(UINT8 val) { - if (val == m_lastSelfCenter) - return; - /* - if (val == 0) - printf(">> Stop Self-Center\n"); - else - printf(">> Self-Center %02X\n", val); - */ - - ForceFeedbackCmd ffCmd; - ffCmd.id = FFSelfCenter; - ffCmd.force = (float)val / 255.0f; - m_inputs->steering->SendForceFeedbackCmd(ffCmd); + if (val == m_lastSelfCenter) + return; + /* + if (val == 0) + printf(">> Stop Self-Center\n"); + else + printf(">> Self-Center %02X\n", val); + */ + + ForceFeedbackCmd ffCmd; + ffCmd.id = FFSelfCenter; + ffCmd.force = (float)val / 255.0f; + m_inputs->steering->SendForceFeedbackCmd(ffCmd); - m_lastSelfCenter = val; + m_lastSelfCenter = val; } void CDriveBoard::SendFriction(UINT8 val) { - if (val == m_lastFriction) - return; - /* - if (val == 0) - printf(">> Stop Friction\n"); - else - printf(">> Friction %02X\n", val); - */ - - ForceFeedbackCmd ffCmd; - ffCmd.id = FFFriction; - ffCmd.force = (float)val / 255.0f; - m_inputs->steering->SendForceFeedbackCmd(ffCmd); + if (val == m_lastFriction) + return; + /* + if (val == 0) + printf(">> Stop Friction\n"); + else + printf(">> Friction %02X\n", val); + */ + + ForceFeedbackCmd ffCmd; + ffCmd.id = FFFriction; + ffCmd.force = (float)val / 255.0f; + m_inputs->steering->SendForceFeedbackCmd(ffCmd); - m_lastFriction = val; + m_lastFriction = val; } void CDriveBoard::SendVibrate(UINT8 val) { - if (val == m_lastVibrate) - return; - /* - if (val == 0) - printf(">> Stop Vibrate\n"); - else - printf(">> Vibrate %02X\n", val); - */ + if (val == m_lastVibrate) + return; + /* + if (val == 0) + printf(">> Stop Vibrate\n"); + else + printf(">> Vibrate %02X\n", val); + */ - ForceFeedbackCmd ffCmd; - ffCmd.id = FFVibrate; - ffCmd.force = (float)val / 255.0f; - m_inputs->steering->SendForceFeedbackCmd(ffCmd); + ForceFeedbackCmd ffCmd; + ffCmd.id = FFVibrate; + ffCmd.force = (float)val / 255.0f; + m_inputs->steering->SendForceFeedbackCmd(ffCmd); - m_lastVibrate = val; + m_lastVibrate = val; } -CDriveBoard::CDriveBoard() : m_attached(false), m_tmpDisabled(false), m_simulated(false), - m_rom(NULL), m_ram(NULL), m_inputs(NULL), m_outputs(NULL), m_dip1(0xCF), m_dip2(0xFF) +CDriveBoard::CDriveBoard(const Util::Config::Node &config) + : m_config(config), + m_attached(false), + m_tmpDisabled(false), + m_simulated(false), + m_dip1(0xCF), + m_dip2(0xFF), + m_rom(NULL), + m_ram(NULL), + m_inputs(NULL), + m_outputs(NULL) { - DebugLog("Built Drive Board\n"); + DebugLog("Built Drive Board\n"); } CDriveBoard::~CDriveBoard(void) -{ - if (m_ram != NULL) - { - delete[] m_ram; - m_ram = NULL; - } - m_rom = NULL; - m_inputs = NULL; - m_outputs = NULL; +{ + if (m_ram != NULL) + { + delete[] m_ram; + m_ram = NULL; + } + m_rom = NULL; + m_inputs = NULL; + m_outputs = NULL; - DebugLog("Destroyed Drive Board\n"); + DebugLog("Destroyed Drive Board\n"); } diff --git a/Src/Model3/DriveBoard.h b/Src/Model3/DriveBoard.h index 105bc52..385cd6a 100644 --- a/Src/Model3/DriveBoard.h +++ b/Src/Model3/DriveBoard.h @@ -28,26 +28,7 @@ #ifndef INCLUDED_DRIVEBOARD_H #define INCLUDED_DRIVEBOARD_H -/* - * CDriveBoardConfig: - * - * Settings used by CDriveBoard. - */ -class CDriveBoardConfig -{ -public: - bool forceFeedback; // Enable drive board emulation/simulation (read only during Reset(), cannot be changed in-game) - bool simulateDrvBoard; // Simulate drive board rather than emulating it - unsigned steeringStrength; // Setting for steering strength on DIP switches of drive board - - // Defaults - CDriveBoardConfig(void) - { - forceFeedback = false; - simulateDrvBoard = false; - steeringStrength = 5; - } -}; +#include "Util/NewConfig.h" /* * CDriveBoard @@ -55,287 +36,292 @@ public: class CDriveBoard : public IBus { public: - /* - * IsAttached(void): - * - * Returns: - * True if the drive board is "attached" and should be emulated, - * otherwise false. - */ - bool IsAttached(void); + /* + * IsAttached(void): + * + * Returns: + * True if the drive board is "attached" and should be emulated, + * otherwise false. + */ + bool IsAttached(void); - /* - * IsSimulated(void): - * - * Returns: - * True if the drive board is being simulated rather than actually - * emulated, otherwise false. - */ - bool IsSimulated(void); + /* + * IsSimulated(void): + * + * Returns: + * True if the drive board is being simulated rather than actually + * emulated, otherwise false. + */ + bool IsSimulated(void); - /* - * GetDIPSwitches(dip1, dip2): - * - * Reads the two sets of DIP switches on the drive board. - * - * Parameters: - * dip1 Reference of variable to store DIP switch 1 to. - * dip2 DIP switch 2. - */ - void GetDIPSwitches(UINT8 &dip1, UINT8 &dip2); + /* + * GetDIPSwitches(dip1, dip2): + * + * Reads the two sets of DIP switches on the drive board. + * + * Parameters: + * dip1 Reference of variable to store DIP switch 1 to. + * dip2 DIP switch 2. + */ + void GetDIPSwitches(UINT8 &dip1, UINT8 &dip2); - /* - * SetDIPSwitches(dip1, dip2): - * - * Sets the DIP switches. - * - * Parameters: - * dip1 DIP switch 1 value. - * dip2 DIP switch 2 value. - */ - void SetDIPSwitches(UINT8 dip1, UINT8 dip2); + /* + * SetDIPSwitches(dip1, dip2): + * + * Sets the DIP switches. + * + * Parameters: + * dip1 DIP switch 1 value. + * dip2 DIP switch 2 value. + */ + void SetDIPSwitches(UINT8 dip1, UINT8 dip2); - /* - * GetSteeringStrength(void): - * - * Returns: - * Strength of the steering based on drive board DIP switches (1-8). - */ - unsigned GetSteeringStrength(void); + /* + * GetSteeringStrength(void): + * + * Returns: + * Strength of the steering based on drive board DIP switches (1-8). + */ + unsigned GetSteeringStrength(void); - /* - * SetSteeringStrength(steeringStrength): - * - * Sets the steering strength (modifies the DIP switch setting). - * - * Parameters: - * steeringStrength A value ranging from 1 to 8. - */ - void SetSteeringStrength(unsigned steeringStrength); + /* + * SetSteeringStrength(steeringStrength): + * + * Sets the steering strength (modifies the DIP switch setting). + * + * Parameters: + * steeringStrength A value ranging from 1 to 8. + */ + void SetSteeringStrength(unsigned steeringStrength); - /* - * Get7SegDisplays(seg1Digit1, seg1Digit2, seg2Digit1, seg2Digit2): - * - * Reads the 7-segment displays. - * - * Parameters: - * seg1Digit1 Reference of variable to store digit 1 of the first 7- - * segment display to. - * seg1Digit2 First display, second digit. - * seg2Digit1 Second display, first digit. - * seg2Digit2 Second display, second digit. - */ - void Get7SegDisplays(UINT8 &seg1Digit, UINT8 &seg1Digit2, UINT8 &seg2Digit1, UINT8 &seg2Digit2); + /* + * Get7SegDisplays(seg1Digit1, seg1Digit2, seg2Digit1, seg2Digit2): + * + * Reads the 7-segment displays. + * + * Parameters: + * seg1Digit1 Reference of variable to store digit 1 of the first 7- + * segment display to. + * seg1Digit2 First display, second digit. + * seg2Digit1 Second display, first digit. + * seg2Digit2 Second display, second digit. + */ + void Get7SegDisplays(UINT8 &seg1Digit, UINT8 &seg1Digit2, UINT8 &seg2Digit1, UINT8 &seg2Digit2); - /* - * GetZ80(void): - * - * Returns: - * The Z80 object. - */ - CZ80 *GetZ80(void); + /* + * GetZ80(void): + * + * Returns: + * The Z80 object. + */ + CZ80 *GetZ80(void); - /* - * SaveState(SaveState): - * - * Saves the drive board state. - * - * Parameters: - * SaveState Block file to save state information to. - */ - void SaveState(CBlockFile *SaveState); + /* + * SaveState(SaveState): + * + * Saves the drive board state. + * + * Parameters: + * SaveState Block file to save state information to. + */ + void SaveState(CBlockFile *SaveState); - /* - * LoadState(SaveState): - * - * Restores the drive board state. - * - * Parameters: - * SaveState Block file to load save state information from. - */ - void LoadState(CBlockFile *SaveState); + /* + * LoadState(SaveState): + * + * Restores the drive board state. + * + * Parameters: + * SaveState Block file to load save state information from. + */ + void LoadState(CBlockFile *SaveState); - /* - * Init(romPtr): - * - * Initializes (and "attaches") the drive board. This should be called - * before other members. - * - * Parameters: - * romPtr Pointer to the drive board ROM (Z80 program). If this - * is NULL, then the drive board will not be emulated. - * - * Returns: - * FAIL if the drive board could not be initialized (prints own error - * message), otherwise OKAY. If the drive board is not attached - * because no ROM was passed to it, no error is generated and the - * drive board is silently disabled (detached). - */ - bool Init(const UINT8 *romPtr); + /* + * Init(romPtr): + * + * Initializes (and "attaches") the drive board. This should be called + * before other members. + * + * Parameters: + * romPtr Pointer to the drive board ROM (Z80 program). If this + * is NULL, then the drive board will not be emulated. + * + * Returns: + * FAIL if the drive board could not be initialized (prints own error + * message), otherwise OKAY. If the drive board is not attached + * because no ROM was passed to it, no error is generated and the + * drive board is silently disabled (detached). + */ + bool Init(const UINT8 *romPtr); - /* - * AttachInputs(InputsPtr, gameInputFlags): - * - * Attaches inputs to the drive board (for access to the steering wheel - * position). - * - * Parameters: - * inputs Pointer to the input object. - * gameInputFlags The current game's input flags. - */ - void AttachInputs(CInputs *inputs, unsigned gameInputFlags); + /* + * AttachInputs(InputsPtr, gameInputFlags): + * + * Attaches inputs to the drive board (for access to the steering wheel + * position). + * + * Parameters: + * inputs Pointer to the input object. + * gameInputFlags The current game's input flags. + */ + void AttachInputs(CInputs *inputs, unsigned gameInputFlags); - void AttachOutputs(COutputs *outputs); + void AttachOutputs(COutputs *outputs); - /* - * Reset(void): - * - * Resets the drive board. - */ - void Reset(void); + /* + * Reset(void): + * + * Resets the drive board. + */ + void Reset(void); - /* - * Read(): - * - * Reads data from the drive board. - * - * Returns: - * Data read. - */ - UINT8 Read(void); + /* + * Read(): + * + * Reads data from the drive board. + * + * Returns: + * Data read. + */ + UINT8 Read(void); - /* - * Write(data): - * - * Writes data to the drive board. - * - * Parameters: - * data Data to send. - */ - void Write(UINT8 data); + /* + * Write(data): + * + * Writes data to the drive board. + * + * Parameters: + * data Data to send. + */ + void Write(UINT8 data); - /* - * RunFrame(void): - * - * Emulates a single frame's worth of time on the drive board. - */ - void RunFrame(void); + /* + * RunFrame(void): + * + * Emulates a single frame's worth of time on the drive board. + */ + void RunFrame(void); - /* - * CDriveBoard(): - * ~CDriveBoard(): - * - * Constructor and destructor. Memory is freed by destructor. - */ - CDriveBoard(); - ~CDriveBoard(void); + /* + * CDriveBoard(config): + * ~CDriveBoard(): + * + * Constructor and destructor. Memory is freed by destructor. + * + * Paramters: + * config Run-time configuration. The reference should be held because + * this changes at run-time. + */ + CDriveBoard(const Util::Config::Node &config); + ~CDriveBoard(void); - /* - * Read8(addr): - * IORead8(portNum): - * - * Methods for reading from Z80's memory and IO space. Required by CBus. - * - * Parameters: - * addr Address in memory (0-0xFFFF). - * portNum Port address (0-255). - * - * Returns: - * A byte of data from the address or port. - */ - UINT8 Read8(UINT32 addr); - UINT8 IORead8(UINT32 portNum); - - /* - * Write8(addr, data): - * IORead8(portNum, data): - * - * Methods for writing to Z80's memory and IO space. Required by CBus. - * - * Parameters: - * addr Address in memory (0-0xFFFF). - * portNum Port address (0-255). - * data Byte to write. - */ - void Write8(UINT32 addr, UINT8 data); - void IOWrite8(UINT32 portNum, UINT8 data); - + /* + * Read8(addr): + * IORead8(portNum): + * + * Methods for reading from Z80's memory and IO space. Required by CBus. + * + * Parameters: + * addr Address in memory (0-0xFFFF). + * portNum Port address (0-255). + * + * Returns: + * A byte of data from the address or port. + */ + UINT8 Read8(UINT32 addr); + UINT8 IORead8(UINT32 portNum); + + /* + * Write8(addr, data): + * IORead8(portNum, data): + * + * Methods for writing to Z80's memory and IO space. Required by CBus. + * + * Parameters: + * addr Address in memory (0-0xFFFF). + * portNum Port address (0-255). + * data Byte to write. + */ + void Write8(UINT32 addr, UINT8 data); + void IOWrite8(UINT32 portNum, UINT8 data); + private: - bool m_attached; // True if drive board is attached - bool m_tmpDisabled; // True if temporarily disabled by loading an incompatible save state - bool m_simulated; // True if drive board should be simulated rather than emulated + const Util::Config::Node &m_config; + bool m_attached; // True if drive board is attached + bool m_tmpDisabled; // True if temporarily disabled by loading an incompatible save state + bool m_simulated; // True if drive board should be simulated rather than emulated - UINT8 m_dip1; // Value of DIP switch 1 - UINT8 m_dip2; // Value of DIP switch 2 + UINT8 m_dip1; // Value of DIP switch 1 + UINT8 m_dip2; // Value of DIP switch 2 - const UINT8* m_rom; // 32k ROM - UINT8* m_ram; // 8k RAM + const UINT8* m_rom; // 32k ROM + UINT8* m_ram; // 8k RAM - CZ80 m_z80; // Z80 CPU @ 4MHz + CZ80 m_z80; // Z80 CPU @ 4MHz - CInputs *m_inputs; - unsigned m_inputFlags; + CInputs *m_inputs; + unsigned m_inputFlags; - COutputs *m_outputs; - - // Emulation state - bool m_initialized; // True if drive board has finished initialization - bool m_allowInterrupts; // True if drive board has enabled NMI interrupts + COutputs *m_outputs; + + // Emulation state + bool m_initialized; // True if drive board has finished initialization + bool m_allowInterrupts; // True if drive board has enabled NMI interrupts - UINT8 m_seg1Digit1; // Current value of left digit on 7-segment display 1 - UINT8 m_seg1Digit2; // Current value of right digit on 7-segment display 1 - UINT8 m_seg2Digit1; // Current value of left digit on 7-segment display 2 - UINT8 m_seg2Digit2; // Current value of right digit on 7-segment display 2 + UINT8 m_seg1Digit1; // Current value of left digit on 7-segment display 1 + UINT8 m_seg1Digit2; // Current value of right digit on 7-segment display 1 + UINT8 m_seg2Digit1; // Current value of left digit on 7-segment display 2 + UINT8 m_seg2Digit2; // Current value of right digit on 7-segment display 2 - UINT8 m_dataSent; // Last command sent by main board - UINT8 m_dataReceived; // Data to send back to main board + UINT8 m_dataSent; // Last command sent by main board + UINT8 m_dataReceived; // Data to send back to main board - UINT16 m_adcPortRead; // ADC port currently reading from - UINT8 m_adcPortBit; // Bit number currently reading on ADC port + UINT16 m_adcPortRead; // ADC port currently reading from + UINT8 m_adcPortBit; // Bit number currently reading on ADC port - UINT8 m_port42Out; // Last value sent to Z80 I/O port 42 (encoder motor data) - UINT8 m_port46Out; // Last value sent to Z80 I/O port 46 (encoder motor control) + UINT8 m_port42Out; // Last value sent to Z80 I/O port 42 (encoder motor data) + UINT8 m_port46Out; // Last value sent to Z80 I/O port 46 (encoder motor control) - UINT8 m_prev42Out; // Previous value sent to Z80 I/O port 42 - UINT8 m_prev46Out; // Previous value sent to Z80 I/O port 46 + UINT8 m_prev42Out; // Previous value sent to Z80 I/O port 42 + UINT8 m_prev46Out; // Previous value sent to Z80 I/O port 46 - UINT8 m_uncenterVal1; // First part of pending uncenter command - UINT8 m_uncenterVal2; // Second part of pending uncenter command + UINT8 m_uncenterVal1; // First part of pending uncenter command + UINT8 m_uncenterVal2; // Second part of pending uncenter command - // Simulation state - UINT8 m_initState; - UINT8 m_statusFlags; - UINT8 m_boardMode; - UINT8 m_readMode; - UINT8 m_wheelCenter; - UINT8 m_cockpitCenter; - UINT8 m_echoVal; + // Simulation state + UINT8 m_initState; + UINT8 m_statusFlags; + UINT8 m_boardMode; + UINT8 m_readMode; + UINT8 m_wheelCenter; + UINT8 m_cockpitCenter; + UINT8 m_echoVal; - // Feedback state - INT8 m_lastConstForce; // Last constant force command sent - UINT8 m_lastSelfCenter; // Last self center command sent - UINT8 m_lastFriction; // Last friction command sent - UINT8 m_lastVibrate; // Last vibrate command sent + // Feedback state + INT8 m_lastConstForce; // Last constant force command sent + UINT8 m_lastSelfCenter; // Last self center command sent + UINT8 m_lastFriction; // Last friction command sent + UINT8 m_lastVibrate; // Last vibrate command sent - UINT8 SimulateRead(void); + UINT8 SimulateRead(void); - void SimulateWrite(UINT8 data); + void SimulateWrite(UINT8 data); - void SimulateFrame(void); + void SimulateFrame(void); - void EmulateFrame(void); + void EmulateFrame(void); - void ProcessEncoderCmd(void); + void ProcessEncoderCmd(void); - void SendStopAll(void); + void SendStopAll(void); - void SendConstantForce(INT8 val); + void SendConstantForce(INT8 val); - void SendSelfCenter(UINT8 val); + void SendSelfCenter(UINT8 val); - void SendFriction(UINT8 val); + void SendFriction(UINT8 val); - void SendVibrate(UINT8 val); + void SendVibrate(UINT8 val); }; -#endif // INCLUDED_DRIVEBOARD_H +#endif // INCLUDED_DRIVEBOARD_H diff --git a/Src/Model3/IEmulator.h b/Src/Model3/IEmulator.h index 03f57fe..5f96e50 100644 --- a/Src/Model3/IEmulator.h +++ b/Src/Model3/IEmulator.h @@ -30,7 +30,8 @@ #define INCLUDED_IEMULATOR_H class CBlockFile; -struct GameInfo; +struct Game; +struct ROMSet; class CRender2D; class IRender3D; class CInputs; @@ -116,31 +117,30 @@ public: * Resets the system. Does not modify non-volatile memory. */ virtual void Reset(void) = 0; - + /* - * GetGameInfo(void): + * GetGame(void): * * Returns: - * A pointer to the presently loaded game's information structure (or - * NULL if no ROM set has yet been loaded). + * A reference to the presently loaded game's information structure (which + * will be blank if no game has yet been loaded). */ - virtual const struct GameInfo * GetGameInfo(void) = 0; - + virtual const Game &GetGame(void) const = 0; + /* - * LoadROMSet(GameList, zipFile): + * LoadGame(game, rom_set): * - * Loads a complete ROM set from the specified ZIP archive. + * Loads a game, copying in the provided ROMs and setting the hardware + * stepping. * - * NOTE: Command line settings will not have been applied here yet. - * - * Parameters: - * GameList List of all supported games and their ROMs. - * zipFile ZIP file to load from. + * Parameters: + * game Game information. + * rom_set ROMs. * * Returns: * OKAY if successful, FAIL otherwise. Prints errors. */ - virtual bool LoadROMSet(const struct GameInfo *GameList, const char *zipFile) = 0; + virtual bool LoadGame(const Game &game, const ROMSet &rom_set) = 0; /* * AttachRenderers(Render2DPtr, Render3DPtr): diff --git a/Src/Model3/Model3.cpp b/Src/Model3/Model3.cpp index 1c9369f..c71b379 100644 --- a/Src/Model3/Model3.cpp +++ b/Src/Model3/Model3.cpp @@ -202,10 +202,13 @@ #include #include #include "Supermodel.h" +#include "Game.h" +#include "ROMSet.h" #include "Util/Format.h" +#include "Util/ByteSwap.h" #include #include -#include +#include /****************************************************************************** Model 3 Inputs @@ -244,7 +247,7 @@ UINT8 CModel3::ReadInputs(unsigned reg) data = (data&0xDF)|(EEPROM.Read()<<5); // bank 1 contains EEPROM data bit } - if ((Game->inputFlags&GAME_INPUT_SKI)) + if ((m_game.inputs & Game::INPUT_SKI)) { if ((inputBank&1) == 0) { @@ -261,12 +264,12 @@ UINT8 CModel3::ReadInputs(unsigned reg) data = 0xFF; - if ((Game->inputFlags&GAME_INPUT_SKI)) + if ((m_game.inputs & Game::INPUT_SKI)) { data &= ~(Inputs->skiPollRight->value<<0); } - if ((Game->inputFlags&GAME_INPUT_JOYSTICK1)) + if ((m_game.inputs & Game::INPUT_JOYSTICK1)) { data &= ~(Inputs->up[0]->value<<5); // P1 Up data &= ~(Inputs->down[0]->value<<4); // P1 Down @@ -274,7 +277,7 @@ UINT8 CModel3::ReadInputs(unsigned reg) data &= ~(Inputs->right[0]->value<<6); // P1 Right } - if ((Game->inputFlags&GAME_INPUT_FIGHTING)) + if ((m_game.inputs & Game::INPUT_FIGHTING)) { data &= ~(Inputs->escape[0]->value<<3); // P1 Escape data &= ~(Inputs->guard[0]->value<<2); // P1 Guard @@ -282,7 +285,7 @@ UINT8 CModel3::ReadInputs(unsigned reg) data &= ~(Inputs->punch[0]->value<<0); // P1 Punch } - if ((Game->inputFlags&GAME_INPUT_SPIKEOUT)) + if ((m_game.inputs & Game::INPUT_SPIKEOUT)) { data &= ~(Inputs->shift->value<<2); // Shift data &= ~(Inputs->beat->value<<0); // Beat @@ -290,14 +293,14 @@ UINT8 CModel3::ReadInputs(unsigned reg) data &= ~(Inputs->jump->value<<3); // Jump } - if ((Game->inputFlags&GAME_INPUT_SOCCER)) + if ((m_game.inputs & Game::INPUT_SOCCER)) { data &= ~(Inputs->shortPass[0]->value<<2); // P1 Short Pass data &= ~(Inputs->longPass[0]->value<<0); // P1 Long Pass data &= ~(Inputs->shoot[0]->value<<1); // P1 Shoot } - if ((Game->inputFlags&GAME_INPUT_VR4)) + if ((m_game.inputs & Game::INPUT_VR4)) { data &= ~(Inputs->vr[0]->value<<0); // VR1 Red data &= ~(Inputs->vr[1]->value<<1); // VR2 Blue @@ -305,16 +308,16 @@ UINT8 CModel3::ReadInputs(unsigned reg) data &= ~(Inputs->vr[3]->value<<3); // VR4 Green } - if ((Game->inputFlags&GAME_INPUT_VIEWCHANGE)) + if ((m_game.inputs & Game::INPUT_VIEWCHANGE)) { // Harley is wired slightly differently - if ((Game->inputFlags&GAME_INPUT_HARLEY)) + if ((m_game.inputs & Game::INPUT_HARLEY)) data &= ~(Inputs->viewChange->value<<1); // View change else data &= ~(Inputs->viewChange->value<<0); // View change } - if ((Game->inputFlags&GAME_INPUT_SHIFT4)) + if ((m_game.inputs & Game::INPUT_SHIFT4)) { if (Inputs->gearShift4->value == 2) // Shift 2 data &= ~0x60; @@ -326,10 +329,10 @@ UINT8 CModel3::ReadInputs(unsigned reg) data &= ~0x10; } - if ((Game->inputFlags&GAME_INPUT_SHIFTUPDOWN)) + if ((m_game.inputs & Game::INPUT_SHIFTUPDOWN)) { // Harley is wired slightly differently - if ((Game->inputFlags&GAME_INPUT_HARLEY)) + if ((m_game.inputs & Game::INPUT_HARLEY)) { if (Inputs->gearShiftUp->value) // Shift up data &= ~0x60; @@ -345,16 +348,16 @@ UINT8 CModel3::ReadInputs(unsigned reg) } } - if ((Game->inputFlags&GAME_INPUT_HANDBRAKE)) + if ((m_game.inputs & Game::INPUT_HANDBRAKE)) data &= ~(Inputs->handBrake->value<<1); // Hand brake - if ((Game->inputFlags&GAME_INPUT_HARLEY)) + if ((m_game.inputs & Game::INPUT_HARLEY)) data &= ~(Inputs->musicSelect->value<<0); // Music select - if ((Game->inputFlags&GAME_INPUT_GUN1)) + if ((m_game.inputs & Game::INPUT_GUN1)) data &= ~(Inputs->trigger[0]->value<<0); // P1 Trigger - if ((Game->inputFlags&GAME_INPUT_ANALOG_JOYSTICK)) + if ((m_game.inputs & Game::INPUT_ANALOG_JOYSTICK)) { data &= ~(Inputs->analogJoyTrigger1->value<<5); // Trigger 1 data &= ~(Inputs->analogJoyTrigger2->value<<4); // Trigger 2 @@ -362,7 +365,7 @@ UINT8 CModel3::ReadInputs(unsigned reg) data &= ~(Inputs->analogJoyEvent2->value<<1); // Event Button 2 } - if ((Game->inputFlags&GAME_INPUT_TWIN_JOYSTICKS)) // First twin joystick + if ((m_game.inputs & Game::INPUT_TWIN_JOYSTICKS)) // First twin joystick { /* * Process left joystick inputs first @@ -418,16 +421,16 @@ UINT8 CModel3::ReadInputs(unsigned reg) data &= ~0x40; } - if ((Game->inputFlags&GAME_INPUT_ANALOG_GUN1)) + if ((m_game.inputs & Game::INPUT_ANALOG_GUN1)) { data &= ~(Inputs->analogTriggerLeft[0]->value<<0); data &= ~(Inputs->analogTriggerRight[0]->value<<1); } - if ((Game->inputFlags & GAME_INPUT_MAGTRUCK)) + if ((m_game.inputs & Game::INPUT_MAGTRUCK)) data &= ~(Inputs->magicalPedal1->value << 0); - if ((Game->inputFlags & GAME_INPUT_FISHING)) + if ((m_game.inputs & Game::INPUT_FISHING)) { data &= ~(Inputs->fishingCast->value << 0); data &= ~(Inputs->fishingSelect->value << 1); @@ -441,7 +444,7 @@ UINT8 CModel3::ReadInputs(unsigned reg) if (DriveBoard.IsAttached()) data = DriveBoard.Read(); - if ((Game->inputFlags&GAME_INPUT_JOYSTICK2)) + if ((m_game.inputs & Game::INPUT_JOYSTICK2)) { data &= ~(Inputs->up[1]->value<<5); // P2 Up data &= ~(Inputs->down[1]->value<<4); // P2 Down @@ -449,7 +452,7 @@ UINT8 CModel3::ReadInputs(unsigned reg) data &= ~(Inputs->right[1]->value<<6); // P2 Right } - if ((Game->inputFlags&GAME_INPUT_FIGHTING)) + if ((m_game.inputs & Game::INPUT_FIGHTING)) { data &= ~(Inputs->escape[1]->value<<3); // P2 Escape data &= ~(Inputs->guard[1]->value<<2); // P2 Guard @@ -457,14 +460,14 @@ UINT8 CModel3::ReadInputs(unsigned reg) data &= ~(Inputs->punch[1]->value<<0); // P2 Punch } - if ((Game->inputFlags&GAME_INPUT_SOCCER)) + if ((m_game.inputs & Game::INPUT_SOCCER)) { data &= ~(Inputs->shortPass[1]->value<<2); // P2 Short Pass data &= ~(Inputs->longPass[1]->value<<0); // P2 Long Pass data &= ~(Inputs->shoot[1]->value<<1); // P2 Shoot } - if ((Game->inputFlags&GAME_INPUT_TWIN_JOYSTICKS)) // Second twin joystick (see register 0x08 for comments) + if ((m_game.inputs & Game::INPUT_TWIN_JOYSTICKS)) // Second twin joystick (see register 0x08 for comments) { data &= ~(Inputs->twinJoyShot2->value<<0); @@ -494,16 +497,16 @@ UINT8 CModel3::ReadInputs(unsigned reg) data &= ~0x80; } - if ((Game->inputFlags&GAME_INPUT_GUN2)) + if ((m_game.inputs & Game::INPUT_GUN2)) data &= ~(Inputs->trigger[1]->value<<0); // P2 Trigger - if ((Game->inputFlags&GAME_INPUT_ANALOG_GUN2)) + if ((m_game.inputs & Game::INPUT_ANALOG_GUN2)) { data &= ~(Inputs->analogTriggerLeft[1]->value<<0); data &= ~(Inputs->analogTriggerRight[1]->value<<1); } - if ((Game->inputFlags & GAME_INPUT_MAGTRUCK)) + if ((m_game.inputs & Game::INPUT_MAGTRUCK)) data &= ~(Inputs->magicalPedal2->value << 0); return data; @@ -521,22 +524,22 @@ UINT8 CModel3::ReadInputs(unsigned reg) // Load ADC channels with input data memset(adc, 0, sizeof(adc)); - if ((Game->inputFlags&GAME_INPUT_VEHICLE)) + if ((m_game.inputs & Game::INPUT_VEHICLE)) { adc[0] = (UINT8)Inputs->steering->value; adc[1] = (UINT8)Inputs->accelerator->value; adc[2] = (UINT8)Inputs->brake->value; - if ((Game->inputFlags&GAME_INPUT_HARLEY)) + if ((m_game.inputs & Game::INPUT_HARLEY)) adc[3] = (UINT8)Inputs->rearBrake->value; } - if ((Game->inputFlags&GAME_INPUT_ANALOG_JOYSTICK)) + if ((m_game.inputs & Game::INPUT_ANALOG_JOYSTICK)) { adc[0] = (UINT8)Inputs->analogJoyY->value; adc[1] = (UINT8)Inputs->analogJoyX->value; } - if ((Game->inputFlags&GAME_INPUT_ANALOG_GUN1)||(Game->inputFlags&GAME_INPUT_ANALOG_GUN2)) + if ((m_game.inputs & Game::INPUT_ANALOG_GUN1)||(m_game.inputs & Game::INPUT_ANALOG_GUN2)) { adc[0] = (UINT8)Inputs->analogGunX[0]->value; adc[2] = (UINT8)Inputs->analogGunY[0]->value; @@ -544,19 +547,19 @@ UINT8 CModel3::ReadInputs(unsigned reg) adc[3] = (UINT8)Inputs->analogGunY[1]->value; } - if ((Game->inputFlags&GAME_INPUT_SKI)) + if ((m_game.inputs & Game::INPUT_SKI)) { adc[0] = (UINT8)Inputs->skiY->value; adc[1] = (UINT8)Inputs->skiX->value; } - if ((Game->inputFlags & GAME_INPUT_MAGTRUCK)) + if ((m_game.inputs & Game::INPUT_MAGTRUCK)) { adc[0] = uint8_t(Inputs->magicalLever1->value); adc[1] = uint8_t(Inputs->magicalLever2->value); } - if ((Game->inputFlags & GAME_INPUT_FISHING)) + if ((m_game.inputs & Game::INPUT_FISHING)) { adc[0] = uint8_t(Inputs->fishingRodY->value); adc[1] = uint8_t(Inputs->fishingRodX->value); @@ -615,7 +618,7 @@ void CModel3::WriteInputs(unsigned reg, UINT8 data) case 0x87: // Read light gun register serialFIFO1 = 0; // clear serial FIFO 1 serialFIFO2 = 0; - if ((Game->inputFlags&GAME_INPUT_GUN1||Game->inputFlags&GAME_INPUT_GUN2)) + if ((m_game.inputs & Game::INPUT_GUN1||m_game.inputs & Game::INPUT_GUN2)) { switch (gunReg) { @@ -940,7 +943,7 @@ UINT8 CModel3::Read8(UINT32 addr) // 53C810 SCSI case 0xC0: // only on Step 1.0 - if (Game->step != 0x10) + if (m_game.stepping != "1.0") break; case 0xF9: case 0xC1: @@ -1174,7 +1177,7 @@ UINT32 CModel3::Read32(UINT32 addr) // 53C810 SCSI case 0xC0: // only on Step 1.0 - if (Game->step != 0x10) // check for Step 1.0 + if (m_game.stepping != "1.0") // check for Step 1.0 break; case 0xF9: case 0xC1: @@ -1291,7 +1294,7 @@ void CModel3::Write8(UINT32 addr, UINT8 data) // 53C810 SCSI case 0xC0: // only on Step 1.0 - if (Game->step != 0x10) + if (m_game.stepping != "1.0") goto Unknown8; case 0xF9: case 0xC1: @@ -1553,7 +1556,7 @@ void CModel3::Write32(UINT32 addr, UINT32 data) // 53C810 SCSI case 0xC0: // step 1.0 only - if (Game->step != 0x10) + if (m_game.stepping != "1.0") goto Unknown32; case 0xF9: case 0xC1: @@ -1687,20 +1690,20 @@ void CModel3::RunFrame(void) UINT32 start = CThread::GetTicks(); // See if currently running multi-threaded - if (g_Config.multiThreaded) + if (m_multiThreaded) { // If so, check all threads are up and running if (!StartThreads()) goto ThreadError; // Wake threads for PPC main board (if multi-threading GPU), sound board (if sync'd) and drive board (if attached) so they can process a frame - if ((g_Config.gpuMultiThreaded && !ppcBrdThreadSync->Post()) || - (syncSndBrdThread && !sndBrdThreadSync->Post()) || - (DriveBoard.IsAttached() && !drvBrdThreadSync->Post())) + if ((m_gpuMultiThreaded && !ppcBrdThreadSync->Post()) || + (syncSndBrdThread && !sndBrdThreadSync->Post()) || + (DriveBoard.IsAttached() && !drvBrdThreadSync->Post())) goto ThreadError; // If not multi-threading GPU, then run PPC main board for a frame and sync GPUs now in this thread - if (!g_Config.gpuMultiThreaded) + if (!m_gpuMultiThreaded) { RunMainBoardFrame(); SyncGPUs(); @@ -1714,9 +1717,9 @@ void CModel3::RunFrame(void) goto ThreadError; // Wait for PPC main board, sound board and drive board threads to finish their work (if they are running and haven't finished already) - while ((g_Config.gpuMultiThreaded && !ppcBrdThreadDone) || - (syncSndBrdThread && !sndBrdThreadDone) || - (DriveBoard.IsAttached() && !drvBrdThreadDone)) + while ((m_gpuMultiThreaded && !ppcBrdThreadDone) || + (syncSndBrdThread && !sndBrdThreadDone) || + (DriveBoard.IsAttached() && !drvBrdThreadDone)) { if (!notifySync->Wait(notifyLock)) goto ThreadError; @@ -1730,7 +1733,7 @@ void CModel3::RunFrame(void) goto ThreadError; // If multi-threading GPU, then sync GPUs last while PPC main board thread is waiting - if (g_Config.gpuMultiThreaded) + if (m_gpuMultiThreaded) SyncGPUs(); } else @@ -1750,7 +1753,7 @@ void CModel3::RunFrame(void) ThreadError: ErrorLog("Threading error in CModel3::RunFrame: %s\nSwitching back to single-threaded mode.\n", CThread::GetLastError()); - g_Config.multiThreaded = false; + m_multiThreaded = false; } void CModel3::RunMainBoardFrame(void) @@ -1758,7 +1761,7 @@ void CModel3::RunMainBoardFrame(void) UINT32 start = CThread::GetTicks(); // Compute display and VBlank timings - unsigned ppcCycles = g_Config.GetPowerPCFrequency() * 1000000; + unsigned ppcCycles = m_config["PowerPCFrequency"].ValueAs() * 1000000; unsigned frameCycles = ppcCycles / 60; unsigned vblCycles = (unsigned)((float) frameCycles * 2.5f/100.0f); // 2.5% vblank (ridiculously short and wrong but bigger values cause flicker in Daytona) unsigned dispCycles = frameCycles - vblCycles; @@ -1774,15 +1777,15 @@ void CModel3::RunMainBoardFrame(void) // The values below were arrived at by trial and error and clearly more investigation is required. If it turns out that the status bit is // connected to the end of VBlank then the code below should be removed and the timing handled via GPU.VBlankEnd() instead. unsigned statusCycles; - if (Game->step >= 0x20) + if (m_game.stepping == "2.0" || m_game.stepping == "2.1") { // For some reason, Fighting Vipers 2 and Daytona USA 2 require completely different timing to the rest of the step 2.x games - if (!strcmp(Game->id, "daytona2") || (Game->step == 0x20 && !strcmp(Game->id, "fvipers2"))) + if (m_game.name == "daytona2" || (m_game.stepping == "2.0" && m_game.name == "fvipers2")) statusCycles = (unsigned)((float)frameCycles * 24.0f/100.0f); else statusCycles = (unsigned)((float)frameCycles * 9.12f/100.0f); } - else if (Game->step == 0x15) + else if (m_game.stepping == "1.5") statusCycles = (unsigned)((float)frameCycles * 5.5f/100.0f); else statusCycles = (unsigned)((float)frameCycles * 48.0f/100.0f); @@ -1905,7 +1908,7 @@ bool CModel3::StartThreads(void) return true; // Create synchronization objects - if (g_Config.gpuMultiThreaded) + if (m_gpuMultiThreaded) { ppcBrdThreadSync = CThread::CreateSemaphore(0); if (ppcBrdThreadSync == NULL) @@ -1938,7 +1941,7 @@ bool CModel3::StartThreads(void) stopThreads = false; // Create PPC main board thread, if multi-threading GPU - if (g_Config.gpuMultiThreaded) + if (m_gpuMultiThreaded) { ppcBrdThread = CThread::CreateThread(StartMainBoardThread, this); if (ppcBrdThread == NULL) @@ -1971,7 +1974,7 @@ bool CModel3::StartThreads(void) ThreadError: ErrorLog("Unable to create threads and/or synchronization objects: %s\nSwitching back to single-threaded mode.\n", CThread::GetLastError()); DeleteThreadObjects(); - g_Config.multiThreaded = false; + m_multiThreaded = false; return false; } @@ -1999,7 +2002,7 @@ bool CModel3::PauseThreads(void) ThreadError: ErrorLog("Threading error in CModel3::PauseThreads: %s\nSwitching back to single-threaded mode.\n", CThread::GetLastError()); - g_Config.multiThreaded = false; + m_multiThreaded = false; return false; } @@ -2022,7 +2025,7 @@ bool CModel3::ResumeThreads(void) ThreadError: ErrorLog("Threading error in CModel3::ResumeThreads: %s\nSwitching back to single-threaded mode.\n", CThread::GetLastError()); - g_Config.multiThreaded = false; + m_multiThreaded = false; return false; } @@ -2086,7 +2089,7 @@ bool CModel3::StopThreads(void) ThreadError: ErrorLog("Threading error in CModel3::StopThreads: %s\nSwitching back to single-threaded mode.\n", CThread::GetLastError()); - g_Config.multiThreaded = false; + m_multiThreaded = false; return false; } @@ -2244,7 +2247,7 @@ int CModel3::RunMainBoardThread(void) ThreadError: ErrorLog("Threading error in RunMainBoardThread: %s\nSwitching back to single-threaded mode.\n", CThread::GetLastError()); - g_Config.multiThreaded = false; + m_multiThreaded = false; return 1; } @@ -2289,7 +2292,7 @@ bool CModel3::WakeSoundBoardThread(void) ThreadError: ErrorLog("Threading error in WakeSoundBoardThread: %s\nSwitching back to single-threaded mode.\n", CThread::GetLastError()); - g_Config.multiThreaded = false; + m_multiThreaded = false; return false; } @@ -2373,7 +2376,7 @@ int CModel3::RunSoundBoardThread(void) ThreadError: ErrorLog("Threading error in RunSoundBoardThread: %s\nSwitching back to single-threaded mode.\n", CThread::GetLastError()); - g_Config.multiThreaded = false; + m_multiThreaded = false; return 1; } @@ -2429,7 +2432,7 @@ int CModel3::RunSoundBoardThreadSyncd(void) ThreadError: ErrorLog("Threading error in RunSoundBoardThreadSyncd: %s\nSwitching back to single-threaded mode.\n", CThread::GetLastError()); - g_Config.multiThreaded = false; + m_multiThreaded = false; return 1; } @@ -2485,7 +2488,7 @@ int CModel3::RunDriveBoardThread(void) ThreadError: ErrorLog("Threading error in RunDriveBoardThread: %s\nSwitching back to single-threaded mode.\n", CThread::GetLastError()); - g_Config.multiThreaded = false; + m_multiThreaded = false; return 1; } @@ -2546,13 +2549,13 @@ void CModel3::Reset(void) ******************************************************************************/ // Apply patches to games -void CModel3::Patch(void) +static void Patch(uint8_t *crom, const Game &game) { - if (!strcmp(Game->id, "scudp")) + if (game.name == "scudp") { // Base offset of program in CROM: 0x710000 } - else if (!strcmp(Game->id, "lemans24")) + else if (game.name == "lemans24") { // Base offset of program in CROM: 6473C0 *(UINT32 *) &crom[0x6D8C4C] = 0x00000002; // comm. mode: 00=master, 01=slave, 02=satellite @@ -2561,18 +2564,18 @@ void CModel3::Patch(void) *(UINT32 *) &crom[0x73EDD0] = 0x60000000; *(UINT32 *) &crom[0x73EDC4] = 0x60000000; } - else if (!strcmp(Game->id, "lostwsga")) + else if (game.name == "lostwsga") { *(UINT32 *) &crom[0x7374f4] = 0x38840004; // an actual bug in the game code } - else if (!strcmp(Game->id, "vs215") || !strcmp(Game->id, "vs215o") || !strcmp(Game->id, "vs29815")) + else if (game.name == "vs215" || game.name == "vs215o" || game.name == "vs29815") { // VS215 is a modification of VS2 that runs on Step 1.5 hardware. I // suspect the code here is trying to detect the system type but am too // lazy to figure it out right now. *(UINT32 *) &crom[0x7001A8] = 0x48000000+(0xFFF01630-0xFFF001A8); // force a jump to FFF01630 } - else if (!strcmp(Game->id, "vs298")) + else if (game.name == "vs298") { // Base offset of program in CROM: 600000 // Inexplicably, at PC=AFC1C, a call is made to FC78, which is right in the middle of some @@ -2581,36 +2584,36 @@ void CModel3::Patch(void) // Or, 300138 needs to be written with a non-zero value, it is loaded from EEPROM but is 0. *(UINT32 *) &crom[0x6AFC1C] = 0x60000000; } - else if (!strcmp(Game->id, "srally2")) + else if (game.name == "srally2") { *(UINT32 *) &crom[0x7C0C4] = 0x60000000; *(UINT32 *) &crom[0x7C0C8] = 0x60000000; *(UINT32 *) &crom[0x7C0CC] = 0x60000000; } - else if (!strcmp(Game->id, "harley")) + else if (game.name == "harley") { *(UINT32 *) &crom[0x50E8D4] = 0x60000000; *(UINT32 *) &crom[0x50E8F4] = 0x60000000; *(UINT32 *) &crom[0x50FB84] = 0x60000000; } - else if (!strcmp(Game->id, "harleyb")) + else if (game.name == "harleyb") { *(UINT32 *) &crom[0x50ECB4] = 0x60000000; *(UINT32 *) &crom[0x50ECD4] = 0x60000000; *(UINT32 *) &crom[0x50FF64] = 0x60000000; } - else if (!strcmp(Game->id, "swtrilgy")) + else if (game.name == "swtrilgy") { *(UINT32 *) &crom[0xF0E48] = 0x60000000; *(UINT32 *) &crom[0x043DC] = 0x48000090; // related to joystick feedback *(UINT32 *) &crom[0x029A0] = 0x60000000; *(UINT32 *) &crom[0x02A0C] = 0x60000000; } - else if (!strcmp(Game->id, "swtrilgya")) + else if (game.name == "swtrilgya") { *(UINT32 *) &crom[0xF6DD0] = 0x60000000; // from MAME } - else if (!strcmp(Game->id, "eca") || !strcmp(Game->id, "ecax")) + else if (game.name == "eca" || game.name == "ecax") { *(UINT32 *) &crom[0x535580] = 0x60000000; //*(UINT32 *) &crom[0x5023B4] = 0x60000000; @@ -2660,89 +2663,98 @@ static void Reverse32(uint8_t *buf, size_t size) // 64-bit magic number used to detect loading of optional ROMs #define MAGIC_NUMBER 0x4C444D5245505553ULL -const struct GameInfo * CModel3::GetGameInfo(void) +const Game &CModel3::GetGame() const { - return Game; + return m_game; } // Stepping-dependent parameters (MPC10x type, etc.) are initialized here -bool CModel3::LoadROMSet(const struct GameInfo *GameList, const char *zipFile) +bool CModel3::LoadGame(const Game &game, const ROMSet &rom_set) { - struct ROMMap Map[] = + m_game = Game(); + + /* + * Copy in ROM data with mirroring as necessary for the following cases: + * + * - VROM: 64MB. If <= 32MB, mirror to high 32MB. + * - Banked CROM: 128MB. If <= 64MB, mirror to high 64MB. + * - Fixed CROM: 8MB. If < 8MB, loaded only in high part of space and low + * part is a mirror of (banked) CROM0. + * - Sample ROM: 16MB. If <= 8MB, mirror to high 8MB. + * + * ROMs are released after being loaded. + */ + if (rom_set.get_rom("vrom").size <= 32*0x100000) { - { "CROM", crom }, - { "CROMxx", &crom[0x800000] }, - { "VROM", vrom }, - { "SndProg", soundROM }, - { "Samples", sampleROM }, - { "DSBProg", dsbROM }, - { "DSBMPEG", mpegROM }, - { "DriveBd", driveROM }, - { NULL, NULL } - }; - PPC_CONFIG PPCConfig; - - // Magic numbers to detect if optional ROMs are loaded - *(UINT64 *) driveROM = MAGIC_NUMBER; - - // Load game - Game = LoadROMSetFromZIPFile(Map, GameList, zipFile, true); - if (NULL == Game) - return ErrorLog("Failed to load ROM set."); - - // Perform mirroring as necessary - if (Game->vromSize < 0x4000000) // VROM is actually 64 MB - CopyRegion(vrom, Game->vromSize, 0x4000000, vrom, Game->vromSize); - if (Game->cromSize < 0x800000) // low part of fixed CROM region contains CROM0 - CopyRegion(crom, 0, 0x800000-Game->cromSize, &crom[0x800000], 0x800000); - if (Game->mirrorLow64MB) // for games w/ 64 MB or less banked CROM, mirror to upper 128 MB - CopyRegion(&crom[0x800000], 0x4000000, 0x8000000, &crom[0x800000], 0x4000000); - if (Game->sampleSize < 0x1000000) // if less than 16 MB of sample ROMs, mirror - CopyRegion(sampleROM, 0x800000, 0x1000000, sampleROM, 0x800000); - - // Byte reverse the PowerPC ROMs (convert to little endian words) - Reverse32(crom, 0x800000+0x8000000); - - // Byte swap sound board 68K ROMs (convert to little endian words) - Reverse16(soundROM, 0x80000); - Reverse16(sampleROM, 0x1000000); - - // Initialize CPU and configure hardware (CPU speed is set in Init()) - if (Game->step >= 0x20) // Step 2.0+ - { - PPCConfig.pvr = PPC_MODEL_603R; // 166 MHz - PPCConfig.bus_frequency = BUS_FREQUENCY_66MHZ; - PPCConfig.bus_frequency_multiplier = 0x25; // 2.5X multiplier - PCIBridge.SetModel(0x106); // MPC106 - } - else if (Game->step == 0x15) // Step 1.5 - { - PPCConfig.pvr = PPC_MODEL_603E; // 100 MHz - PPCConfig.bus_frequency = BUS_FREQUENCY_66MHZ; - PPCConfig.bus_frequency_multiplier = 0x15; // 1.5X multiplier - if (!strcmp(Game->id, "scudp1")) // some Step 1.x games use MPC106 - PCIBridge.SetModel(0x106); - else - PCIBridge.SetModel(0x105); // MPC105 - } - else if (Game->step == 0x10) // Step 1.0 - { - PPCConfig.pvr = PPC_MODEL_603R; // 66 MHz - PPCConfig.bus_frequency = BUS_FREQUENCY_66MHZ; - PPCConfig.bus_frequency_multiplier = 0x10; // 1X multiplier - if (!strcmp(Game->id, "bass") || !strcmp(Game->id, "getbass")) // some Step 1.x games use MPC106 - PCIBridge.SetModel(0x106); - else - PCIBridge.SetModel(0x105); // MPC105 + rom_set.get_rom("vrom").CopyTo(&vrom[0], 32*100000); + rom_set.get_rom("vrom").CopyTo(&vrom[32*0x100000], 32*0x100000); } else - return ErrorLog("Game uses an unrecognized stepping (%d.%d), cannot configure Model 3.", (Game->step>>4)&0xF, Game->step&0xF); + rom_set.get_rom("vrom").CopyTo(vrom, 64*0x100000); + if (rom_set.get_rom("banked_crom").size <= 64*0x100000) + { + rom_set.get_rom("banked_crom").CopyTo(&crom[8*0x100000 + 0], 64*0x100000); + rom_set.get_rom("banked_crom").CopyTo(&crom[8*0x100000 + 64*0x100000], 64*0x100000); + } + else + rom_set.get_rom("banked_crom").CopyTo(&crom[8*0x100000 + 0], 128*0x100000); + size_t crom_size = rom_set.get_rom("crom").size; + rom_set.get_rom("crom").CopyTo(&crom[8*0x100000 - crom_size], crom_size); + if (crom_size < 8*0x100000) + rom_set.get_rom("banked_crom").CopyTo(&crom[0], 8*0x100000 - crom_size); + if (rom_set.get_rom("sound_samples").size <= 8*0x100000) + { + rom_set.get_rom("sound_samples").CopyTo(&sampleROM[0], 8*0x100000); + rom_set.get_rom("sound_samples").CopyTo(&sampleROM[8*0x100000], 8*0x100000); + } + else + rom_set.get_rom("sound_samples").CopyTo(sampleROM, 16*0x100000); + rom_set.get_rom("sound_program").CopyTo(soundROM, 512*1024); + rom_set.get_rom("mpeg_program").CopyTo(dsbROM, 128*1024); + rom_set.get_rom("mpeg_music").CopyTo(mpegROM, 16*0x100000); + rom_set.get_rom("driveboard_program").CopyTo(driveROM, 64*1024); + + // Convert PowerPC and 68K ROMs to little endian words + Util::FlipEndian32(crom, 8*0x100000 + 128*0x100000); + Util::FlipEndian16(soundROM, 512*1024); + Util::FlipEndian16(sampleROM, 16*0x100000); - GPU.SetStep(Game->step); - - ppc_init(&PPCConfig); + // Initialize CPU + PPC_CONFIG ppc_config; + if (game.stepping == "2.0" || game.stepping == "2.1") + { + ppc_config.pvr = PPC_MODEL_603R; // 166 MHz + ppc_config.bus_frequency = BUS_FREQUENCY_66MHZ; + ppc_config.bus_frequency_multiplier = 0x25; // 2.5X multiplier + PCIBridge.SetModel(0x106); // MPC106 + } + else if (game.stepping == "1.5") + { + ppc_config.pvr = PPC_MODEL_603E; // 100 MHz + ppc_config.bus_frequency = BUS_FREQUENCY_66MHZ; + ppc_config.bus_frequency_multiplier = 0x15; // 1.5X multiplier + if (game.name == "scudp1") + PCIBridge.SetModel(0x106); // some Step 1.x games use MPC106 + else + PCIBridge.SetModel(0x105); // MPC105 + } + else if (game.stepping == "1.0") + { + ppc_config.pvr = PPC_MODEL_603R; // 66 MHz + ppc_config.bus_frequency = BUS_FREQUENCY_66MHZ; + ppc_config.bus_frequency_multiplier = 0x10; // 1X multiplier + if (game.name == "bass" || game.name == "getbass") + PCIBridge.SetModel(0x106); // some Step 1.x games use MPC106 + else + PCIBridge.SetModel(0x105); // MPC105 + } + else + { + ErrorLog("Cannot configure Model 3 because game uses unrecognized stepping (%s).", game.stepping.c_str()); + return FAIL; + } + ppc_init(&ppc_config); ppc_attach_bus(this); - PPCFetchRegions[0].start = 0; PPCFetchRegions[0].end = 0x007FFFFF; PPCFetchRegions[0].ptr = (UINT32 *) ram; @@ -2752,67 +2764,71 @@ bool CModel3::LoadROMSet(const struct GameInfo *GameList, const char *zipFile) PPCFetchRegions[2].start = 0; PPCFetchRegions[2].end = 0; PPCFetchRegions[2].ptr = NULL; - ppc_set_fetch(PPCFetchRegions); - // DSB board (if present) - if (Game->mpegBoard == 1) // Z80 board, do not byte swap program ROM + // Initialize Real3D + int stepping = ((game.stepping[0] - '0') << 4) | (game.stepping[2] - '0'); + GPU.SetStepping(stepping); + + // MPEG board (if present) + if (rom_set.get_rom("mpeg_program").size) { - DSB = new(std::nothrow) CDSB1(); - if (NULL == DSB) - return ErrorLog("Insufficient memory for Digital Sound Board object."); - if (OKAY != DSB->Init(dsbROM,mpegROM)) - return FAIL; - } - else if (Game->mpegBoard == 2) // 68K board - { - Reverse16(dsbROM, 0x20000); // byte swap program ROM - DSB = new(std::nothrow) CDSB2(); - if (NULL == DSB) - return ErrorLog("Insufficient memory for Digital Sound Board object."); - if (OKAY != DSB->Init(dsbROM,mpegROM)) + if (game.mpeg_board == "DSB1") + { + DSB = new(std::nothrow) CDSB1(m_config); + if (NULL == DSB) + return ErrorLog("Insufficient memory for Digital Sound Board object."); + } + else if (game.mpeg_board == "DSB2") + { + Util::FlipEndian16(dsbROM, 128*1024); // 68K program needs to be byte swapped + DSB = new(std::nothrow) CDSB2(m_config); + if (NULL == DSB) + return ErrorLog("Insufficient memory for Digital Sound Board object."); + } + else if (game.mpeg_board.empty()) + ErrorLog("No MPEG board type defined in game XML for MPEG ROMs."); + else + ErrorLog("Unknown MPEG board type '%s'. Only 'DSB1' and 'DSB2' are supported.", game.mpeg_board.c_str()); + if (DSB && OKAY != DSB->Init(dsbROM, mpegROM)) return FAIL; } SoundBoard.AttachDSB(DSB); // Drive board (if present) - if (Game->driveBoard) + if (rom_set.get_rom("driveboard_program").size) { - // Was the optional drive board ROM loaded? - if (MAGIC_NUMBER != *(UINT64 *) driveROM) // magic number overwritten by ROM - { - if (DriveBoard.Init(driveROM)) - return FAIL; - } - else - DriveBoard.Init(NULL); + if (DriveBoard.Init(driveROM)) + return FAIL; } else - DriveBoard.Init(NULL); // disable + DriveBoard.Init(NULL); // Security board encryption device - m_cryptoDevice.Init(Game->encryptionKey, std::bind(&CModel3::ReadSecurityRAM, this, std::placeholders::_1)); + m_cryptoDevice.Init(game.encryption_key, std::bind(&CModel3::ReadSecurityRAM, this, std::placeholders::_1)); // Apply ROM patches - Patch(); + //TODO: place these in XML + Patch(crom, game); // Print game information - std::set extraHw; - if (Game->mpegBoard) - extraHw.insert(Util::Format() << "Digital Sound Board (Type " << Game->mpegBoard << ")"); - if (Game->driveBoard) - extraHw.insert("Drive Board"); - if (Game->encryptionKey) - extraHw.insert("Security Board"); - printf(" Title: %s\n", Game->title); - printf(" ROM Set: %s\n", Game->id); - printf(" Developer: %s\n", Game->mfgName); - printf(" Year: %d\n", Game->year); - printf(" Step: %d.%d\n", (Game->step>>4)&0xF, Game->step&0xF); - if (!extraHw.empty()) - printf(" Extra Hardware: %s\n", Util::Format(", ").Join(extraHw).str().c_str()); - printf("\n"); + std::set extra_hw; + if (DSB) + extra_hw.insert(Util::Format() << "Digital Sound Board (Type " << game.mpeg_board << ")"); + if (rom_set.get_rom("driveboard_program").size) + extra_hw.insert("Drive Board"); + if (game.encryption_key) + extra_hw.insert("Security Board"); + std::cout << " Title: " << game.title << std::endl; + std::cout << " ROM Set: " << game.name << std::endl; + std::cout << " Developer: " << game.manufacturer << std::endl; + std::cout << " Year: " << game.year << std::endl; + std::cout << " Stepping: " << game.stepping << std::endl; + if (!extra_hw.empty()) + std::cout << " Extra Hardware: " << Util::Format(", ").Join(extra_hw) << std::endl; + std::cout << std::endl; + m_game = game; return OKAY; } @@ -2827,7 +2843,7 @@ void CModel3::AttachInputs(CInputs *InputsPtr) Inputs = InputsPtr; if (DriveBoard.IsAttached()) - DriveBoard.AttachInputs(Inputs, Game->inputFlags); + DriveBoard.AttachInputs(Inputs, m_game.inputs); DebugLog("Model 3 attached inputs\n"); } @@ -2835,7 +2851,7 @@ void CModel3::AttachInputs(CInputs *InputsPtr) void CModel3::AttachOutputs(COutputs *OutputsPtr) { Outputs = OutputsPtr; - Outputs->SetGame(Game); + Outputs->SetGame(m_game); Outputs->Attached(); if (DriveBoard.IsAttached()) @@ -2853,6 +2869,7 @@ bool CModel3::Init(void) memoryPool = new(std::nothrow) UINT8[MEMORY_POOL_SIZE]; if (NULL == memoryPool) return ErrorLog("Insufficient memory for Model 3 object (needs %1.1f MB).", memSizeMB); + memset(memoryPool, 0, MEMORY_POOL_SIZE); // Set up pointers ram = &memoryPool[OFFSET_RAM]; @@ -2901,13 +2918,19 @@ CDriveBoard *CModel3::GetDriveBoard(void) return &DriveBoard; } -CModel3::CModel3(void) +CModel3::CModel3(const Util::Config::Node &config) + : m_config(config), + m_multiThreaded(config["MultiThreaded"].ValueAs()), + m_gpuMultiThreaded(config["GPUMultiThreaded"].ValueAs()), + TileGen(config), + GPU(config), + SoundBoard(config), + DriveBoard(config) { // Initialize pointers so dtor can know whether to free them memoryPool = NULL; // Various uninitialized pointers - Game = NULL; Inputs = NULL; Outputs = NULL; ram = NULL; @@ -2995,7 +3018,6 @@ CModel3::~CModel3(void) DSB = NULL; } - Game = NULL; Inputs = NULL; Outputs = NULL; ram = NULL; diff --git a/Src/Model3/Model3.h b/Src/Model3/Model3.h index 6a14391..d309f3e 100644 --- a/Src/Model3/Model3.h +++ b/Src/Model3/Model3.h @@ -30,6 +30,7 @@ #include "Model3/IEmulator.h" #include "Model3/Crypto.h" +#include "Util/NewConfig.h" /* * FrameTimings @@ -47,44 +48,6 @@ struct FrameTimings UINT32 frameTicks; }; -/* - * CModel3Config: - * - * Settings used by CModel3. - */ -class CModel3Config -{ -public: - bool multiThreaded; // Multi-threaded (enabled if true) - bool gpuMultiThreaded; // Multi-threaded rendering (enabled if true) - - // PowerPC clock frequency in MHz (minimum: 1 MHz) - inline void SetPowerPCFrequency(unsigned f) - { - if ((f<1) || (f>1000)) - { - ErrorLog("PowerPC frequency must be between 1 and 1000 MHz; setting to 50 MHz."); - f = 50; - } - ppcFrequency = f*1000000; - } - inline unsigned GetPowerPCFrequency(void) - { - return ppcFrequency/1000000; - } - - // Defaults - CModel3Config(void) - { - multiThreaded = true; // enable by default - gpuMultiThreaded = true; // enable by default - ppcFrequency = 50*1000000; // 50 MHz - } - -private: - unsigned ppcFrequency; // in Hz -}; - /* * CModel3: * @@ -110,7 +73,7 @@ public: void RunFrame(void); void RenderFrame(void); void Reset(void); - const struct GameInfo * GetGameInfo(void); + const Game &GetGame(void) const; void AttachRenderers(CRender2D *Render2DPtr, IRender3D *Render3DPtr); void AttachInputs(CInputs *InputsPtr); void AttachOutputs(COutputs *OutputsPtr); @@ -131,20 +94,19 @@ public: void Write64(UINT32 addr, UINT64 data); /* - * LoadROMSet(GameList, zipFile): + * LoadGame(game, rom_set): * - * Loads a complete ROM set from the specified ZIP archive. - * - * NOTE: Command line settings will not have been applied here yet. + * Loads a game, copying in the provided ROMs and setting the hardware + * stepping. * * Parameters: - * GameList List of all supported games and their ROMs. - * zipFile ZIP file to load from. + * game Game information. + * rom_set ROMs. * * Returns: * OKAY if successful, FAIL otherwise. Prints errors. */ - bool LoadROMSet(const struct GameInfo *GameList, const char *zipFile); + bool LoadGame(const Game &game, const ROMSet &rom_set); /* * GetSoundBoard(void): @@ -181,15 +143,19 @@ public: FrameTimings GetTimings(void); /* - * CModel3(void): + * CModel3(config): * ~CModel3(void): * * Constructor and destructor for Model 3 class. Constructor performs a * bare-bones initialization of object; does not perform any memory * allocation or any actions that can fail. The destructor will deallocate * memory and free resources used by the object (and its child objects). + * + * Paramters: + * config Run-time configuration. The reference should be held because + * this changes at run-time. */ - CModel3(void); + CModel3(const Util::Config::Node &config); ~CModel3(void); /* @@ -206,7 +172,6 @@ private: void SetCROMBank(unsigned idx); UINT8 ReadSystemRegister(unsigned reg); void WriteSystemRegister(unsigned reg, UINT8 data); - void Patch(void); void RunMainBoardFrame(void); // Runs PPC main board for a frame void SyncGPUs(void); // Sync's up GPUs in preparation for rendering - must be called when PPC is not running @@ -230,8 +195,13 @@ private: int RunSoundBoardThreadSyncd(void); // Runs sound board thread (sync'd in step with render thread) int RunDriveBoardThread(void); // Runs drive board thread (sync'd in step with render thread) + // Runtime configuration + const Util::Config::Node &m_config; + bool m_multiThreaded; + bool m_gpuMultiThreaded; + // Game and hardware information - const struct GameInfo *Game; + Game m_game; // Game inputs and outputs CInputs *Inputs; diff --git a/Src/Model3/Model3GraphicsState.h b/Src/Model3/Model3GraphicsState.h index 53c290e..2a8b297 100644 --- a/Src/Model3/Model3GraphicsState.h +++ b/Src/Model3/Model3GraphicsState.h @@ -90,11 +90,18 @@ public: } } - const struct GameInfo * GetGameInfo(void) + const Game &GetGame(void) { return m_game; } + bool LoadGame(const Game &game) + { + //TODO: write me + return FAIL; + } + + //TODO: replicate this logic in LoadGame() bool LoadROMSet(const struct GameInfo *gameList, const char *zipFile) { // Load ROM diff --git a/Src/Model3/Real3D.cpp b/Src/Model3/Real3D.cpp index f0d809a..132af74 100644 --- a/Src/Model3/Real3D.cpp +++ b/Src/Model3/Real3D.cpp @@ -111,7 +111,7 @@ void CReal3D::LoadState(CBlockFile *SaveState) SaveState->Read(memoryPool, MEM_POOL_SIZE_RW); // If multi-threaded, update read-only snapshots too - if (g_Config.gpuMultiThreaded) + if (m_gpuMultiThreaded) UpdateSnapshots(true); Render3D->UploadTextures(0, 0, 0, 2048, 2048); SaveState->Read(&fifoIdx, sizeof(fifoIdx)); @@ -159,7 +159,7 @@ uint32_t CReal3D::SyncSnapshots(void) commandPortWrittenRO = commandPortWritten; commandPortWritten = false; - if (!g_Config.gpuMultiThreaded) + if (!m_gpuMultiThreaded) return 0; // Update read-only queue @@ -230,7 +230,7 @@ uint32_t CReal3D::UpdateSnapshots(bool copyWhole) void CReal3D::BeginFrame(void) { // If multi-threaded, perform now any queued texture uploads to renderer before rendering begins - if (g_Config.gpuMultiThreaded) + if (m_gpuMultiThreaded) { for (const auto &it : queuedUploadTexturesRO) { Render3D->UploadTextures(it.level, it.x, it.y, it.width, it.height); @@ -632,7 +632,7 @@ void CReal3D::StoreTexture(unsigned level, unsigned xPos, unsigned yPos, unsigne { for (uint32_t xx = 0; xx < 8; xx++) { - if (g_Config.gpuMultiThreaded) + if (m_gpuMultiThreaded) MARK_DIRTY(textureRAMDirty, destOffset * 2); textureRAM[destOffset++] = texData[decode[(yy*8+xx)^1]]; } @@ -668,11 +668,11 @@ void CReal3D::StoreTexture(unsigned level, unsigned xPos, unsigned yPos, unsigne { uint8_t byte1 = texData[decode[(yy^1)*8+((xx+0)^1)]/2]>>8; uint8_t byte2 = texData[decode[(yy^1)*8+((xx+1)^1)]/2]&0xFF; - if (g_Config.gpuMultiThreaded) + if (m_gpuMultiThreaded) MARK_DIRTY(textureRAMDirty, destOffset * 2); StoreTexelByte(&textureRAM[destOffset], byteSelect, byte1); ++destOffset; - if (g_Config.gpuMultiThreaded) + if (m_gpuMultiThreaded) MARK_DIRTY(textureRAMDirty, destOffset * 2); StoreTexelByte(&textureRAM[destOffset], byteSelect, byte2); ++destOffset; @@ -686,7 +686,7 @@ void CReal3D::StoreTexture(unsigned level, unsigned xPos, unsigned yPos, unsigne // Signal to renderer that textures have changed // TO-DO: mipmaps? What if a game writes non-mipmap textures to mipmap area? - if (g_Config.gpuMultiThreaded) + if (m_gpuMultiThreaded) { // If multi-threaded, then queue calls to UploadTextures for render thread to perform at beginning of next frame QueuedUploadTextures upl; @@ -866,21 +866,21 @@ void CReal3D::WriteTexturePort(unsigned reg, uint32_t data) void CReal3D::WriteLowCullingRAM(uint32_t addr, uint32_t data) { - if (g_Config.gpuMultiThreaded) + if (m_gpuMultiThreaded) MARK_DIRTY(cullingRAMLoDirty, addr); cullingRAMLo[addr/4] = data; } void CReal3D::WriteHighCullingRAM(uint32_t addr, uint32_t data) { - if (g_Config.gpuMultiThreaded) + if (m_gpuMultiThreaded) MARK_DIRTY(cullingRAMHiDirty, addr); cullingRAMHi[addr/4] = data; } void CReal3D::WritePolygonRAM(uint32_t addr, uint32_t data) { - if (g_Config.gpuMultiThreaded) + if (m_gpuMultiThreaded) MARK_DIRTY(polyRAMDirty, addr); polyRAM[addr/4] = data; } @@ -958,7 +958,7 @@ void CReal3D::Reset(void) dmaStatus = 0; dmaUnknownReg = 0; - unsigned memSize = (g_Config.gpuMultiThreaded ? MEMORY_POOL_SIZE : MEM_POOL_SIZE_RW); + unsigned memSize = (m_gpuMultiThreaded ? MEMORY_POOL_SIZE : MEM_POOL_SIZE_RW); memset(memoryPool, 0, memSize); memset(m_vromTextureFIFO, 0, sizeof(m_vromTextureFIFO)); @@ -974,20 +974,20 @@ void CReal3D::AttachRenderer(IRender3D *Render3DPtr) { Render3D = Render3DPtr; - // If multi-threaded, attach read-only snapshots to renderer instead of real ones - if (g_Config.gpuMultiThreaded) + // If mult-threaded, attach read-only snapshots to renderer instead of real ones + if (m_gpuMultiThreaded) Render3D->AttachMemory(cullingRAMLoRO, cullingRAMHiRO, polyRAMRO, vrom, textureRAMRO); else Render3D->AttachMemory(cullingRAMLo, cullingRAMHi, polyRAM, vrom, textureRAM); - Render3D->SetStep(step); + Render3D->SetStepping(step); DebugLog("Real3D attached a Render3D object\n"); } -void CReal3D::SetStep(int stepID) +void CReal3D::SetStepping(int stepping) { - step = stepID; + step = stepping; if ((step!=0x10) && (step!=0x15) && (step!=0x20) && (step!=0x21)) { DebugLog("Real3D: Unrecognized stepping: %d.%d\n", (step>>4)&0xF, step&0xF); @@ -1002,14 +1002,14 @@ void CReal3D::SetStep(int stepID) // Pass to renderer if (Render3D != NULL) - Render3D->SetStep(step); + Render3D->SetStepping(step); DebugLog("Real3D set to Step %d.%d\n", (step>>4)&0xF, step&0xF); } bool CReal3D::Init(const uint8_t *vromPtr, IBus *BusObjectPtr, CIRQ *IRQObjectPtr, unsigned dmaIRQBit) { - uint32_t memSize = (g_Config.gpuMultiThreaded ? MEMORY_POOL_SIZE : MEM_POOL_SIZE_RW); + uint32_t memSize = (m_config["GPUMultiThreaded"].ValueAs() ? MEMORY_POOL_SIZE : MEM_POOL_SIZE_RW); float memSizeMB = (float)memSize/(float)0x100000; // IRQ and bus objects @@ -1030,7 +1030,7 @@ bool CReal3D::Init(const uint8_t *vromPtr, IBus *BusObjectPtr, CIRQ *IRQObjectPt textureFIFO = (uint32_t *) &memoryPool[OFFSET_TEXFIFO]; // If multi-threaded, set up pointers for read-only snapshots and dirty page arrays too - if (g_Config.gpuMultiThreaded) + if (m_gpuMultiThreaded) { cullingRAMLoRO = (uint32_t *) &memoryPool[OFFSET_8C_RO]; cullingRAMHiRO = (uint32_t *) &memoryPool[OFFSET_8E_RO]; @@ -1049,7 +1049,9 @@ bool CReal3D::Init(const uint8_t *vromPtr, IBus *BusObjectPtr, CIRQ *IRQObjectPt return OKAY; } -CReal3D::CReal3D(void) +CReal3D::CReal3D(const Util::Config::Node &config) + : m_config(config), + m_gpuMultiThreaded(config["GPUMultiThreaded"].ValueAs()) { Render3D = NULL; memoryPool = NULL; @@ -1117,6 +1119,7 @@ CReal3D::~CReal3D(void) printf("unable to dump %s\n", "texram"); Util::WriteSurfaceToBMP("textures.bmp", reinterpret_cast(textureRAM), 2048, 2048, false); #endif +Util::WriteSurfaceToBMP("textures.bmp", reinterpret_cast(textureRAM), 2048, 2048, false); Render3D = NULL; if (memoryPool != NULL) diff --git a/Src/Model3/Real3D.h b/Src/Model3/Real3D.h index e340361..db63267 100644 --- a/Src/Model3/Real3D.h +++ b/Src/Model3/Real3D.h @@ -334,17 +334,17 @@ public: void AttachRenderer(IRender3D *Render3DPtr); /* - * SetStep(stepID): + * SetStepping(stepping): * * Sets the Model 3 hardware stepping, which also determines the Real3D * functionality. The default is Step 1.0. This should be called prior to * any other emulation functions and after Init(). * * Parameters: - * stepID 0x10 for Step 1.0, 0x15 for Step 1.5, 0x20 for Step 2.0, - * or 0x21 for Step 2.1. Anything else defaults to 1.0. + * stepping 0x10 for Step 1.0, 0x15 for Step 1.5, 0x20 for Step 2.0, or + * 0x21 for Step 2.1. Anything else defaults to 1.0. */ - void SetStep(int stepID); + void SetStepping(int stepping); /* * Init(vromPtr, BusObjectPtr, IRQObjectPtr, dmaIRQBit): @@ -370,12 +370,16 @@ public: bool Init(const uint8_t *vromPtr, IBus *BusObjectPtr, CIRQ *IRQObjectPtr, unsigned dmaIRQBit); /* - * CReal3D(void): + * CReal3D(config): * ~CReal3D(void): * * Constructor and destructor. + * + * Paramters: + * config Run-time configuration. The reference should be held because + * this changes at run-time. */ - CReal3D(void); + CReal3D(const Util::Config::Node &config); ~CReal3D(void); private: @@ -389,6 +393,10 @@ private: uint32_t UpdateSnapshots(bool copyWhole); uint32_t UpdateSnapshot(bool copyWhole, uint8_t *src, uint8_t *dst, unsigned size, uint8_t *dirty); + // Config + const Util::Config::Node &m_config; + const bool m_gpuMultiThreaded; + // Renderer attached to the Real3D IRender3D *Render3D; diff --git a/Src/Model3/SoundBoard.cpp b/Src/Model3/SoundBoard.cpp index 2234865..54b9cbd 100644 --- a/Src/Model3/SoundBoard.cpp +++ b/Src/Model3/SoundBoard.cpp @@ -338,7 +338,7 @@ void CSoundBoard::WriteMIDIPort(UINT8 data) bool CSoundBoard::RunFrame(void) { // Run sound board first to generate SCSP audio - if (g_Config.emulateSound) + if (m_config["EmulateSound"].ValueAs()) { M68KSetContext(&M68K); SCSP_Update(); @@ -355,7 +355,7 @@ bool CSoundBoard::RunFrame(void) DSB->RunFrame(audioL, audioR); // Output the audio buffers - bool bufferFull = OutputAudio(44100/60, audioL, audioR); + bool bufferFull = OutputAudio(44100/60, audioL, audioR, m_config["FlipStereo"].ValueAs()); #ifdef SUPERMODEL_LOG_AUDIO // Output to binary file @@ -478,7 +478,7 @@ bool CSoundBoard::Init(const UINT8 *soundROMPtr, const UINT8 *sampleROMPtr) // Initialize SCSPs SCSP_SetBuffers(audioL, audioR, 44100/60); SCSP_SetCB(SCSP68KRunCallback, SCSP68KIRQCallback); - if (OKAY != SCSP_Init(2)) + if (OKAY != SCSP_Init(m_config, 2)) return FAIL; SCSP_SetRAM(0, ram1); SCSP_SetRAM(1, ram2); @@ -503,7 +503,8 @@ CDSB *CSoundBoard::GetDSB(void) return DSB; } -CSoundBoard::CSoundBoard(void) +CSoundBoard::CSoundBoard(const Util::Config::Node &config) + : m_config(config) { DSB = NULL; memoryPool = NULL; diff --git a/Src/Model3/SoundBoard.h b/Src/Model3/SoundBoard.h index bebe57b..f840d12 100644 --- a/Src/Model3/SoundBoard.h +++ b/Src/Model3/SoundBoard.h @@ -33,50 +33,6 @@ #include "Model3/DSB.h" #include "OSD/Thread.h" -/* - * CSoundBoardConfig: - * - * Settings used by CSoundBoard. - */ -class CSoundBoardConfig -{ -public: - bool emulateSound; // sound board emulation (enabled if true) - - // Master/slave SCSP relative balance (-100-100, with 100 meaning master volume doubled, slave silenced) - inline void SetSCSPBalance(int bal) - { - if (bal > 100) - { - ErrorLog("Front/rear balance cannot exceed 100%%; setting to 100%%.\n"); - bal = 100; - } - - if (bal < -100) - { - ErrorLog("Front/rear balance cannot be less than -100%%; setting to -100%%.\n"); - bal = -100; - } - - scspBalance = bal; - } - - inline int GetSCSPBalance(void) - { - return scspBalance; - } - - // Defaults - CSoundBoardConfig(void) - { - emulateSound = true; - scspBalance = 0; - } - -private: - int scspBalance; -}; - /* * CSoundBoard: * @@ -211,18 +167,25 @@ public: bool Init(const UINT8 *soundROMPtr, const UINT8 *sampleROMPtr); /* - * CSoundBoard(void): + * CSoundBoard(config): * ~CSoundBoard(void): * * Constructor and destructor. + * + * Paramters: + * config Run-time configuration. The reference should be held because + * this changes at run-time. */ - CSoundBoard(void); + CSoundBoard(const Util::Config::Node &config); ~CSoundBoard(void); private: // Private helper functions void UpdateROMBanks(void); + // Config + const Util::Config::Node &m_config; + // Digital Sound Board CDSB *DSB; diff --git a/Src/Model3/TileGen.cpp b/Src/Model3/TileGen.cpp index b50c01a..8203e1d 100644 --- a/Src/Model3/TileGen.cpp +++ b/Src/Model3/TileGen.cpp @@ -111,7 +111,7 @@ void CTileGen::LoadState(CBlockFile *SaveState) RecomputePalettes(); // If multi-threaded, update read-only snapshots too - if (g_Config.gpuMultiThreaded) + if (m_gpuMultiThreaded) UpdateSnapshots(true); } @@ -144,7 +144,7 @@ void CTileGen::EndVBlank(void) void CTileGen::RecomputePalettes(void) { // Writing the colors forces palettes to be computed - if (g_Config.gpuMultiThreaded) + if (m_gpuMultiThreaded) { for (unsigned colorAddr = 0; colorAddr < 32768*4; colorAddr += 4 ) { @@ -169,7 +169,7 @@ UINT32 CTileGen::SyncSnapshots(void) recomputePalettes = false; } - if (!g_Config.gpuMultiThreaded) + if (!m_gpuMultiThreaded) return 0; // Update read-only snapshots @@ -274,7 +274,7 @@ UINT32 CTileGen::ReadRAM32(unsigned addr) void CTileGen::WriteRAM32(unsigned addr, UINT32 data) { - if (g_Config.gpuMultiThreaded) + if (m_gpuMultiThreaded) MARK_DIRTY(vramDirty, addr); *(UINT32 *) &vram[addr] = data; @@ -285,7 +285,7 @@ void CTileGen::WriteRAM32(unsigned addr, UINT32 data) unsigned color = addr/4; // color index // Same address in both palettes must be marked dirty - if (g_Config.gpuMultiThreaded) + if (m_gpuMultiThreaded) { MARK_DIRTY(palDirty[0], addr); MARK_DIRTY(palDirty[1], addr); @@ -333,7 +333,7 @@ void CTileGen::InitPalette(void) for (int i = 0; i < 0x20000/4; i++) { WritePalette(i, *(UINT32 *) &vram[0x100000 + i*4]); - if (g_Config.gpuMultiThreaded) + if (m_gpuMultiThreaded) { palRO[0][i] = pal[0][i]; palRO[1][i] = pal[1][i]; @@ -444,7 +444,7 @@ void CTileGen::WriteRegister(unsigned reg, UINT32 data) void CTileGen::Reset(void) { - unsigned memSize = (g_Config.gpuMultiThreaded ? MEMORY_POOL_SIZE : MEM_POOL_SIZE_RW); + unsigned memSize = (m_gpuMultiThreaded ? MEMORY_POOL_SIZE : MEM_POOL_SIZE_RW); memset(memoryPool, 0, memSize); memset(regs, 0, sizeof(regs)); memset(regsRO, 0, sizeof(regsRO)); @@ -465,7 +465,7 @@ void CTileGen::AttachRenderer(CRender2D *Render2DPtr) Render2D = Render2DPtr; // If multi-threaded, attach read-only snapshots to renderer instead of real ones - if (g_Config.gpuMultiThreaded) + if (m_gpuMultiThreaded) { Render2D->AttachVRAM(vramRO); Render2D->AttachPalette((const UINT32 **)palRO); @@ -484,7 +484,7 @@ void CTileGen::AttachRenderer(CRender2D *Render2DPtr) bool CTileGen::Init(CIRQ *IRQObjectPtr) { - unsigned memSize = (g_Config.gpuMultiThreaded ? MEMORY_POOL_SIZE : MEM_POOL_SIZE_RW); + unsigned memSize = (m_gpuMultiThreaded ? MEMORY_POOL_SIZE : MEM_POOL_SIZE_RW); float memSizeMB = (float)memSize/(float)0x100000; // Allocate all memory for all TileGen RAM regions @@ -498,7 +498,7 @@ bool CTileGen::Init(CIRQ *IRQObjectPtr) pal[1] = (UINT32 *) &memoryPool[OFFSET_PAL_B]; // If multi-threaded, set up pointers for read-only snapshots and dirty page arrays too - if (g_Config.gpuMultiThreaded) + if (m_gpuMultiThreaded) { vramRO = (UINT8 *) &memoryPool[OFFSET_VRAM_RO]; palRO[0] = (UINT32 *) &memoryPool[OFFSET_PAL_RO_A]; @@ -515,7 +515,9 @@ bool CTileGen::Init(CIRQ *IRQObjectPtr) return OKAY; } -CTileGen::CTileGen(void) +CTileGen::CTileGen(const Util::Config::Node &config) + : m_config(config), + m_gpuMultiThreaded(config["GPUMultiThreaded"].ValueAs()) { IRQ = NULL; memoryPool = NULL; diff --git a/Src/Model3/TileGen.h b/Src/Model3/TileGen.h index 85e782b..44b9999 100644 --- a/Src/Model3/TileGen.h +++ b/Src/Model3/TileGen.h @@ -238,12 +238,16 @@ public: bool Init(CIRQ *IRQObjectPtr); /* - * CTileGen(void): + * CTileGen(config): * ~CTileGen(void): * * Constructor and destructor. + * + * Paramters: + * config Run-time configuration. The reference should be held because + * this changes at run-time. */ - CTileGen(void); + CTileGen(const Util::Config::Node &config); ~CTileGen(void); private: @@ -253,7 +257,10 @@ private: void WritePalette(unsigned color, UINT32 data); UINT32 UpdateSnapshots(bool copyWhole); UINT32 UpdateSnapshot(bool copyWhole, UINT8 *src, UINT8 *dst, unsigned size, UINT8 *dirty); - + + const Util::Config::Node &m_config; + const bool m_gpuMultiThreaded; + CIRQ *IRQ; // IRQ controller the tile generator is attached to CRender2D *Render2D; // 2D renderer the tile generator is attached to diff --git a/Src/OSD/Audio.h b/Src/OSD/Audio.h index 5ff0c13..ccfbc57 100755 --- a/Src/OSD/Audio.h +++ b/Src/OSD/Audio.h @@ -46,7 +46,7 @@ extern bool OpenAudio(); * * Sends a chunk of two-channel audio with the given number of samples to the audio system. */ -extern bool OutputAudio(unsigned numSamples, INT16 *leftBuffer, INT16 *rightBuffer); +extern bool OutputAudio(unsigned numSamples, INT16 *leftBuffer, INT16 *rightBuffer, bool flipStereo); /* * CloseAudio() diff --git a/Src/OSD/Outputs.cpp b/Src/OSD/Outputs.cpp index 160575e..a0a452b 100755 --- a/Src/OSD/Outputs.cpp +++ b/Src/OSD/Outputs.cpp @@ -67,12 +67,12 @@ COutputs::~COutputs() // } -const GameInfo *COutputs::GetGame() const +const Game &COutputs::GetGame() const { return m_game; } -void COutputs::SetGame(const GameInfo *game) +void COutputs::SetGame(const Game &game) { m_game = game; } diff --git a/Src/OSD/Outputs.h b/Src/OSD/Outputs.h index 83117ae..203f23e 100755 --- a/Src/OSD/Outputs.h +++ b/Src/OSD/Outputs.h @@ -1,55 +1,55 @@ -/** - ** Supermodel - ** A Sega Model 3 Arcade Emulator. - ** Copyright 2011 Bart Trzynadlowski, Nik Henson - ** - ** This file is part of Supermodel. - ** - ** Supermodel 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 (at your option) - ** any later version. - ** - ** Supermodel 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 Supermodel. If not, see . - **/ - -/* - * Outputs.h - * - * Base class for outputs. - */ - +/** + ** Supermodel + ** A Sega Model 3 Arcade Emulator. + ** Copyright 2011 Bart Trzynadlowski, Nik Henson + ** + ** This file is part of Supermodel. + ** + ** Supermodel 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 (at your option) + ** any later version. + ** + ** Supermodel 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 Supermodel. If not, see . + **/ + +/* + * Outputs.h + * + * Base class for outputs. + */ + #ifndef INCLUDED_OUTPUTS_H #define INCLUDED_OUTPUTS_H - -/* - * EOutputs enumeration of all available outputs. - * Currently just contains the outputs for the driving games - more will need to be added for the other games. - */ -enum EOutputs -{ - OutputUnknown = -1, - OutputPause = 0, - OutputLampStart, - OutputLampView1, - OutputLampView2, - OutputLampView3, - OutputLampView4, - OutputLampLeader, - OutputRawDrive, - OutputRawLamps -}; - -#define NUM_OUTPUTS 9 - -struct GameInfo; - + +#include "Game.h" + +/* + * EOutputs enumeration of all available outputs. + * Currently just contains the outputs for the driving games - more will need to be added for the other games. + */ +enum EOutputs +{ + OutputUnknown = -1, + OutputPause = 0, + OutputLampStart, + OutputLampView1, + OutputLampView2, + OutputLampView3, + OutputLampView4, + OutputLampLeader, + OutputRawDrive, + OutputRawLamps +}; + +#define NUM_OUTPUTS 9 + class COutputs { public: @@ -95,14 +95,14 @@ public: * * Returns the currently running game. */ - const GameInfo *GetGame() const; + const Game &GetGame() const; /* * SetGame(game): * * Sets the currently running game. */ - void SetGame(const GameInfo *game); + void SetGame(const Game &game); /* * GetValue(output): @@ -137,7 +137,7 @@ protected: private: static const char* s_outputNames[]; // Static array of output names - const GameInfo *m_game; // Currently running game + Game m_game; // Currently running game bool m_first[NUM_OUTPUTS]; // For each output, true if an initial value has been set UINT8 m_values[NUM_OUTPUTS]; // Current value of each output }; diff --git a/Src/OSD/SDL/Audio.cpp b/Src/OSD/SDL/Audio.cpp index 6924227..8811727 100755 --- a/Src/OSD/SDL/Audio.cpp +++ b/Src/OSD/SDL/Audio.cpp @@ -190,7 +190,7 @@ static void PlayCallback(void *data, Uint8 *stream, int len) callback(callbackData); } -static void MixChannels(unsigned numSamples, INT16 *leftBuffer, INT16 *rightBuffer, void *dest) +static void MixChannels(unsigned numSamples, INT16 *leftBuffer, INT16 *rightBuffer, void *dest, bool flipStereo) { INT16 *p = (INT16*)dest; @@ -198,7 +198,7 @@ static void MixChannels(unsigned numSamples, INT16 *leftBuffer, INT16 *rightBuff for (unsigned i = 0; i < numSamples; i++) *p++ = leftBuffer[i] + rightBuffer[i]; // TODO: these should probably be clipped! #else - if (g_Config.flipStereo) // swap left and right channels + if (flipStereo) // swap left and right channels { for (unsigned i = 0; i < numSamples; i++) { @@ -280,7 +280,7 @@ bool OpenAudio() return OKAY; } -bool OutputAudio(unsigned numSamples, INT16 *leftBuffer, INT16 *rightBuffer) +bool OutputAudio(unsigned numSamples, INT16 *leftBuffer, INT16 *rightBuffer, bool flipStereo) { //printf("OutputAudio(%u) [writePos = %u, writeWrapped = %s, playPos = %u, audioBufferSize = %u]\n", // numSamples, writePos, (writeWrapped ? "true" : "false"), playPos, audioBufferSize); @@ -295,7 +295,7 @@ bool OutputAudio(unsigned numSamples, INT16 *leftBuffer, INT16 *rightBuffer) // Mix together left and right channels into single chunk of data INT16 mixBuffer[NUM_CHANNELS * SAMPLES_PER_FRAME]; - MixChannels(numSamples, leftBuffer, rightBuffer, mixBuffer); + MixChannels(numSamples, leftBuffer, rightBuffer, mixBuffer, flipStereo); // Lock SDL audio callback so that it doesn't interfere with following code SDL_LockAudio(); diff --git a/Src/OSD/SDL/Main.cpp b/Src/OSD/SDL/Main.cpp index 46ea505..2d5c33e 100644 --- a/Src/OSD/SDL/Main.cpp +++ b/Src/OSD/SDL/Main.cpp @@ -26,6 +26,14 @@ * * To Do Before Next Release * ------------------------- + * - Thoroughly test config system (do overrides work as expected? XInput + * force settings?) + * - Make sure fragment and vertex shaders are configurable for 3D (and 2D?) + * - Remove all occurrences of "using namespace std" from Nik's code. + * - Standardize variable naming (recently introduced vars_like_this should be + * converted back to varsLikeThis). + * - Update save state file revision (strings > 1024 chars are now supported). + * - Fix BlockFile.cpp to use fstream! * - Check to make sure save states use explicitly-sized types for 32/64-bit * compatibility (i.e., size_t, int, etc. not allowed). * - Make sure quitting while paused works. @@ -57,26 +65,38 @@ #include "Supermodel.h" #include "Util/Format.h" +#include "Util/NewConfig.h" +#include "Util/ConfigBuilders.h" +#include "GameLoader.h" #include "SDLInputSystem.h" #ifdef SUPERMODEL_WIN32 #include "DirectInputSystem.h" #include "WinOutputs.h" #endif +#include + // Log file names #define DEBUG_LOG_FILE "debug.log" #define ERROR_LOG_FILE "error.log" +/****************************************************************************** + Global Run-time Config +******************************************************************************/ + +static Util::Config::Node s_runtime_config("Global"); + + /****************************************************************************** Display Management ******************************************************************************/ /* * Position and size of rectangular region within OpenGL display to render to. - * Unlike the g_Config object, these end up containing the actual resolution - * (and computed offsets within the viewport) that will be rendered based on - * what was obtained from SDL. + * Unlike the config tree, these end up containing the actual resolution (and + * computed offsets within the viewport) that will be rendered based on what + * was obtained from SDL. */ static unsigned xOffset, yOffset; // offset of renderer output within OpenGL viewport static unsigned xRes, yRes; // renderer output resolution (can be smaller than GL viewport) @@ -141,7 +161,7 @@ static bool SetGLGeometry(unsigned *xOffsetPtr, unsigned *yOffsetPtr, unsigned * glEnable(GL_SCISSOR_TEST); // Scissor box (to clip visible area) - if (g_Config.wideScreen) + if (s_runtime_config["WideScreen"].ValueAsDefault(false)) { glScissor(0, correction, *totalXResPtr, *totalYResPtr - (correction * 2)); } @@ -180,7 +200,7 @@ static bool CreateGLScreen(const char *caption, unsigned *xOffsetPtr, unsigned * SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1); // Set vsync - SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, (g_Config.vsync ? 1 : 0)); + SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, s_runtime_config["VSync"].ValueAsDefault(false) ? 1 : 0); // Set video mode if (SDL_SetVideoMode(*xResPtr,*yResPtr,0,SDL_OPENGL|(fullScreen?SDL_FULLSCREEN|SDL_HWSURFACE:0)) == NULL) @@ -461,197 +481,6 @@ static void TestPolygonHeaderBits(IEmulator *Emu) #endif -/****************************************************************************** - Configuration - - Configuration file management and input settings. -******************************************************************************/ - -static const char s_configFilePath[] = { "Config/Supermodel.ini" }; - -// Create and configure inputs -static bool ConfigureInputs(CInputs *Inputs, bool configure) -{ - static const char configFileComment[] = { - ";\n" - "; Supermodel Configuration File\n" - ";\n" - }; - - // Open and parse configuration file - CINIFile INI; - INI.Open(s_configFilePath); // doesn't matter if it exists or not, will get overwritten - INI.SetDefaultSectionName("Global"); - INI.Parse(); - - Inputs->ReadFromINIFile(&INI, "Global"); - - // If the user wants to configure the inputs, do that now - if (configure) - { - // Open an SDL window - unsigned xOffset, yOffset, xRes=496, yRes=384; - if (OKAY != CreateGLScreen("Supermodel - Configuring Inputs...", &xOffset, &yOffset, &xRes, &yRes, &totalXRes, &totalYRes, false, false)) - return (bool) ErrorLog("Unable to start SDL to configure inputs.\n"); - - // Configure the inputs - if (Inputs->ConfigureInputs(NULL, xOffset, yOffset, xRes, yRes)) - { - // Write input configuration and input system settings to config file - Inputs->WriteToINIFile(&INI, "Global"); - - if (OKAY != INI.Write(configFileComment)) - ErrorLog("Unable to save configuration to '%s'.", s_configFilePath); - else - printf("Configuration successfully saved to '%s'.\n", s_configFilePath); - } - else - puts("Configuration aborted..."); - puts(""); - } - - INI.Close(); - return OKAY; -} - -// Apply configuration settings from configuration file (does NOT read input settings; see ConfigureInputs()) -static void ApplySettings(CINIFile *INI, const char *section) -{ - unsigned x; - int y; - string String; - - // Model 3 - INI->Get(section, "MultiThreaded", g_Config.multiThreaded); - INI->Get(section, "GPUMultiThreaded", g_Config.gpuMultiThreaded); - if (OKAY == INI->Get(section, "PowerPCFrequency", x)) - g_Config.SetPowerPCFrequency(x); - - // 3D renderer - INI->Get(section, "VertexShader", g_Config.vertexShaderFile); - INI->Get(section, "FragmentShader", g_Config.fragmentShaderFile); - - // SCSP and DSB - if (OKAY == INI->Get(section, "SoundVolume", x)) - g_Config.SetSoundVolume(x); - if (OKAY == INI->Get(section, "MusicVolume", x)) - g_Config.SetMusicVolume(x); - if (OKAY == INI->Get(section, "Balance", y)) - g_Config.SetSCSPBalance(y); - INI->Get(section, "EmulateSound", g_Config.emulateSound); - INI->Get(section, "EmulateDSB", g_Config.emulateDSB); - - // Drive board -#ifdef SUPERMODEL_WIN32 - INI->Get(section, "ForceFeedback", g_Config.forceFeedback); -#endif // SUPERMODEL_WIN32 - - // OSD - INI->Get(section, "New3DEngine", g_Config.new3DEngine); - INI->Get(section, "XResolution", g_Config.xRes); - INI->Get(section, "YResolution", g_Config.yRes); - INI->Get(section, "FullScreen", g_Config.fullScreen); - INI->Get(section, "WideScreen", g_Config.wideScreen); - INI->Get(section, "MultiTexture", g_Config.multiTexture); - INI->Get(section, "VSync", g_Config.vsync); - INI->Get(section, "Throttle", g_Config.throttle); - INI->Get(section, "ShowFrameRate", g_Config.showFPS); - INI->Get(section, "Crosshairs", g_Config.crosshairs); - INI->Get(section, "FlipStereo", g_Config.flipStereo); - -#ifdef SUPERMODEL_WIN32 - // DirectInput ForceFeedback - INI->Get(section, "DirectInputConstForceMax", g_Config.dInputConstForceLeftMax); - INI->Get(section, "DirectInputConstForceMax", g_Config.dInputConstForceRightMax); - INI->Get(section, "DirectInputConstForceLeftMax", g_Config.dInputConstForceLeftMax); - INI->Get(section, "DirectInputConstForceRightMax", g_Config.dInputConstForceRightMax); - INI->Get(section, "DirectInputSelfCenterMax", g_Config.dInputSelfCenterMax); - INI->Get(section, "DirectInputFrictionMax", g_Config.dInputFrictionMax); - INI->Get(section, "DirectInputVibrateMax", g_Config.dInputVibrateMax); - - // XInput ForceFeedback - INI->Get(section, "XInputConstForceThreshold", g_Config.xInputConstForceThreshold); - INI->Get(section, "XInputConstForceMax", g_Config.xInputConstForceMax); - INI->Get(section, "XInputVibrateMax", g_Config.xInputVibrateMax); -#endif // SUPERMODEL_WIN32 -} - -// Read settings (from a specific section) from the config file -static void ReadConfigFile(const char *section) -{ - CINIFile INI; - - INI.Open(s_configFilePath); - INI.SetDefaultSectionName("Global"); // required to read settings not associated with a specific section - INI.Parse(); - ApplySettings(&INI, section); - INI.Close(); -} - -// Log the configuration to info log -static void LogConfig(void) -{ - InfoLog("Program settings:"); - - // COSDConfig - InfoLog("\tNew3DEngine = %d", g_Config.new3DEngine); - InfoLog("\tXResolution = %d", g_Config.xRes); - InfoLog("\tYResolution = %d", g_Config.yRes); - InfoLog("\tFullScreen = %d", g_Config.fullScreen); - InfoLog("\tWideScreen = %d", g_Config.wideScreen); - InfoLog("\tVSync = %d", g_Config.vsync); - InfoLog("\tMultiTexture = %d", g_Config.multiTexture); - InfoLog("\tThrottle = %d", g_Config.throttle); - InfoLog("\tShowFrameRate = %d", g_Config.showFPS); - InfoLog("\tCrosshairs = %d", g_Config.crosshairs); -#ifdef SUPERMODEL_DEBUGGER - InfoLog("\tDisableDebugger = %d", g_Config.disableDebugger); -#endif - InfoLog("\tInputSystem = %s", g_Config.GetInputSystem()); - InfoLog("\tOutputs = %s", g_Config.GetOutputs()); - InfoLog("\tFlipStereo = %d", g_Config.flipStereo); - -#ifdef SUPERMODEL_WIN32 - // DirectInput ForceFeedback - InfoLog("\tDirectInputConstForceLeftMax = %u", g_Config.dInputConstForceLeftMax); - InfoLog("\tDirectInputConstForceRightMax = %u", g_Config.dInputConstForceRightMax); - InfoLog("\tDirectInputSelfCenterMax = %u", g_Config.dInputSelfCenterMax); - InfoLog("\tDirectInputFrictionMax = %u", g_Config.dInputFrictionMax); - InfoLog("\tDirectInputVibrateMax = %u", g_Config.dInputVibrateMax); - - // XInput ForceFeedback - InfoLog("\tXInputConstForceThreshold = %u", g_Config.xInputConstForceThreshold); - InfoLog("\tXInputConstForceMax = %u", g_Config.xInputConstForceMax); - InfoLog("\tXInputVibrateMax = %u", g_Config.xInputVibrateMax); -#endif // SUPERMODEL_WIN32 - - // CModel3Config - InfoLog("\tMultiThreaded = %d", g_Config.multiThreaded); - InfoLog("\tGPUMultiThreaded = %d", g_Config.gpuMultiThreaded); - InfoLog("\tPowerPCFrequency = %d", g_Config.GetPowerPCFrequency()); - - // CSoundBoardConfig - InfoLog("\tEmulateSound = %d", g_Config.emulateSound); - InfoLog("\tBalance = %d", g_Config.GetSCSPBalance()); - - // CDSBConfig - InfoLog("\tEmulateDSB = %d", g_Config.emulateDSB); - InfoLog("\tSoundVolume = %d", g_Config.GetSoundVolume()); - InfoLog("\tMusicVolume = %d", g_Config.GetMusicVolume()); - - // CDriveBoardConfig -#ifdef SUPERMODEL_WIN32 - InfoLog("\tForceFeedback = %d", g_Config.forceFeedback); -#endif - - // CLegacy3DConfig - InfoLog("\tVertexShader = %s", g_Config.vertexShaderFile.c_str()); - InfoLog("\tFragmentShader = %s", g_Config.fragmentShaderFile.c_str()); - - InfoLog(""); -} - - /****************************************************************************** Save States and NVRAM @@ -674,24 +503,23 @@ static void SaveState(IEmulator *Model3) { CBlockFile SaveState; - char filePath[24]; - sprintf(filePath, "Saves/%s.st%d", Model3->GetGameInfo()->id, s_saveSlot); - if (OKAY != SaveState.Create(filePath, "Supermodel Save State", "Supermodel Version " SUPERMODEL_VERSION)) + std::string file_path = Util::Format() << "Saves/" << Model3->GetGame().name << ".st" << s_saveSlot; + if (OKAY != SaveState.Create(file_path, "Supermodel Save State", "Supermodel Version " SUPERMODEL_VERSION)) { - ErrorLog("Unable to save state to '%s'.", filePath); + ErrorLog("Unable to save state to '%s'.", file_path.c_str()); return; } // Write file format version and ROM set ID to header block int32_t fileVersion = STATE_FILE_VERSION; SaveState.Write(&fileVersion, sizeof(fileVersion)); - SaveState.Write(Model3->GetGameInfo()->id, strlen(Model3->GetGameInfo()->id)+1); + SaveState.Write(Model3->GetGame().name); // Save state Model3->SaveState(&SaveState); SaveState.Close(); - printf("Saved state to '%s'.\n", filePath); - DebugLog("Saved state to '%s'.\n", filePath); + printf("Saved state to '%s'.\n", file_path.c_str()); + DebugLog("Saved state to '%s'.\n", file_path.c_str()); } static void LoadState(IEmulator *Model3) @@ -699,19 +527,18 @@ static void LoadState(IEmulator *Model3) CBlockFile SaveState; // Generate file path - char filePath[24]; - sprintf(filePath, "Saves/%s.st%d", Model3->GetGameInfo()->id, s_saveSlot); + std::string file_path = Util::Format() << "Saves/" << Model3->GetGame().name << ".st" << s_saveSlot; // Open and check to make sure format is correct - if (OKAY != SaveState.Load(filePath)) + if (OKAY != SaveState.Load(file_path)) { - ErrorLog("Unable to load state from '%s'.", filePath); + ErrorLog("Unable to load state from '%s'.", file_path.c_str()); return; } if (OKAY != SaveState.FindBlock("Supermodel Save State")) { - ErrorLog("'%s' does not appear to be a valid save state file.", filePath); + ErrorLog("'%s' does not appear to be a valid save state file.", file_path.c_str()); return; } @@ -719,38 +546,37 @@ static void LoadState(IEmulator *Model3) SaveState.Read(&fileVersion, sizeof(fileVersion)); if (fileVersion != STATE_FILE_VERSION) { - ErrorLog("'%s' is incompatible with this version of Supermodel.", filePath); + ErrorLog("'%s' is incompatible with this version of Supermodel.", file_path.c_str()); return; } // Load Model3->LoadState(&SaveState); SaveState.Close(); - printf("Loaded state from '%s'.\n", filePath); - DebugLog("Loaded state from '%s'.\n", filePath); + printf("Loaded state from '%s'.\n", file_path.c_str()); + DebugLog("Loaded state from '%s'.\n", file_path.c_str()); } static void SaveNVRAM(IEmulator *Model3) { CBlockFile NVRAM; - char filePath[24]; - sprintf(filePath, "NVRAM/%s.nv", Model3->GetGameInfo()->id); - if (OKAY != NVRAM.Create(filePath, "Supermodel NVRAM State", "Supermodel Version " SUPERMODEL_VERSION)) + std::string file_path = Util::Format() << "NVRAM/" << Model3->GetGame().name << ".nv"; + if (OKAY != NVRAM.Create(file_path, "Supermodel NVRAM State", "Supermodel Version " SUPERMODEL_VERSION)) { - ErrorLog("Unable to save NVRAM to '%s'. Make sure directory exists!", filePath); + ErrorLog("Unable to save NVRAM to '%s'. Make sure directory exists!", file_path.c_str()); return; } // Write file format version and ROM set ID to header block int32_t fileVersion = NVRAM_FILE_VERSION; NVRAM.Write(&fileVersion, sizeof(fileVersion)); - NVRAM.Write(Model3->GetGameInfo()->id, strlen(Model3->GetGameInfo()->id)+1); + NVRAM.Write(Model3->GetGame().name); // Save NVRAM Model3->SaveNVRAM(&NVRAM); NVRAM.Close(); - DebugLog("Saved NVRAM to '%s'.\n", filePath); + DebugLog("Saved NVRAM to '%s'.\n", file_path.c_str()); } static void LoadNVRAM(IEmulator *Model3) @@ -758,11 +584,10 @@ static void LoadNVRAM(IEmulator *Model3) CBlockFile NVRAM; // Generate file path - char filePath[24]; - sprintf(filePath, "NVRAM/%s.nv", Model3->GetGameInfo()->id); + std::string file_path = Util::Format() << "NVRAM/" << Model3->GetGame().name << ".nv"; // Open and check to make sure format is correct - if (OKAY != NVRAM.Load(filePath)) + if (OKAY != NVRAM.Load(file_path)) { //ErrorLog("Unable to restore NVRAM from '%s'.", filePath); return; @@ -770,7 +595,7 @@ static void LoadNVRAM(IEmulator *Model3) if (OKAY != NVRAM.FindBlock("Supermodel NVRAM State")) { - ErrorLog("'%s' does not appear to be a valid NVRAM file.", filePath); + ErrorLog("'%s' does not appear to be a valid NVRAM file.", file_path.c_str()); return; } @@ -778,14 +603,14 @@ static void LoadNVRAM(IEmulator *Model3) NVRAM.Read(&fileVersion, sizeof(fileVersion)); if (fileVersion != NVRAM_FILE_VERSION) { - ErrorLog("'%s' is incompatible with this version of Supermodel.", filePath); + ErrorLog("'%s' is incompatible with this version of Supermodel.", file_path.c_str()); return; } // Load Model3->LoadNVRAM(&NVRAM); NVRAM.Close(); - DebugLog("Loaded NVRAM from '%s'.\n", filePath); + DebugLog("Loaded NVRAM from '%s'.\n", file_path.c_str()); } @@ -896,7 +721,7 @@ void EndFrameVideo() { // Show crosshairs for light gun games if (videoInputs) - UpdateCrosshairs(videoInputs, g_Config.crosshairs); + UpdateCrosshairs(videoInputs, s_runtime_config["Crosshairs"].ValueAs()); // Swap the buffers SDL_GL_SwapBuffers(); @@ -904,12 +729,12 @@ void EndFrameVideo() static void SuperSleep(UINT32 time) { - UINT32 start = SDL_GetTicks(); - UINT32 tics = start; + UINT32 start = SDL_GetTicks(); + UINT32 tics = start; - while (start + time > tics) { - tics = SDL_GetTicks(); - } + while (start + time > tics) { + tics = SDL_GetTicks(); + } } /****************************************************************************** @@ -917,29 +742,26 @@ static void SuperSleep(UINT32 time) ******************************************************************************/ #ifdef SUPERMODEL_DEBUGGER -int Supermodel(const char *zipFile, IEmulator *Model3, CInputs *Inputs, COutputs *Outputs, Debugger::CDebugger *Debugger, CINIFile *CmdLine) +int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *Inputs, COutputs *Outputs, Debugger::CDebugger *Debugger) { CLogger *oldLogger = 0; #else -int Supermodel(const char *zipFile, IEmulator *Model3, CInputs *Inputs, COutputs *Outputs, CINIFile *CmdLine) +int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *Inputs, COutputs *Outputs) { #endif // SUPERMODEL_DEBUGGER unsigned prevFPSTicks; - unsigned fpsFramesElapsed; - bool gameHasLightguns = false; - bool quit = false; - bool paused = false; - bool dumpTimings = false; + unsigned fpsFramesElapsed; + bool gameHasLightguns = false; + bool quit = false; + bool paused = false; + bool dumpTimings = false; // Initialize and load ROMs if (OKAY != Model3->Init()) return 1; - if (OKAY != Model3->LoadROMSet(g_Model3GameList, zipFile)) + if (Model3->LoadGame(game, *rom_set)) return 1; - - // Apply game-specific settings and then, lastly, command line settings - ReadConfigFile(Model3->GetGameInfo()->id); - ApplySettings(CmdLine, "Global"); + *rom_set = ROMSet(); // free up this memory we won't need anymore // Load NVRAM LoadNVRAM(Model3); @@ -947,23 +769,22 @@ int Supermodel(const char *zipFile, IEmulator *Model3, CInputs *Inputs, COutputs // Start up SDL and open a GL window char baseTitleStr[128]; char titleStr[128]; - totalXRes = xRes = g_Config.xRes; - totalYRes = yRes = g_Config.yRes; - sprintf(baseTitleStr, "Supermodel - %s", Model3->GetGameInfo()->title); - if (OKAY != CreateGLScreen(baseTitleStr, &xOffset, &yOffset ,&xRes, &yRes, &totalXRes, &totalYRes, true, g_Config.fullScreen)) + totalXRes = xRes = s_runtime_config["XResolution"].ValueAs(); + totalYRes = yRes = s_runtime_config["YResolution"].ValueAs(); + sprintf(baseTitleStr, "Supermodel - %s", game.title.c_str()); + if (OKAY != CreateGLScreen(baseTitleStr, &xOffset, &yOffset ,&xRes, &yRes, &totalXRes, &totalYRes, true, s_runtime_config["FullScreen"].ValueAs())) return 1; - - // Info log GL information and user options + + // Info log GL information PrintGLInfo(false, true, false); - LogConfig(); // Initialize audio system if (OKAY != OpenAudio()) return 1; // Hide mouse if fullscreen, enable crosshairs for gun games - Inputs->GetInputSystem()->SetMouseVisibility(!g_Config.fullScreen); - gameHasLightguns = !!(Model3->GetGameInfo()->inputFlags & (GAME_INPUT_GUN1|GAME_INPUT_GUN2)); + Inputs->GetInputSystem()->SetMouseVisibility(!s_runtime_config["FullScreen"].ValueAs()); + gameHasLightguns = !!(game.inputs & (GAME_INPUT_GUN1|GAME_INPUT_GUN2)); if (gameHasLightguns) videoInputs = Inputs; else @@ -978,7 +799,7 @@ int Supermodel(const char *zipFile, IEmulator *Model3, CInputs *Inputs, COutputs // Initialize the renderers CRender2D *Render2D = new CRender2D(); - IRender3D *Render3D = g_Config.new3DEngine ? ((IRender3D *) new New3D::CNew3D()) : ((IRender3D *) new Legacy3D::CLegacy3D()); + IRender3D *Render3D = s_runtime_config["New3DEngine"].ValueAs() ? ((IRender3D *) new New3D::CNew3D()) : ((IRender3D *) new Legacy3D::CLegacy3D(s_runtime_config)); if (OKAY != Render2D->Init(xOffset, yOffset, xRes, yRes, totalXRes, totalYRes)) goto QuitError; if (OKAY != Render3D->Init(xOffset, yOffset, xRes, yRes, totalXRes, totalYRes)) @@ -1013,7 +834,7 @@ int Supermodel(const char *zipFile, IEmulator *Model3, CInputs *Inputs, COutputs #endif while (!quit) { - auto startTime = SDL_GetTicks(); + auto startTime = SDL_GetTicks(); // Render if paused, otherwise run a frame if (paused) @@ -1022,7 +843,7 @@ int Supermodel(const char *zipFile, IEmulator *Model3, CInputs *Inputs, COutputs Model3->RunFrame(); // Poll the inputs - if (!Inputs->Poll(Model3->GetGameInfo(), xOffset, yOffset, xRes, yRes)) + if (!Inputs->Poll(&game, xOffset, yOffset, xRes, yRes)) quit = true; #ifdef SUPERMODEL_DEBUGGER @@ -1104,7 +925,7 @@ int Supermodel(const char *zipFile, IEmulator *Model3, CInputs *Inputs, COutputs else if (Inputs->uiFullScreen->Pressed()) { // Toggle emulator fullscreen - g_Config.fullScreen = !g_Config.fullScreen; + s_runtime_config.Get("FullScreen").SetValue(!s_runtime_config["FullScreen"].ValueAs()); // Delete renderers and recreate them afterwards since GL context will most likely be lost when switching from/to fullscreen delete Render2D; @@ -1113,21 +934,21 @@ int Supermodel(const char *zipFile, IEmulator *Model3, CInputs *Inputs, COutputs Render3D = NULL; // Resize screen - totalXRes = xRes = g_Config.xRes; - totalYRes = yRes = g_Config.yRes; - if (OKAY != ResizeGLScreen(&xOffset,&yOffset,&xRes,&yRes,&totalXRes,&totalYRes,true,g_Config.fullScreen)) + totalXRes = xRes = s_runtime_config["XResolution"].ValueAs(); + totalYRes = yRes = s_runtime_config["YResolution"].ValueAs(); + if (OKAY != ResizeGLScreen(&xOffset,&yOffset,&xRes,&yRes,&totalXRes,&totalYRes,true,s_runtime_config["FullScreen"].ValueAs())) goto QuitError; // Recreate renderers and attach to the emulator Render2D = new CRender2D(); - Render3D = g_Config.new3DEngine ? ((IRender3D *) new New3D::CNew3D()) : ((IRender3D *) new Legacy3D::CLegacy3D()); + Render3D = s_runtime_config["New3DEngine"].ValueAs() ? ((IRender3D *) new New3D::CNew3D()) : ((IRender3D *) new Legacy3D::CLegacy3D(s_runtime_config)); if (OKAY != Render2D->Init(xOffset, yOffset, xRes, yRes, totalXRes, totalYRes)) goto QuitError; if (OKAY != Render3D->Init(xOffset, yOffset, xRes, yRes, totalXRes, totalYRes)) goto QuitError; Model3->AttachRenderers(Render2D,Render3D); - Inputs->GetInputSystem()->SetMouseVisibility(!g_Config.fullScreen); + Inputs->GetInputSystem()->SetMouseVisibility(!s_runtime_config["FullScreen"].ValueAs()); } else if (Inputs->uiSaveState->Pressed()) { @@ -1179,12 +1000,10 @@ int Supermodel(const char *zipFile, IEmulator *Model3, CInputs *Inputs, COutputs else if (Inputs->uiMusicVolUp->Pressed()) { // Increase music volume by 10% - if (Model3->GetGameInfo()->mpegBoard) + if (!Model3->GetGame().mpeg_board.empty()) { - int vol = (int) g_Config.GetMusicVolume() + 10; - if (vol > 200) - vol = 200; - g_Config.SetMusicVolume(vol); + int vol = std::min(200, s_runtime_config["MusicVolume"].ValueAs() + 10); + s_runtime_config.Get("MusicVolume").SetValue(vol); printf("Music volume: %d%%", vol); if (200 == vol) puts(" (maximum)"); @@ -1197,12 +1016,10 @@ int Supermodel(const char *zipFile, IEmulator *Model3, CInputs *Inputs, COutputs else if (Inputs->uiMusicVolDown->Pressed()) { // Decrease music volume by 10% - if (Model3->GetGameInfo()->mpegBoard) + if (!Model3->GetGame().mpeg_board.empty()) { - int vol = (int) g_Config.GetMusicVolume() - 10; - if (vol < 0) - vol = 0; - g_Config.SetMusicVolume(vol); + int vol = std::max(0, s_runtime_config["MusicVolume"].ValueAs() - 10); + s_runtime_config.Get("MusicVolume").SetValue(vol); printf("Music volume: %d%%", vol); if (0 == vol) puts(" (muted)"); @@ -1215,10 +1032,8 @@ int Supermodel(const char *zipFile, IEmulator *Model3, CInputs *Inputs, COutputs else if (Inputs->uiSoundVolUp->Pressed()) { // Increase sound volume by 10% - int vol = (int) g_Config.GetSoundVolume() + 10; - if (vol > 200) - vol = 200; - g_Config.SetSoundVolume(vol); + int vol = std::min(200, s_runtime_config["SoundVolume"].ValueAs() + 10); + s_runtime_config.Get("SoundVolume").SetValue(vol); printf("Sound volume: %d%%", vol); if (200 == vol) puts(" (maximum)"); @@ -1228,10 +1043,8 @@ int Supermodel(const char *zipFile, IEmulator *Model3, CInputs *Inputs, COutputs else if (Inputs->uiSoundVolDown->Pressed()) { // Decrease sound volume by 10% - int vol = (int) g_Config.GetSoundVolume() - 10; - if (vol < 0) - vol = 0; - g_Config.SetSoundVolume(vol); + int vol = std::max(0, s_runtime_config["SoundVolume"].ValueAs() - 10); + s_runtime_config.Get("SoundVolume").SetValue(vol); printf("Sound volume: %d%%", vol); if (0 == vol) puts(" (muted)"); @@ -1241,7 +1054,7 @@ int Supermodel(const char *zipFile, IEmulator *Model3, CInputs *Inputs, COutputs else if (Inputs->uiDumpInpState->Pressed()) { // Dump input states - Inputs->DumpState(Model3->GetGameInfo()); + Inputs->DumpState(&game); } else if (Inputs->uiDumpTimings->Pressed()) { @@ -1249,8 +1062,9 @@ int Supermodel(const char *zipFile, IEmulator *Model3, CInputs *Inputs, COutputs } else if (Inputs->uiSelectCrosshairs->Pressed() && gameHasLightguns) { - g_Config.crosshairs++; - switch (g_Config.crosshairs & 3) + int crosshairs = (s_runtime_config["Crosshairs"].ValueAs() + 1) & 3; + s_runtime_config.Get("Crosshairs").SetValue(crosshairs); + switch (crosshairs) { case 0: puts("Crosshairs disabled."); break; case 3: puts("Crosshairs enabled."); break; @@ -1267,8 +1081,8 @@ int Supermodel(const char *zipFile, IEmulator *Model3, CInputs *Inputs, COutputs else if (Inputs->uiToggleFrLimit->Pressed()) { // Toggle frame limiting - g_Config.throttle = !g_Config.throttle; - printf("Frame limiting: %s\n", g_Config.throttle?"On":"Off"); + s_runtime_config.Get("Throttle").SetValue(!s_runtime_config["Throttle"].ValueAs()); + printf("Frame limiting: %s\n", s_runtime_config["Throttle"].ValueAs() ? "On" : "Off"); } #ifdef SUPERMODEL_DEBUGGER else if (Debugger != NULL && Inputs->uiEnterDebugger->Pressed()) @@ -1283,7 +1097,7 @@ int Supermodel(const char *zipFile, IEmulator *Model3, CInputs *Inputs, COutputs // Frame rate and limiting unsigned currentFPSTicks = SDL_GetTicks(); unsigned currentTicks = currentFPSTicks; - if (g_Config.showFPS) + if (s_runtime_config["ShowFrameRate"].ValueAs()) { ++fpsFramesElapsed; if((currentFPSTicks-prevFPSTicks) >= 1000) // update FPS every 1 second (each tick is 1 ms) @@ -1295,11 +1109,11 @@ int Supermodel(const char *zipFile, IEmulator *Model3, CInputs *Inputs, COutputs } } - if (paused || g_Config.throttle) + if (paused || s_runtime_config["Throttle"].ValueAs()) { - UINT32 endTime = SDL_GetTicks(); - UINT32 diff = endTime - startTime; - UINT32 frameTime = (UINT32)(1000 / 60.f); // 60 fps, we could roll with 57.5? that would be a jerk fest on 60hz screens though + UINT32 endTime = SDL_GetTicks(); + UINT32 diff = endTime - startTime; + UINT32 frameTime = (UINT32)(1000 / 60.f); // 60 fps, we could roll with 57.5? that would be a jerk fest on 60hz screens though if (diff < frameTime) { SuperSleep(frameTime - diff); @@ -1346,84 +1160,144 @@ QuitError: } -/****************************************************************************** - CROM Disassembler -******************************************************************************/ - -// Disassemble instructions from CROM -static int DisassembleCROM(const char *zipFile, uint32_t addr, unsigned n) -{ - const struct GameInfo *Game; - uint8_t *crom; - struct ROMMap Map[] = - { - { "CROM", NULL }, - { "CROMxx", NULL }, - { NULL, NULL } - }; - - // Do we have a valid CROM address? - if (addr < 0xFF800000) - return ErrorLog("Valid CROM address range is FF800000-FFFFFFFF."); - - // Allocate memory and set ROM region - crom = new(std::nothrow) uint8_t[0x8800000]; - if (NULL == crom) - return ErrorLog("Insufficient memory to load CROM (need %d MB).", (0x8800000/8)); - Map[0].ptr = crom; - Map[1].ptr = &crom[0x800000]; - - // Load ROM set - Game = LoadROMSetFromZIPFile(Map, g_Model3GameList, zipFile, false); - if (NULL == Game) - return ErrorLog("Failed to load ROM set."); - - // Mirror CROM if necessary - if (Game->cromSize < 0x800000) // high part of fixed CROM region contains CROM0 - CopyRegion(crom, 0, 0x800000-0x200000, &crom[0x800000], 0x800000); - - // Disassemble! - addr -= 0xFF800000; - while ((n > 0) && ((addr+4) <= 0x800000)) - { - uint32_t op = (crom[addr+0]<<24) | (crom[addr+1]<<16) | (crom[addr+2]<<8) | crom[addr+3]; - - printf("%08X: ", addr+0xFF800000); - char mnem[16]; - char oprs[48]; - if (DisassemblePowerPC(op, addr+0xFF800000, mnem, oprs, 1)) - { - if (mnem[0] != '\0') // invalid form - printf("%08X %s*\t%s\n", op, mnem, oprs); - else - printf("%08X ?\n", op); - } - else - printf("%08X %s\t%s\n", op, mnem, oprs); - - addr += 4; - --n; - } - - delete [] crom; - return OKAY; -} - - /****************************************************************************** Entry Point and Command Line Procesing ******************************************************************************/ -// Print Supermodel title and copyright information +static const char s_configFilePath[] = { "Config/Supermodel.ini" }; +static const char s_gameXMLFilePath[] = { "Config/Games.xml" }; + +// Create and configure inputs +static bool ConfigureInputs(CInputs *Inputs, Util::Config::Node *config, bool configure) +{ + static const char configFileComment[] = { + ";\n" + "; Supermodel Configuration File\n" + ";\n" + }; + + Inputs->LoadFromConfig(*config); + + // If the user wants to configure the inputs, do that now + if (configure) + { + // Open an SDL window + unsigned xOffset, yOffset, xRes=496, yRes=384; + if (OKAY != CreateGLScreen("Supermodel - Configuring Inputs...", &xOffset, &yOffset, &xRes, &yRes, &totalXRes, &totalYRes, false, false)) + return (bool) ErrorLog("Unable to start SDL to configure inputs.\n"); + + // Configure the inputs + if (Inputs->ConfigureInputs(NULL, xOffset, yOffset, xRes, yRes)) + { + // Write input configuration and input system settings to config file + Inputs->StoreToConfig(config); + Util::Config::WriteINIFile(s_configFilePath, *config, configFileComment); + } + else + puts("Configuration aborted..."); + puts(""); + } + + return OKAY; +} + +// Print game list +static void PrintGameList(const std::string &xml_file, const std::map &games) +{ + if (games.empty()) + { + puts("No games defined."); + return; + } + printf("Games defined in %s:\n", xml_file.c_str()); + puts(""); + puts(" ROM Set Title"); + puts(" ------- -----"); + for (auto &v: games) + { + const Game &game = v.second; + printf(" %s", game.name.c_str()); + for (int i = game.name.length(); i < 9; i++) // pad for alignment (no game ID should be more than 9 letters) + printf(" "); + printf(" %s\n", game.title.c_str()); + } +} + +static void LogConfig(const Util::Config::Node &config) +{ + InfoLog("Runtime configuration:"); + for (auto &child: config) + { + if (child.Empty()) + InfoLog(" %s=", child.Key().c_str()); + else + InfoLog(" %s=%s", child.Key().c_str(), child.ValueAs().c_str()); + } + InfoLog(""); +} + +static Util::Config::Node DefaultConfig() +{ + Util::Config::Node config("Global"); + config.Set("GameXMLFile", s_gameXMLFilePath); + // CModel3 + config.Set("MultiThreaded", true); + config.Set("GPUMultiThreaded", true); + config.Set("PowerPCFrequency", "50"); + // CLegacy3D + config.Set("MultiTexture", false); + config.Set("VertexShader", ""); + config.Set("FragmentShader", ""); + // CSoundBoard + config.Set("EmulateSound", true); + config.Set("Balance", false); + // CDSB + config.Set("EmulateDSB", true); + config.Set("SoundVolume", "100"); + config.Set("MusicVolume", "100"); + // CDriveBoard +#ifdef SUPERMODEL_WIN32 + config.Set("ForceFeedback", false); +#endif + // Platform-specific/UI + config.Set("New3DEngine", false); + config.Set("XResolution", "496"); + config.Set("YResolution", "384"); + config.Set("FullScreen", false); + config.Set("WideScreen", false); + config.Set("VSync", true); + config.Set("Throttle", true); + config.Set("ShowFrameRate", false); + config.Set("Crosshairs", int(0)); + config.Set("FlipStereo", false); +#ifdef SUPERMODEL_WIN32 + config.Set("InputSystem", "dinput"); + // DirectInput ForceFeedback + config.Set("DirectInputConstForceLeftMax", "100"); + config.Set("DirectInputConstForceRightMax", "100"); + config.Set("DirectInputSelfCenterMax", "100"); + config.Set("DirectInputFrictionMax", "100"); + config.Set("DirectInputVibrateMax", "100"); + // XInput ForceFeedback + config.Set("XInputConstForceThreshold", "30"); + config.Set("XInputConstForceMax", "100"); + config.Set("XInputVibrateMax", "100"); +#else + config.Set("InputSystem", "sdl"); +#endif + config.Set("Outputs", "none"); + return config; +} + static void Title(void) { puts("Supermodel: A Sega Model 3 Arcade Emulator (Version " SUPERMODEL_VERSION ")"); puts("Copyright 2011-2016 by Bart Trzynadlowski and Nik Henson\n"); } -// Print usage information static void Help(void) { + Util::Config::Node defaultConfig = DefaultConfig(); puts("Usage: Supermodel [options]"); puts("ROM set must be a valid ZIP file containing a single game."); puts(""); @@ -1432,7 +1306,7 @@ static void Help(void) puts(" -print-games List supported games and quit"); puts(""); puts("Core Options:"); - printf(" -ppc-frequency= PowerPC frequency in MHz [Default: %d]\n", g_Config.GetPowerPCFrequency()); + printf(" -ppc-frequency= PowerPC frequency in MHz [Default: %d]\n", defaultConfig["PowerPCFrequency"].ValueAs()); puts(" -no-threads Disable multi-threading entirely"); puts(" -gpu-multi-threaded Run graphics rendering in separate thread [Default]"); puts(" -no-gpu-thread Run graphics rendering in main thread"); @@ -1471,8 +1345,8 @@ static void Help(void) #endif puts(" -config-inputs Configure keyboards, mice, and game controllers"); #ifdef SUPERMODEL_WIN32 - printf(" -input-system= Input system [Default: %s]\n", g_Config.GetInputSystem()); - printf(" -outputs= Outputs [Default: %s]\n", g_Config.GetOutputs()); + printf(" -input-system= Input system [Default: %s]\n", defaultConfig["InputSystem"].ValueAs().c_str()); + printf(" -outputs= Outputs [Default: %s]\n", defaultConfig["Outputs"].ValueAs().c_str()); #endif puts(" -print-inputs Prints current input configuration"); puts(""); @@ -1480,27 +1354,167 @@ static void Help(void) puts("Debug Options:"); puts(" -disable-debugger Completely disable debugger functionality"); puts(" -enter-debugger Enter debugger at start of emulation"); - puts(" -dis=[,n] Disassemble PowerPC code from CROM"); puts(""); #endif // SUPERMODEL_DEBUGGER } -// Print game list -static void PrintGameList(void) +struct ParsedCommandLine { - int i, j; - - puts("Supported games:"); - puts(""); - puts(" ROM Set Title"); - puts(" ------- -----"); - for (i = 0; g_Model3GameList[i].title != NULL; i++) + Util::Config::Node config = Util::Config::Node("CommandLine"); + std::vector rom_files; + bool show_help = false; + bool print_games = false; + bool print_gl_info = false; + bool config_inputs = false; + bool print_inputs = false; + bool disable_debugger = false; + bool enter_debugger = false; +#ifdef DEBUG + std::string gfx_state; +#endif +}; + +static ParsedCommandLine ParseCommandLine(int argc, char **argv) +{ + ParsedCommandLine cmd_line; + const std::map valued_options + { // -option=value + { "-game-xml-file", "GameXMLFile" }, + { "-ppc-frequency", "PowerPCFrequency" }, + { "-crosshairs", "Crosshairs" }, + { "-vert-shader", "VertexShader" }, + { "-frag-shader", "FragmentShader" }, + { "-sound-volume", "SoundVolume" }, + { "-music-volume", "MusicVolume" }, + { "-balance", "Balance" }, + { "-input-system", "InputSystem" }, + { "-outputs", "Outputs" } + }; + const std::map> bool_options + { // -option + { "-threads", { "MultiThreaded", true } }, + { "-no-threads", { "MultiThreaded", false } }, + { "-gpu-multi-threaded", { "GPUMultiThreaded", true } }, + { "-no-gpu-thread", { "GPUMultiThreaded", false } }, + { "-window", { "FullScreen", false } }, + { "-fullscreen", { "FullScreen", true } }, + { "-no-wide-screen", { "WideScreen", false } }, + { "-wide-screen", { "WideScreen", true } }, + { "-no-multi-texture", { "MultiTexture", false } }, + { "-multi-texture", { "MultiTexture", true } }, + { "-throttle", { "Throttle", true } }, + { "-no-throttle", { "Throttle", false } }, + { "-vsync", { "VSync", true } }, + { "-no-vsync", { "VSync", false } }, + { "-show-fps", { "ShowFrameRate", true } }, + { "-no-fps", { "ShowFrameRate", false } }, + { "-new3d", { "New3DEngine", true } }, + { "-legacy3d", { "New3DEngine", false } }, + { "-no-flip-stereo", { "FlipStereo", false } }, + { "-flip-stereo", { "FlipStereo", true } }, + { "-sound", { "EmulateSound", true } }, + { "-no-sound", { "EmulateSound", false } }, + { "-dsb", { "EmulateDSB", true } }, + { "-no-dsb", { "EmulateDSB", false } }, +#ifdef SUPERMODEL_WIN32 + { "-no-force-feedback", { "ForceFeedback", false } }, + { "-force-feedback", { "ForceFeedback", true } }, +#endif + + }; + for (int i = 1; i < argc; i++) { - printf(" %s", g_Model3GameList[i].id); - for (j = strlen(g_Model3GameList[i].id); j < 9; j++) // pad for alignment (no game ID is more than 9 letters) - printf(" "); - printf(" %s\n", g_Model3GameList[i].title); + std::string arg(argv[i]); + if (arg[0] == '-') + { + // First, check maps + size_t idx_equals = arg.find_first_of('='); + if (idx_equals != std::string::npos) + { + std::string option(arg.begin(), arg.begin() + idx_equals); + std::string value(arg.begin() + idx_equals + 1, arg.end()); + if (value.length() == 0) + { + ErrorLog("Argument to '%s' cannot be blank.", option.c_str()); + continue; + } + auto it = valued_options.find(option); + if (it != valued_options.end()) + { + const std::string &config_key = it->second; + cmd_line.config.Set(config_key, value); + continue; + } + } + else + { + auto it = bool_options.find(arg); + if (it != bool_options.end()) + { + const std::string &config_key = it->second.first; + bool value = it->second.second; + cmd_line.config.Set(config_key, value); + continue; + } + else if (valued_options.find(arg) != valued_options.end()) + { + ErrorLog("'%s' requires an argument.", argv[i]); + continue; + } + } + // Fell through -- handle special cases + if (arg == "-?" || arg == "-h" || arg == "-help" || arg == "--help") + cmd_line.show_help = true; + else if (arg == "-print-games") + cmd_line.print_games = true; + else if (arg == "-res" || arg.find("-res=") == 0) + { + std::vector parts = Util::Format(arg).Split('='); + if (parts.size() != 2) + ErrorLog("'-res' requires both a width and height (e.g., '-res=496,384')."); + else + { + unsigned x, y; + if (2 == sscanf(&argv[i][4],"=%d,%d", &x, &y)) + { + std::string xres = Util::Format() << x; + std::string yres = Util::Format() << y; + cmd_line.config.Set("XResolution", xres); + cmd_line.config.Set("YResolution", yres); + } + else + ErrorLog("'-res' requires both a width and height (e.g., '-res=496,384')."); + } + } + else if (arg == "-print-gl-info") + cmd_line.print_gl_info = true; + else if (arg == "-config-inputs") + cmd_line.config_inputs = true; + else if (arg == "-print-inputs") + cmd_line.print_inputs = true; +#ifdef SUPERMODEL_DEBUGGER + else if (arg == "-disable-debugger") + cmd_line.disable_debugger = true; + else if (arg == "-enter-debugger") + cmd_line.enter_debugger = true; +#endif +#ifdef DEBUG + else if (arg == "-gfx-state") + { + std::vector parts = Util::Format(arg).Split('='); + if (parts.size() != 2) + ErrorLog("'-gfx-state' requires a file name."); + else + cmd_line.gfx_state = parts[1]; + } +#endif + else + ErrorLog("Ignoring unrecognized option: %s", argv[i]); + } + else + cmd_line.rom_files.emplace_back(arg); } + return cmd_line; } /* @@ -1514,10 +1528,6 @@ int main(int argc, char **argv) #ifdef SUPERMODEL_DEBUGGER bool cmdEnterDebugger = false; #endif // SUPERMODEL_DEBUGGER - char *inputSystem = NULL; // use default input system - char *outputs = NULL; - unsigned num_instructions; - uint32_t addr; Title(); if (argc <= 1) @@ -1530,295 +1540,59 @@ int main(int argc, char **argv) CFileLogger Logger(DEBUG_LOG_FILE, ERROR_LOG_FILE); Logger.ClearLogs(); SetLogger(&Logger); - - // Log the command line used to start Supermodel InfoLog("Started as:"); for (int i = 0; i < argc; i++) - InfoLog("\targv[%d] = %s", i, argv[i]); + InfoLog(" argv[%d] = %s", i, argv[i]); InfoLog(""); - // Read global settings from INI file - ReadConfigFile("Global"); - - /* - * Parse command line. - * - * Settings are stored in CmdLine so that they can be applied later, after - * game-specific settings are read from the configuration file (which - * requires the ROM set to be identified and therefore is done later). - * - * Some commands are processed here directly. - */ - int fileIdx = 0; - bool cmdPrintInputs = false; - bool cmdConfigInputs = false; - bool cmdDis = false; - CINIFile CmdLine; // not associated with any files, only holds command line options - CmdLine.SetDefaultSectionName("Global"); // command line settings are global-level - for (int i = 1; i < argc; i++) + // Load config and parse command line + auto cmd_line = ParseCommandLine(argc, argv); + if (cmd_line.print_gl_info) { - if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-?") || !strcmp(argv[i], "-help") || !strcmp(argv[i], "--help")) - { - Help(); - return 0; - } - else if (!strcmp(argv[i], "-print-games")) - { - PrintGameList(); - return 0; - } - else if (!strncmp(argv[i], "-ppc-frequency", 14)) - { - int f; - int ret = sscanf(&argv[i][14], "=%d", &f); - if (ret != 1) - ErrorLog("'-ppc-frequency' requires a frequency."); - else - CmdLine.Set("Global", "PowerPCFrequency", f); - } - else if (!strcmp(argv[i], "-no-threads")) - { - unsigned n = 0; - CmdLine.Set("Global", "MultiThreaded", n); - } - else if (!strcmp(argv[i], "-gpu-multi-threaded")) - { - unsigned n = 1; - CmdLine.Set("Global", "GPUMultiThreaded", n); - } - else if (!strcmp(argv[i], "-no-gpu-thread")) - { - unsigned n = 0; - CmdLine.Set("Global", "GPUMultiThreaded", n); - } -#ifdef SUPERMODEL_DEBUGGER - else if (!strcmp(argv[i], "-disable-debugger")) - g_Config.disableDebugger = true; - else if (!strcmp(argv[i], "-enter-debugger")) - cmdEnterDebugger = true; -#endif // SUPERMODEL_DEBUGGER - else if (!strncmp(argv[i], "-sound-volume", 13)) - { - unsigned n; - int ret = sscanf(&argv[i][13],"=%d", &n); - if (ret != 1) - ErrorLog("'-sound-volume' requires a volume setting."); - else - CmdLine.Set("Global", "SoundVolume", n); - } - else if (!strncmp(argv[i], "-music-volume", 13)) - { - unsigned n; - int ret = sscanf(&argv[i][13],"=%d", &n); - if (ret != 1) - ErrorLog("'-music-volume' requires a volume setting."); - else - CmdLine.Set("Global", "MusicVolume", n); - } - else if (!strncmp(argv[i], "-balance", 8)) - { - unsigned n; - int ret = sscanf(&argv[i][8], "=%d", &n); - if (ret != 1) - ErrorLog("'-balance' requires a front/rear balance setting."); - else - CmdLine.Set("Global", "Balance", n); - } - else if (!strcmp(argv[i], "-flip-stereo")) - { - unsigned n = 1; - CmdLine.Set("Global", "FlipStereo", n); - } - else if (!strcmp(argv[i], "-no-sound")) - { - unsigned n = 0; - CmdLine.Set("Global", "EmulateSound", n); - } - else if (!strcmp(argv[i], "-no-dsb")) - { - unsigned n = 0; - CmdLine.Set("Global", "EmulateDSB", n); - } -#ifdef SUPERMODEL_WIN32 - else if (!strcmp(argv[i], "-force-feedback")) - { - unsigned n = 1; - CmdLine.Set("Global", "ForceFeedback", n); - } -#endif - else if (!strncmp(argv[i], "-res", 4)) - { - unsigned x, y; - - int ret = sscanf(&argv[i][4],"=%d,%d", &x, &y); - if (ret != 2) - { - ret = sscanf(&argv[i][4],"=%dx%d", &x, &y); - if (ret != 2) - ErrorLog("'-res' requires both a width and a height."); - } - if (ret == 2) - { - CmdLine.Set("Global", "XResolution", x); - CmdLine.Set("Global", "YResolution", y); - } - } - else if (!strcmp(argv[i], "-window")) - { - unsigned n = 0; - CmdLine.Set("Global", "FullScreen", n); - } - else if (!strcmp(argv[i], "-fullscreen")) - { - unsigned n = 1; - CmdLine.Set("Global", "FullScreen", n); - } - else if (!strcmp(argv[i], "-wide-screen")) - { - unsigned n = 1; - CmdLine.Set("Global", "WideScreen", n); - } - else if (!strcmp(argv[i], "-multi-texture")) - { - unsigned n = 1; - CmdLine.Set("Global", "MultiTexture", n); - } - else if (!strcmp(argv[i], "-no-multi-texture")) - { - unsigned n = 0; - CmdLine.Set("Global", "MultiTexture", n); - } - else if (!strcmp(argv[i], "-vsync")) - { - unsigned n = 1; - CmdLine.Set("Global", "VSync", n); - } - else if (!strcmp(argv[i], "-no-vsync")) - { - unsigned n = 0; - CmdLine.Set("Global", "VSync", n); - } - else if (!strcmp(argv[i], "-no-throttle")) - { - unsigned n = 0; - CmdLine.Set("Global", "Throttle", n); - } - else if (!strcmp(argv[i], "-show-fps")) - { - unsigned n = 1; - CmdLine.Set("Global", "ShowFrameRate", n); - } - else if (!strncmp(argv[i], "-crosshairs", 11)) - { - unsigned x; - int ret = sscanf(&argv[i][11],"=%d", &x); - if (ret != 1 || x > 3) - ErrorLog("'-crosshairs' requires a number 0-3"); - else - CmdLine.Set("Global", "Crosshairs", x); - } - else if (!strcmp(argv[i], "-new3d")) - { - unsigned n = 1; - CmdLine.Set("Global", "New3DEngine", n); - } - else if (!strcmp(argv[i], "-legacy3d")) - { - unsigned n = 0; - CmdLine.Set("Global", "New3DEngine", n); - } - else if (!strncmp(argv[i], "-vert-shader", 12)) - { - if (argv[i][12] == '\0') - ErrorLog("'-vert-shader' requires a file path."); - else if (argv[i][12] != '=') - ErrorLog("Ignoring unrecognized option: %s", argv[i]); - else if (argv[i][13] == '\0') - ErrorLog("'-vert-shader' requires a file path."); - else - CmdLine.Set("Global", "VertexShader", &argv[i][13]); - } - else if (!strncmp(argv[i], "-frag-shader", 12)) - { - if (argv[i][12] == '\0') - ErrorLog("'-frag-shader' requires a file path."); - else if (argv[i][12] != '=') - ErrorLog("Ignoring unrecognized option: %s", argv[i]); - else if (argv[i][13] == '\0') - ErrorLog("'-frag-shader' requires a file path."); - else - CmdLine.Set("Global", "FragmentShader", &argv[i][13]); - } -#ifdef SUPERMODEL_WIN32 - else if (!strncmp(argv[i], "-input-system", 13)) // this setting is not written to the config file! - { - if (argv[i][13] == '\0') - ErrorLog("'-input-system' requires an input system name."); - else if (argv[i][13] != '=') - ErrorLog("Ignoring unrecognized option: %s", argv[i]); - else if (argv[i][14] == '\0') - ErrorLog("'-input-system' requires an input system name."); - else - inputSystem = &argv[i][14]; - } - else if (!strncmp(argv[i], "-outputs", 8)) // this setting is not written to the config file! - { - if (argv[i][8] == '\0') - ErrorLog("'-outputs' requires an outputs name."); - else if (argv[i][8] != '=') - ErrorLog("Ignoring unrecognized option: %s", argv[i]); - else if (argv[i][9] == '\0') - ErrorLog("'-outputs' requires an outputs name."); - else - outputs = &argv[i][9]; - } -#endif // SUPERMODEL_WIN32 - else if (!strcmp(argv[i], "-print-inputs")) - cmdPrintInputs = true; - else if (!strcmp(argv[i], "-config-inputs")) - cmdConfigInputs = true; - else if (!strncmp(argv[i], "-dis", 4)) - { - int ret = sscanf(&argv[i][4],"=%X,%X", &addr, &num_instructions); - if (ret == 1) - { - num_instructions = 16; - cmdDis = true; - } - else if (ret == 2) - cmdDis = true; - else - ErrorLog("'-dis' requires address and, optionally, number of instructions."); - } - else if (!strcmp(argv[i], "-print-gl-info")) - { - PrintGLInfo(true, false, false); - return 0; - } -#ifdef DEBUG - else if (!strncmp(argv[i], "-gfx-state", 10)) - { - if (argv[i][10] == '\0') - ErrorLog("'-gfx-state' requires a file path."); - else if (argv[i][10] != '=') - ErrorLog("Ignoring unrecognized option: %s", argv[i]); - else if (argv[i][10] == '\0') - ErrorLog("'-gfx-state' requires a file path."); - else - s_gfxStatePath.assign(&argv[i][11]); - } -#endif - else if (argv[i][0] == '-') - ErrorLog("Ignoring unrecognized option: %s", argv[i]); - else - { - if (fileIdx) // already specified a file - ErrorLog("Multiple files specified. Using '%s', ignoring '%s'.", argv[fileIdx], argv[i]); - else - fileIdx = i; - } + PrintGLInfo(true, false, false); + return 0; } - +#ifdef DEBUG + s_gfxStatePath.assign(cmd_line.gfx_state); +#endif + bool print_games = cmd_line.print_games; + bool rom_specified = !cmd_line.rom_files.empty(); + if (!rom_specified && !print_games && !cmd_line.config_inputs) + { + ErrorLog("No ROM file specified."); + return 0; + } + + // Load game and resolve run-time config + Game game; + ROMSet rom_set; + Util::Config::Node fileConfig("Global"); + Util::Config::Node fileConfigWithDefaults("Global"); + { + Util::Config::Node config3("Global"); + Util::Config::Node config4("Global"); + Util::Config::FromINIFile(&fileConfig, s_configFilePath); + Util::Config::MergeINISections(&fileConfigWithDefaults, DefaultConfig(), fileConfig); // apply .ini file's global section over defaults + Util::Config::MergeINISections(&config3, fileConfigWithDefaults, cmd_line.config); // apply command line overrides + if (rom_specified || print_games) + { + std::string xml_file = config3["GameXMLFile"].ValueAs(); + GameLoader loader(xml_file); + if (print_games) + { + PrintGameList(xml_file, loader.GetGames()); + return 0; + } + if (loader.Load(&game, &rom_set, *cmd_line.rom_files.begin())) + return 1; + Util::Config::MergeINISections(&config4, config3, fileConfig[game.name]); // apply game-specific config + } + else + config4 = config3; + Util::Config::MergeINISections(&s_runtime_config, config4, cmd_line.config); // apply command line overrides once more + } + LogConfig(s_runtime_config); + // Initialize SDL (individual subsystems get initialized later) if (SDL_Init(0) != 0) { @@ -1828,9 +1602,9 @@ int main(int argc, char **argv) // Create Model 3 emulator #ifdef DEBUG - IEmulator *Model3 = s_gfxStatePath.empty() ? static_cast(new CModel3()) : static_cast(new CModel3GraphicsState(s_gfxStatePath)); + IEmulator *Model3 = s_gfxStatePath.empty() ? static_cast(new CModel3(s_runtime_config)) : static_cast(new CModel3GraphicsState(s_gfxStatePath)); #else - IEmulator *Model3 = new CModel3(); + IEmulator *Model3 = new CModel3(s_runtime_config); #endif // Create input system (default is SDL) and debugger @@ -1843,20 +1617,22 @@ int main(int argc, char **argv) #endif // SUPERMODEL_DEBUGGER // Create input system - g_Config.SetInputSystem(inputSystem); - if (stricmp(g_Config.GetInputSystem(), "sdl") == 0) + // NOTE: fileConfigWithDefaults is passed so that the global section is used + // for input settings with default values populated + std::string selectedInputSystem = s_runtime_config["InputSystem"].ValueAs(); + if (selectedInputSystem == "sdl") InputSystem = new CSDLInputSystem(); #ifdef SUPERMODEL_WIN32 - else if (stricmp(g_Config.GetInputSystem(), "dinput") == 0) - InputSystem = new CDirectInputSystem(false, false); - else if (stricmp(g_Config.GetInputSystem(), "xinput") == 0) - InputSystem = new CDirectInputSystem(false, true); - else if (stricmp(g_Config.GetInputSystem(), "rawinput") == 0) - InputSystem = new CDirectInputSystem(true, false); + else if (selectedInputSystem == "dinput") + InputSystem = new CDirectInputSystem(fileConfigWithDefaults, false, false); + else if (selectedInputSystem == "xinput") + InputSystem = new CDirectInputSystem(fileConfigWithDefaults, false, true); + else if (selectedInputSystem == "rawinput") + InputSystem = new CDirectInputSystem(fileConfigWithDefaults, true, false); #endif // SUPERMODEL_WIN32 else { - ErrorLog("Unknown input system: %s\n", g_Config.GetInputSystem()); + ErrorLog("Unknown input system: %s\n", selectedInputSystem.c_str()); exitCode = 1; goto Exit; } @@ -1870,30 +1646,38 @@ int main(int argc, char **argv) goto Exit; } - if (ConfigureInputs(Inputs, cmdConfigInputs)) + // NOTE: fileConfig is passed so that the global section is used for input settings + // and because this function may write out a new config file, which must preserve + // all sections. We don't want to pollute the output with built-in defaults. + if (ConfigureInputs(Inputs, &fileConfig, cmd_line.config_inputs)) { exitCode = 1; goto Exit; } - if (cmdPrintInputs) + if (cmd_line.print_inputs) { Inputs->PrintInputs(NULL); InputSystem->PrintSettings(); } + + if (!rom_specified) + goto Exit; // Create outputs #ifdef SUPERMODEL_WIN32 - g_Config.SetOutputs(outputs); - if (stricmp(g_Config.GetOutputs(), "none") == 0) - Outputs = NULL; - else if (stricmp(g_Config.GetOutputs(), "win") == 0) - Outputs = new CWinOutputs(); - else { - ErrorLog("Unknown outputs: %s\n", g_Config.GetOutputs()); - exitCode = 1; - goto Exit; + std::string outputs = s_runtime_config["Outputs"].ValueAs(); + if (outputs == "none") + Outputs = NULL; + else if (outputs == "win") + Outputs = new CWinOutputs(); + else + { + ErrorLog("Unknown outputs: %s\n", outputs.c_str()); + exitCode = 1; + goto Exit; + } } #endif // SUPERMODEL_WIN32 @@ -1905,24 +1689,9 @@ int main(int argc, char **argv) goto Exit; } - // From this point onwards, a ROM set is needed - if (fileIdx == 0) - { - ErrorLog("No ROM set specified."); - exitCode = 1; - goto Exit; - } - - if (cmdDis) - { - if (OKAY != DisassembleCROM(argv[fileIdx], addr, num_instructions)) - exitCode = 1; - goto Exit; - } - #ifdef SUPERMODEL_DEBUGGER // Create Supermodel debugger unless debugging is disabled - if (!g_Config.disableDebugger) + if (!cmd_line.disable_debugger) { Debugger = new Debugger::CSupermodelDebugger(dynamic_cast(Model3), Inputs, &Logger); // If -enter-debugger option was set force debugger to break straightaway @@ -1930,12 +1699,12 @@ int main(int argc, char **argv) Debugger->ForceBreak(true); } // Fire up Supermodel with debugger - exitCode = Supermodel(argv[fileIdx], Model3, Inputs, Outputs, Debugger, &CmdLine); + exitCode = Supermodel(game, &rom_set, Model3, Inputs, Outputs, Debugger); if (Debugger != NULL) delete Debugger; #else // Fire up Supermodel - exitCode = Supermodel(argv[fileIdx], Model3, Inputs, Outputs, &CmdLine); + exitCode = Supermodel(game, &rom_set, Model3, Inputs, Outputs); #endif // SUPERMODEL_DEBUGGER delete Model3; diff --git a/Src/OSD/SDL/OSDConfig.h b/Src/OSD/SDL/OSDConfig.h deleted file mode 100644 index cec2b1b..0000000 --- a/Src/OSD/SDL/OSDConfig.h +++ /dev/null @@ -1,174 +0,0 @@ -/** - ** Supermodel - ** A Sega Model 3 Arcade Emulator. - ** Copyright 2011-2016 Bart Trzynadlowski, Nik Henson - ** - ** This file is part of Supermodel. - ** - ** Supermodel 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 (at your option) - ** any later version. - ** - ** Supermodel 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 Supermodel. If not, see . - **/ - -/* - * OSDConfig.h - * - * Header file defining the COSDConfig class: OSD configuration settings, - * inherited by CConfig. - */ - -#ifndef INCLUDED_OSDCONFIG_H -#define INCLUDED_OSDCONFIG_H - - -#include -#include "Supermodel.h" -using namespace std; - - -/* - * COSDConfig: - * - * Settings used by COSDConfig. - */ -class COSDConfig -{ -public: - bool new3DEngine; // New 3D engine - unsigned xRes, yRes; // X and Y resolution, in pixels - bool fullScreen; // Full screen mode (if true) - bool wideScreen; // Wide screen hack - bool vsync; // Enable v-sync - bool throttle; // 60 Hz frame limiting - bool showFPS; // Show frame rate - unsigned crosshairs; // For game guns: 0 = no crosshairs, 1 = player 1 only, 2 = player 2 only, 3 = both players - bool flipStereo; // Flip stereo channels - -#ifdef SUPERMODEL_DEBUGGER - bool disableDebugger; // disables the debugger (not stored in the config. file) -#endif - -#ifdef SUPERMODEL_WIN32 - unsigned dInputConstForceLeftMax; - unsigned dInputConstForceRightMax; - unsigned dInputSelfCenterMax; - unsigned dInputFrictionMax; - unsigned dInputVibrateMax; - unsigned xInputConstForceThreshold; - unsigned xInputConstForceMax; - unsigned xInputVibrateMax; -#endif - - // Input system - inline void SetInputSystem(const char *inpSysName) - { - if (inpSysName == NULL) - { -#ifdef SUPERMODEL_WIN32 // default is DirectInput on Windows - inputSystem = "dinput"; -#else // everyone else uses SDL - inputSystem = "sdl"; -#endif - return; - } - - if (stricmp(inpSysName,"sdl") -#ifdef SUPERMODEL_WIN32 - && stricmp(inpSysName,"dinput") && stricmp(inpSysName,"xinput") && stricmp(inpSysName,"rawinput") -#endif - ) - { -#ifdef SUPERMODEL_WIN32 - ErrorLog("Unknown input system '%s', defaulting to DirectInput.", inpSysName); - inputSystem = "dinput"; -#else - ErrorLog("Unknown input system '%s', defaulting to SDL.", inpSysName); - inputSystem = "sdl"; -#endif - return; - } - - inputSystem = inpSysName; - } - - inline const char *GetInputSystem(void) - { - return inputSystem.c_str(); - } - - // Outputs - inline void SetOutputs(const char *outputsName) - { - if (outputsName == NULL) - { - outputs = "none"; - return; - } - - if (stricmp(outputsName, "none") -#ifdef SUPERMODEL_WIN32 - && stricmp(outputsName, "win") -#endif - ) - { - ErrorLog("Unknown outputs '%s', defaulting to None.", outputsName); - outputs = "none"; - return; - } - - outputs = outputsName; - } - - inline const char *GetOutputs(void) - { - return outputs.c_str(); - } - - // Defaults - COSDConfig(void) - { - new3DEngine = false; - xRes = 496; - yRes = 384; - fullScreen = false; - wideScreen = false; - vsync = true; - throttle = true; - showFPS = false; - crosshairs = 0; - flipStereo = false; -#ifdef SUPERMODEL_DEBUGGER - disableDebugger = false; -#endif -#ifdef SUPERMODEL_WIN32 - inputSystem = "dinput"; - dInputConstForceLeftMax = 100; - dInputConstForceRightMax = 100; - dInputSelfCenterMax = 100; - dInputFrictionMax = 100; - dInputVibrateMax = 100; - xInputConstForceThreshold = 30; - xInputConstForceMax = 100; - xInputVibrateMax = 100; -#else - inputSystem = "sdl"; -#endif - outputs = "none"; - } - -private: - string inputSystem; - string outputs; -}; - - -#endif // INCLUDED_OSDCONFIG_H diff --git a/Src/OSD/SDL/SDLInputSystem.cpp b/Src/OSD/SDL/SDLInputSystem.cpp index 02325e1..6d9164d 100644 --- a/Src/OSD/SDL/SDLInputSystem.cpp +++ b/Src/OSD/SDL/SDLInputSystem.cpp @@ -182,7 +182,13 @@ SDLKeyMapStruct CSDLInputSystem::s_keyMap[] = { "UNDO", SDLK_UNDO } }; -CSDLInputSystem::CSDLInputSystem() : CInputSystem("SDL"), m_keyState(NULL), m_mouseX(0), m_mouseY(0), m_mouseZ(0), m_mouseButtons(0) +CSDLInputSystem::CSDLInputSystem() + : CInputSystem("SDL"), + m_keyState(NULL), + m_mouseX(0), + m_mouseY(0), + m_mouseZ(0), + m_mouseButtons(0) { // } diff --git a/Src/OSD/Windows/DirectInputSystem.cpp b/Src/OSD/Windows/DirectInputSystem.cpp index 352633c..d607103 100644 --- a/Src/OSD/Windows/DirectInputSystem.cpp +++ b/Src/OSD/Windows/DirectInputSystem.cpp @@ -428,8 +428,9 @@ const char *CDirectInputSystem::ConstructName(bool useRawInput, bool useXInput) return (useXInput ? "Xinput" : "DirectInput"); } -CDirectInputSystem::CDirectInputSystem(bool useRawInput, bool useXInput) : +CDirectInputSystem::CDirectInputSystem(const Util::Config::Node &config, bool useRawInput, bool useXInput) : CInputSystem(ConstructName(useRawInput, useXInput)), + m_config(config), m_useRawInput(useRawInput), m_useXInput(useXInput), m_enableFFeedback(true), m_initializedCOM(false), m_activated(false), m_hwnd(NULL), m_screenW(0), m_screenH(0), m_getRIDevListPtr(NULL), m_getRIDevInfoPtr(NULL), m_regRIDevsPtr(NULL), m_getRIDataPtr(NULL), @@ -1791,13 +1792,15 @@ bool CDirectInputSystem::ProcessForceFeedbackCmd(int joyNum, int axisNum, ForceF break; case FFConstantForce: + { // Check if constant force effect is disabled - if (g_Config.xInputConstForceMax == 0) + unsigned xInputConstForceMax = m_config["XInputConstForceMax"].ValueAs(); + if (xInputConstForceMax == 0) return false; // Constant force effect is mapped to either left or right vibration motor depending on its direction negForce = ffCmd.force < 0.0f; absForce = (negForce ? -ffCmd.force : ffCmd.force); - threshold = (float)g_Config.xInputConstForceThreshold / 100.0f; + threshold = (float)m_config["XInputConstForceThreshold"].ValueAs() / 100.0f; // Check if constant force effect is being stopped or is below threshold if (absForce == 0.0f || absForce < threshold) { @@ -1808,25 +1811,27 @@ bool CDirectInputSystem::ProcessForceFeedbackCmd(int joyNum, int axisNum, ForceF else if (negForce) { // If force is negative (to left), set left motor vibrating - pInfo->xiConstForceLeft = (WORD)(absForce * (float)(g_Config.xInputConstForceMax * XI_VIBRATE_SCALE)); + pInfo->xiConstForceLeft = (WORD)(absForce * (float)(xInputConstForceMax * XI_VIBRATE_SCALE)); pInfo->xiConstForceRight = 0; } else { // If force positive (to right), set right motor vibrating pInfo->xiConstForceLeft = 0; - pInfo->xiConstForceRight = (WORD)(absForce * (float)(g_Config.xInputConstForceMax * XI_VIBRATE_SCALE)); + pInfo->xiConstForceRight = (WORD)(absForce * (float)(xInputConstForceMax * XI_VIBRATE_SCALE)); } break; - + } case FFSelfCenter: case FFFriction: // Self center and friction effects are not mapped return false; case FFVibrate: - // Check if vibration effect is disabled - if (g_Config.xInputVibrateMax == 0) + { + // Check if vibration effect is disabled + unsigned xInputVibrateMax = m_config["XInputVibrateMax"].ValueAs(); + if (xInputVibrateMax == 0) return false; // Check if vibration effect is being stopped if (ffCmd.force == 0.0f) @@ -1837,10 +1842,10 @@ bool CDirectInputSystem::ProcessForceFeedbackCmd(int joyNum, int axisNum, ForceF else { // Otherwise, set both motors vibrating - pInfo->xiVibrateBoth = (WORD)(ffCmd.force * (float)(g_Config.xInputVibrateMax * XI_VIBRATE_SCALE)); + pInfo->xiVibrateBoth = (WORD)(ffCmd.force * (float)(xInputVibrateMax * XI_VIBRATE_SCALE)); } break; - + } default: // Unknown feedback command return false; @@ -1893,16 +1898,18 @@ bool CDirectInputSystem::ProcessForceFeedbackCmd(int joyNum, int axisNum, ForceF //printf("FFConstantForce %0.2f\n", 100.0f * ffCmd.force); if (ffCmd.force >= 0.0f) { - if (g_Config.dInputConstForceRightMax == 0) + unsigned dInputConstForceRightMax = m_config["DirectInputConstForceRightMax"].ValueAs(); + if (dInputConstForceRightMax == 0) return false; - lFFMag = (LONG)(-ffCmd.force * (float)(g_Config.dInputConstForceRightMax * DI_EFFECTS_SCALE)); // Invert sign for DirectInput effect + lFFMag = (LONG)(-ffCmd.force * (float)(dInputConstForceRightMax * DI_EFFECTS_SCALE)); // Invert sign for DirectInput effect dicf.lMagnitude = std::max(lFFMag, -DI_EFFECTS_MAX); } else { - if (g_Config.dInputConstForceLeftMax == 0) + unsigned dInputConstForceLeftMax = m_config["DirectInputConstForceLeftMax"].ValueAs(); + if (dInputConstForceLeftMax == 0) return false; - lFFMag = (LONG)(-ffCmd.force * (float)(g_Config.dInputConstForceLeftMax * DI_EFFECTS_SCALE)); // Invert sign for DirectInput effect + lFFMag = (LONG)(-ffCmd.force * (float)(dInputConstForceLeftMax * DI_EFFECTS_SCALE)); // Invert sign for DirectInput effect dicf.lMagnitude = std::min(lFFMag, DI_EFFECTS_MAX); } @@ -1911,10 +1918,12 @@ bool CDirectInputSystem::ProcessForceFeedbackCmd(int joyNum, int axisNum, ForceF break; case FFSelfCenter: + { + unsigned dInputSelfCenterMax = m_config["DirectInputSelfCenterMax"].ValueAs(); //printf("FFSelfCenter %0.2f\n", 100.0f * ffCmd.force); - if (g_Config.dInputSelfCenterMax == 0) + if (dInputSelfCenterMax == 0) return false; - lFFMag = (LONG)(ffCmd.force * (float)(g_Config.dInputSelfCenterMax * DI_EFFECTS_SCALE)); + lFFMag = (LONG)(ffCmd.force * (float)(dInputSelfCenterMax * DI_EFFECTS_SCALE)); dic.lOffset = 0; dic.lPositiveCoefficient = std::max(0, std::min(lFFMag, DI_EFFECTS_MAX)); dic.lNegativeCoefficient = std::max(0, std::min(lFFMag, DI_EFFECTS_MAX)); @@ -1925,12 +1934,14 @@ bool CDirectInputSystem::ProcessForceFeedbackCmd(int joyNum, int axisNum, ForceF eff.cbTypeSpecificParams = sizeof(DICONDITION); eff.lpvTypeSpecificParams = &dic; break; - + } case FFFriction: + { + unsigned dInputFrictionMax = m_config["DirectInputFrictionMax"].ValueAs(); //printf("FFFriction %0.2f\n", 100.0f * ffCmd.force); - if (g_Config.dInputFrictionMax == 0) + if (dInputFrictionMax == 0) return false; - lFFMag = (LONG)(ffCmd.force * (float)(g_Config.dInputFrictionMax * DI_EFFECTS_SCALE)); + lFFMag = (LONG)(ffCmd.force * (float)(dInputFrictionMax * DI_EFFECTS_SCALE)); dic.lOffset = 0; dic.lPositiveCoefficient = std::max(0, std::min(lFFMag, DI_EFFECTS_MAX)); dic.lNegativeCoefficient = std::max(0, std::min(lFFMag, DI_EFFECTS_MAX)); @@ -1941,12 +1952,14 @@ bool CDirectInputSystem::ProcessForceFeedbackCmd(int joyNum, int axisNum, ForceF eff.cbTypeSpecificParams = sizeof(DICONDITION); eff.lpvTypeSpecificParams = &dic; break; - + } case FFVibrate: + { + unsigned dInputVibrateMax = m_config["DirectInputVibrateMax"].ValueAs(); //printf("FFVibrate %0.2f\n", 100.0f * ffCmd.force); - if (g_Config.dInputVibrateMax == 0) + if (dInputVibrateMax == 0) return false; - dFFMag = (DWORD)(ffCmd.force * (float)(g_Config.dInputVibrateMax * DI_EFFECTS_SCALE)); + dFFMag = (DWORD)(ffCmd.force * (float)(dInputVibrateMax * DI_EFFECTS_SCALE)); dip.dwMagnitude = std::max(0, std::min(dFFMag, DI_EFFECTS_MAX)); dip.lOffset = 0; dip.dwPhase = 0; @@ -1955,7 +1968,7 @@ bool CDirectInputSystem::ProcessForceFeedbackCmd(int joyNum, int axisNum, ForceF eff.cbTypeSpecificParams = sizeof(DIPERIODIC); eff.lpvTypeSpecificParams = &dip; break; - + } default: // Unknown feedback command return false; diff --git a/Src/OSD/Windows/DirectInputSystem.h b/Src/OSD/Windows/DirectInputSystem.h index 3ebf3a8..2b03976 100644 --- a/Src/OSD/Windows/DirectInputSystem.h +++ b/Src/OSD/Windows/DirectInputSystem.h @@ -108,6 +108,8 @@ typedef /*WINUSERAPI*/ DWORD (WINAPI *XInputSetStatePtr)(IN DWORD dwUserIndex, I class CDirectInputSystem : public CInputSystem { private: + const Util::Config::Node &m_config; + // Lookup table to map key names to DirectInput keycodes and Virtual keycodes static DIKeyMapStruct s_keyMap[]; @@ -232,7 +234,7 @@ public: * to the same shared axis and so cannot be distinguished when pressed together. * If enableFFeedback is true then force feedback is enabled (for those joysticks which are force feedback capable). */ - CDirectInputSystem(bool useRawInput, bool useXInput); + CDirectInputSystem(const Util::Config::Node &config, bool useRawInput, bool useXInput); ~CDirectInputSystem(); diff --git a/Src/OSD/Windows/WinOutputs.cpp b/Src/OSD/Windows/WinOutputs.cpp index 598a8b5..7f48f47 100755 --- a/Src/OSD/Windows/WinOutputs.cpp +++ b/Src/OSD/Windows/WinOutputs.cpp @@ -221,23 +221,19 @@ LRESULT CWinOutputs::UnregisterClient(HWND hwnd, LPARAM id) LRESULT CWinOutputs::SendIdString(HWND hwnd, LPARAM id) { // Id 0 is the name of the game - const char *name; + std::string name; if (id == 0) - name = GetGame()->id; + name = GetGame().name; else - name = MapIdToName(id); + name = MapIdToName(id) ? MapIdToName(id) : ""; - // NULL name is an empty string - if (name == NULL) - name = ""; - // Allocate memory for message - int dataLen = sizeof(CopyDataIdString) + strlen(name); + int dataLen = sizeof(CopyDataIdString) + name.length(); CopyDataIdString *data = (CopyDataIdString*)new(nothrow) UINT8[dataLen]; if (!data) return 1; data->id = id; - strcpy(data->string, name); + strcpy(data->string, name.c_str()); // Reply by using SendMessage with WM_COPYDATA COPYDATASTRUCT copyData; diff --git a/Src/Sound/SCSP.cpp b/Src/Sound/SCSP.cpp index c6f0ff1..fb5c3d6 100644 --- a/Src/Sound/SCSP.cpp +++ b/Src/Sound/SCSP.cpp @@ -57,6 +57,9 @@ #include #include "Sound/SCSPDSP.h" +static const Util::Config::Node *s_config = 0; +static bool s_multiThreaded = false; + //#define NEWSCSP //#define RB_VOLUME @@ -552,8 +555,11 @@ void SCSP_StopSlot(_SLOT *slot,int keyoff) #define log2(n) (log((float) n)/log((float) 2)) -bool SCSP_Init(int n) +bool SCSP_Init(const Util::Config::Node &config, int n) { + s_config = &config; + s_multiThreaded = config["MultiThreaded"].ValueAs(); + if(n==2) { SCSP=SCSPs+1; @@ -928,7 +934,7 @@ void SCSP_UpdateRegR(int reg) /* * MIDI FIFO critical section! */ - if (g_Config.multiThreaded) + if (s_multiThreaded) MIDILock->Lock(); v|=MidiStack[MidiR]; @@ -943,7 +949,7 @@ void SCSP_UpdateRegR(int reg) MidiInFill--; SCSP->data[0x5/2]=v; - if (g_Config.multiThreaded) + if (s_multiThreaded) MIDILock->Unlock(); } break; @@ -1770,7 +1776,12 @@ void SCSP_DoMasterSamples(int nsamples) * When one SCSP is fully attenuated, the other's samples will be multiplied * by 2. */ - float balance = (float) g_Config.GetSCSPBalance() / 100.0f; + float balance = (float) s_config->Get("Balance").ValueAs(); + if (balance < -100.0f) + balance = -100.0f; + else if (balance > 100.0f) + balance = 100.0f; + balance /= 100.0f; float masterBalance = 1.0f+balance; float slaveBalance = 1.0f-balance; @@ -1935,7 +1946,7 @@ void SCSP_MidiIn(BYTE val) /* * MIDI FIFO critical section */ - if (g_Config.multiThreaded) + if (s_multiThreaded) MIDILock->Lock(); //DebugLog("Midi Buffer push %02X",val); @@ -1945,7 +1956,7 @@ void SCSP_MidiIn(BYTE val) //Int68kCB(IrqMidi); // SCSP.data[0x20/2]|=0x8; - if (g_Config.multiThreaded) + if (s_multiThreaded) MIDILock->Unlock(); } @@ -1954,7 +1965,7 @@ void SCSP_MidiOutW(BYTE val) /* * MIDI FIFO critical section */ - if (g_Config.multiThreaded) + if (s_multiThreaded) MIDILock->Lock(); //printf("68K: MIDI out\n"); @@ -1963,7 +1974,7 @@ void SCSP_MidiOutW(BYTE val) MidiOutW&=7; ++MidiOutFill; - if (g_Config.multiThreaded) + if (s_multiThreaded) MIDILock->Unlock(); } @@ -1978,7 +1989,7 @@ unsigned char SCSP_MidiOutR() /* * MIDI FIFO critical section */ - if (g_Config.multiThreaded) + if (s_multiThreaded) MIDILock->Lock(); val=MidiStack[MidiOutR++]; @@ -1986,7 +1997,7 @@ unsigned char SCSP_MidiOutR() MidiOutR&=7; --MidiOutFill; - if (g_Config.multiThreaded) + if (s_multiThreaded) MIDILock->Unlock(); return val; @@ -1999,12 +2010,12 @@ unsigned char SCSP_MidiOutFill() /* * MIDI FIFO critical section */ - if (g_Config.multiThreaded) + if (s_multiThreaded) MIDILock->Lock(); v = MidiOutFill; - if (g_Config.multiThreaded) + if (s_multiThreaded) MIDILock->Unlock(); return v; @@ -2017,12 +2028,12 @@ unsigned char SCSP_MidiInFill() /* * MIDI FIFO critical section */ - if (g_Config.multiThreaded) + if (s_multiThreaded) MIDILock->Lock(); v = MidiInFill; - if (g_Config.multiThreaded) + if (s_multiThreaded) MIDILock->Unlock(); return v; diff --git a/Src/Sound/SCSP.h b/Src/Sound/SCSP.h index 802729a..4ce759a 100644 --- a/Src/Sound/SCSP.h +++ b/Src/Sound/SCSP.h @@ -58,7 +58,7 @@ UINT8 SCSP_MidiOutR(); * Returns: * FAIL if an error occured (prints own error messages), OKAY otherwise. */ -bool SCSP_Init(int n); +bool SCSP_Init(const Util::Config::Node &config, int n); void SCSP_SetRAM(int n,UINT8 *r); void SCSP_RTECheck(); diff --git a/Src/Supermodel.h b/Src/Supermodel.h index 3249419..ff8ace5 100644 --- a/Src/Supermodel.h +++ b/Src/Supermodel.h @@ -97,9 +97,6 @@ // Error logging interface #include "OSD/Logger.h" -// OSD configuration -#include "OSDConfig.h" // located in OSD// directory - // OSD Interfaces #include "OSD/Thread.h" #include "OSD/Audio.h" @@ -154,7 +151,6 @@ #include "Model3/DSB.h" #include "Model3/DriveBoard.h" #include "Model3/Model3.h" -#include "Config.h" /******************************************************************************