diff --git a/CMakeLists.txt b/CMakeLists.txt index 543d9cb98..79e33f181 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,19 +96,13 @@ ENDIF() set(LIBDIR ${CMAKE_SOURCE_DIR}/libs) -set(MANGLE_INPUT ${LIBDIR}/mangle/input/servers/ois_driver.cpp) -set(MANGLE_ALL ${MANGLE_INPUT}) -source_group(libs\\mangle FILES ${MANGLE_ALL}) - set(OENGINE_OGRE ${LIBDIR}/openengine/ogre/renderer.cpp - ${LIBDIR}/openengine/ogre/mouselook.cpp ${LIBDIR}/openengine/ogre/fader.cpp ${LIBDIR}/openengine/ogre/imagerotate.cpp ${LIBDIR}/openengine/ogre/atlas.cpp ) set(OENGINE_GUI - ${LIBDIR}/openengine/gui/events.cpp ${LIBDIR}/openengine/gui/manager.cpp ) @@ -135,7 +129,7 @@ set(OENGINE_BULLET set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET}) source_group(libs\\openengine FILES ${OENGINE_ALL}) -set(OPENMW_LIBS ${MANGLE_ALL} ${OENGINE_ALL}) +set(OPENMW_LIBS ${OENGINE_ALL}) set(OPENMW_LIBS_HEADER) # Sound setup @@ -291,6 +285,9 @@ endif (APPLE) configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg "${OpenMW_BINARY_DIR}/settings-default.cfg") +configure_file(${OpenMW_SOURCE_DIR}/files/input-default.xml + "${OpenMW_BINARY_DIR}/input-default.xml") + configure_file(${OpenMW_SOURCE_DIR}/files/transparency-overrides.cfg "${OpenMW_BINARY_DIR}/transparency-overrides.cfg") @@ -443,6 +440,7 @@ endif(WIN32) # Extern add_subdirectory (extern/shiny) +add_subdirectory (extern/oics) # Components add_subdirectory (components) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 02fe0b72c..72c5117d2 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -104,6 +104,7 @@ target_link_libraries(openmw ${MYGUI_PLATFORM_LIBRARIES} "shiny" "shiny.OgrePlatform" + "oics" components ) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 75835120f..128d97553 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -67,7 +67,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) mEnvironment.setFrameDuration (evt.timeSinceLastFrame); // update input - MWBase::Environment::get().getInputManager()->update(); + MWBase::Environment::get().getInputManager()->update(evt.timeSinceLastFrame); // sound if (mUseSound) @@ -270,6 +270,24 @@ void OMW::Engine::go() else if (boost::filesystem::exists(globaldefault)) settings.loadUser(globaldefault); + // Get the path for the keybinder xml file + std::string keybinderDefault; + + // load user settings if they exist, otherwise just load the default settings as user settings + const std::string keybinderUser = (mCfgMgr.getUserPath() / "input.xml").string(); + const std::string keybinderDefaultLocal = (mCfgMgr.getLocalPath() / "input-default.xml").string(); + const std::string keybinderDefaultGlobal = (mCfgMgr.getGlobalPath() / "input-default.xml").string(); + + bool keybinderUserExists = boost::filesystem::exists(keybinderUser); + + if (boost::filesystem::exists(keybinderDefaultLocal)) + keybinderDefault = keybinderDefaultLocal; + else if (boost::filesystem::exists(keybinderDefaultGlobal)) + keybinderDefault = keybinderDefaultGlobal; + else + throw std::runtime_error ("No default input settings found! Make sure the file \"input-default.xml\" was properly installed."); + + mFpsLevel = settings.getInt("fps", "HUD"); // load nif overrides @@ -366,9 +384,9 @@ void OMW::Engine::go() // Sets up the input system - mEnvironment.setInputManager (new MWInput::MWInputManager (*mOgre, + mEnvironment.setInputManager (new MWInput::InputManager (*mOgre, MWBase::Environment::get().getWorld()->getPlayer(), - *MWBase::Environment::get().getWindowManager(), mDebug, *this)); + *MWBase::Environment::get().getWindowManager(), mDebug, *this, keybinderDefault, keybinderUser, keybinderUserExists)); std::cout << "\nPress Q/ESC or close window to exit.\n"; diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index d865bfb0e..5d73025a7 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -22,7 +22,7 @@ namespace MWBase virtual ~InputManager() {} - virtual void update() = 0; + virtual void update(float dt) = 0; virtual void changeInputMode(bool guiMode) = 0; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 8def5c74d..d1c400cea 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1,357 +1,200 @@ #include "inputmanagerimp.hpp" #include +#include -#include -#include - -#include - -#include +#include +#include -#include "../mwbase/windowmanager.hpp" +#include -#include -#include +#include +#include -#include +#include -#include "mouselookevent.hpp" +#include #include "../engine.hpp" #include "../mwworld/player.hpp" #include "../mwbase/world.hpp" - -#include -#include -#include -#include +#include "../mwbase/windowmanager.hpp" namespace MWInput { - enum Actions + InputManager::InputManager(OEngine::Render::OgreRenderer &ogre, + MWWorld::Player &player, + MWBase::WindowManager &windows, + bool debug, + OMW::Engine& engine, + const std::string& defaultFile, + const std::string& userFile, bool userFileExists) + : mOgre(ogre) + , mPlayer(player) + , mWindows(windows) + , mEngine(engine) + , mMouseLookEnabled(true) + , mMouseX(ogre.getWindow()->getWidth ()/2.f) + , mMouseY(ogre.getWindow()->getHeight ()/2.f) + , mUserFile(userFile) + , mDragDrop(false) { - A_Quit, // Exit the program - - A_Screenshot, // Take a screenshot - - A_Inventory, // Toggle inventory screen - - A_Console, // Toggle console screen - - A_MoveLeft, // Move player left / right - A_MoveRight, - A_MoveForward, // Forward / Backward - A_MoveBackward, - - A_Activate, - - A_Use, //Use weapon, spell, etc. - A_Jump, - A_AutoMove, //Toggle Auto-move forward - A_Rest, //Rest - A_Journal, //Journal - A_Weapon, //Draw/Sheath weapon - A_Spell, //Ready/Unready Casting - A_AlwaysRun, //Toggle Always Run - A_CycleSpellLeft, //cycling through spells - A_CycleSpellRight, - A_CycleWeaponLeft,//Cycling through weapons - A_CycleWeaponRight, - A_ToggleSneak, //Toggles Sneak, add Push-Sneak later - A_ToggleWalk, //Toggle Walking/Running - A_Crouch, - - A_QuickSave, - A_QuickLoad, - A_QuickMenu, - A_GameMenu, - A_ToggleWeapon, - A_ToggleSpell, - - A_LAST // Marker for the last item - }; - - // Class that handles all input and key bindings for OpenMW - class InputImpl - { - OEngine::Input::DispatcherPtr disp; - OEngine::Render::OgreRenderer &ogre; - Mangle::Input::OISDriver input; - OEngine::Input::Poller poller; - MouseLookEventPtr mouse; - OEngine::GUI::EventInjectorPtr guiEvents; - MWWorld::Player &player; - MWBase::WindowManager &windows; - OMW::Engine& mEngine; - - bool mDragDrop; - - std::map mControlSwitch; - - /* InputImpl Methods */ -public: - void adjustMouseRegion(int width, int height) - { - input.adjustMouseClippingSize(width, height); - } -private: - void toggleSpell() - { - if (windows.isGuiMode()) return; + Ogre::RenderWindow* window = ogre.getWindow (); + size_t windowHnd; - MWMechanics::DrawState_ state = player.getDrawState(); - if (state == MWMechanics::DrawState_Weapon || state == MWMechanics::DrawState_Nothing) - { - player.setDrawState(MWMechanics::DrawState_Spell); - std::cout << "Player has now readied his hands for spellcasting!\n"; - } - else - { - player.setDrawState(MWMechanics::DrawState_Nothing); - std::cout << "Player does not have any kind of attack ready now.\n"; - } - } + window->getCustomAttribute("WINDOW", &windowHnd); - void toggleWeapon() - { - if (windows.isGuiMode()) return; + std::ostringstream windowHndStr; + OIS::ParamList pl; - MWMechanics::DrawState_ state = player.getDrawState(); - if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing) - { - player.setDrawState(MWMechanics::DrawState_Weapon); - std::cout << "Player is now drawing his weapon.\n"; - } - else + windowHndStr << windowHnd; + pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str())); + + // Set non-exclusive mouse and keyboard input if the user requested + // it. + if (debug) { - player.setDrawState(MWMechanics::DrawState_Nothing); - std::cout << "Player does not have any kind of attack ready now.\n"; + #if defined OIS_WIN32_PLATFORM + pl.insert(std::make_pair(std::string("w32_mouse"), + std::string("DISCL_FOREGROUND" ))); + pl.insert(std::make_pair(std::string("w32_mouse"), + std::string("DISCL_NONEXCLUSIVE"))); + pl.insert(std::make_pair(std::string("w32_keyboard"), + std::string("DISCL_FOREGROUND"))); + pl.insert(std::make_pair(std::string("w32_keyboard"), + std::string("DISCL_NONEXCLUSIVE"))); + #elif defined OIS_LINUX_PLATFORM + pl.insert(std::make_pair(std::string("x11_mouse_grab"), + std::string("false"))); + pl.insert(std::make_pair(std::string("x11_mouse_hide"), + std::string("false"))); + pl.insert(std::make_pair(std::string("x11_keyboard_grab"), + std::string("false"))); + pl.insert(std::make_pair(std::string("XAutoRepeatOn"), + std::string("true"))); + #endif } - } - void screenshot() - { - mEngine.screenshot(); + #ifdef __APPLE_CC__ + // Give the application window focus to receive input events + ProcessSerialNumber psn = { 0, kCurrentProcess }; + TransformProcessType(&psn, kProcessTransformToForegroundApplication); + SetFrontProcess(&psn); + #endif - std::vector empty; - windows.messageBox ("Screenshot saved", empty); - } + mInputManager = OIS::InputManager::createInputSystem( pl ); - /* toggleInventory() is called when the user presses the button to toggle the inventory screen. */ - void toggleInventory() - { - using namespace MWGui; + // Create all devices + mKeyboard = static_cast(mInputManager->createInputObject + ( OIS::OISKeyboard, true )); + mMouse = static_cast(mInputManager->createInputObject + ( OIS::OISMouse, true )); - if (mDragDrop) - return; + mKeyboard->setEventCallback (this); + mMouse->setEventCallback (this); - bool gameMode = !windows.isGuiMode(); + adjustMouseRegion (window->getWidth(), window->getHeight()); - // Toggle between game mode and inventory mode - if(gameMode) - windows.pushGuiMode(GM_Inventory); - else if(windows.getMode() == GM_Inventory) - windows.popGuiMode(); + MyGUI::InputManager::getInstance().injectMouseMove(mMouseX, mMouseY, mMouse->getMouseState ().Z.abs); - // .. but don't touch any other mode. - } + std::string configFile; + if (userFileExists) + configFile = userFile; + else + configFile = defaultFile; - // Toggle console - void toggleConsole() - { - using namespace MWGui; - - if (mDragDrop) - return; - - bool gameMode = !windows.isGuiMode(); - - // Switch to console mode no matter what mode we are currently - // in, except of course if we are already in console mode - if (!gameMode) - { - if (windows.getMode() == GM_Console) - windows.popGuiMode(); - else - windows.pushGuiMode(GM_Console); - } - else - windows.pushGuiMode(GM_Console); - } + std::cout << "Loading input configuration: " << configFile << std::endl; - void toggleJournal() - { - using namespace MWGui; + mInputCtrl = new ICS::InputControlSystem(configFile, true, NULL, NULL, A_LAST); - // Toggle between game mode and journal mode - bool gameMode = !windows.isGuiMode(); + for (int i = 0; i < A_LAST; ++i) + { + mInputCtrl->getChannel (i)->addListener (this); + } - if(gameMode) - windows.pushGuiMode(GM_Journal); - else if(windows.getMode() == GM_Journal) - windows.popGuiMode(); - // .. but don't touch any other mode. - } + mControlSwitch["playercontrols"] = true; + mControlSwitch["playerfighting"] = true; + mControlSwitch["playerjumping"] = true; + mControlSwitch["playerlooking"] = true; + mControlSwitch["playermagic"] = true; + mControlSwitch["playerviewswitch"] = true; + mControlSwitch["vanitymode"] = true; - void activate() - { - mEngine.activate(); + changeInputMode(false); } - void toggleAutoMove() + InputManager::~InputManager() { - if (windows.isGuiMode()) return; - player.setAutoMove (!player.getAutoMove()); - } + mInputCtrl->save (mUserFile); - void toggleWalking() - { - if (windows.isGuiMode()) return; - player.toggleRunning(); - } + delete mInputCtrl; - void toggleMainMenu() - { - if (windows.isGuiMode () && (windows.getMode () == MWGui::GM_MainMenu || windows.getMode () == MWGui::GM_Settings)) - windows.popGuiMode(); - else - windows.pushGuiMode (MWGui::GM_MainMenu); + mInputManager->destroyInputObject(mKeyboard); + mInputManager->destroyInputObject(mMouse); + OIS::InputManager::destroyInputSystem(mInputManager); } - // Exit program now button (which is disabled in GUI mode) - void exitNow() + void InputManager::channelChanged(ICS::Channel* channel, float currentValue, float previousValue) { - if(!windows.isGuiMode()) - Ogre::Root::getSingleton().queueEndRendering (); - } + if (mDragDrop) + return; - public: - InputImpl(OEngine::Render::OgreRenderer &_ogre, - MWWorld::Player &_player, - MWBase::WindowManager &_windows, - bool debug, - OMW::Engine& engine) - : ogre(_ogre), - input(ogre.getWindow(), !debug), - poller(input), - player(_player), - windows(_windows), - mEngine (engine), - mDragDrop(false) - { - using namespace OEngine::Input; - using namespace OEngine::Render; - using namespace OEngine::GUI; - using namespace Mangle::Input; - using namespace OIS; - - disp = DispatcherPtr(new Dispatcher(A_LAST)); - - // Bind MW-specific functions - disp->funcs.bind(A_Quit, boost::bind(&InputImpl::exitNow, this), - "Quit program"); - disp->funcs.bind(A_Screenshot, boost::bind(&InputImpl::screenshot, this), - "Screenshot"); - disp->funcs.bind(A_Inventory, boost::bind(&InputImpl::toggleInventory, this), - "Toggle inventory screen"); - disp->funcs.bind(A_Console, boost::bind(&InputImpl::toggleConsole, this), - "Toggle console"); - disp->funcs.bind(A_Journal, boost::bind(&InputImpl::toggleJournal, this), - "Toggle journal"); - disp->funcs.bind(A_Activate, boost::bind(&InputImpl::activate, this), - "Activate"); - disp->funcs.bind(A_AutoMove, boost::bind(&InputImpl::toggleAutoMove, this), - "Auto Move"); - disp->funcs.bind(A_ToggleWalk, boost::bind(&InputImpl::toggleWalking, this), - "Toggle Walk/Run"); - disp->funcs.bind(A_ToggleWeapon,boost::bind(&InputImpl::toggleWeapon,this), - "Draw Weapon"); - disp->funcs.bind(A_ToggleSpell,boost::bind(&InputImpl::toggleSpell,this), - "Ready hands"); - disp->funcs.bind(A_GameMenu, boost::bind(&InputImpl::toggleMainMenu, this), - "Toggle main menu"); - - mouse = MouseLookEventPtr(new MouseLookEvent()); - - // This event handler pumps events into MyGUI - guiEvents = EventInjectorPtr(new EventInjector(windows.getGui())); - - // Hook 'mouse' and 'disp' up as event handlers into 'input' - // (the OIS driver and event source.) We do this through an - // EventList which dispatches the event to multiple handlers for - // us. - { - EventList *lst = new EventList; - input.setEvent(EventPtr(lst)); - lst->add(mouse,Event::EV_MouseMove); - lst->add(disp,Event::EV_KeyDown); - lst->add(guiEvents,Event::EV_ALL); - } - - mControlSwitch["playercontrols"] = true; - mControlSwitch["playerfighting"] = true; - mControlSwitch["playerjumping"] = true; - mControlSwitch["playerlooking"] = true; - mControlSwitch["playermagic"] = true; - mControlSwitch["playerviewswitch"] = true; - mControlSwitch["vanitymode"] = true; - - changeInputMode(false); - - /********************************** - Key binding section - - The rest of this function has hard coded key bindings, and is - intended to be replaced by user defined bindings later. - **********************************/ - - // Key bindings for keypress events - // NOTE: These keys do not require constant polling - use in conjuction with variables in loops. - - disp->bind(A_Quit, KC_Q); - disp->bind(A_GameMenu, KC_ESCAPE); - disp->bind(A_Screenshot, KC_SYSRQ); - disp->bind(A_Inventory, KC_I); - disp->bind(A_Console, KC_F1); - disp->bind(A_Journal, KC_J); - disp->bind(A_Activate, KC_SPACE); - disp->bind(A_AutoMove, KC_Z); - disp->bind(A_ToggleSneak, KC_X); - disp->bind(A_ToggleWalk, KC_C); - disp->bind(A_ToggleWeapon,KC_F); - disp->bind(A_ToggleSpell,KC_R); - - // Key bindings for polled keys - // NOTE: These keys are constantly being polled. Only add keys that must be checked each frame. - - // Arrow keys - poller.bind(A_MoveLeft, KC_LEFT); - poller.bind(A_MoveRight, KC_RIGHT); - poller.bind(A_MoveForward, KC_UP); - poller.bind(A_MoveBackward, KC_DOWN); - - // WASD keys - poller.bind(A_MoveLeft, KC_A); - poller.bind(A_MoveRight, KC_D); - poller.bind(A_MoveForward, KC_W); - poller.bind(A_MoveBackward, KC_S); - - poller.bind(A_Jump, KC_E); - poller.bind(A_Crouch, KC_LCONTROL); - } + int action = channel->getNumber(); + if (currentValue == 1) + { + // trigger action activated - void setDragDrop(bool dragDrop) - { - mDragDrop = dragDrop; + switch (action) + { + case A_GameMenu: + toggleMainMenu (); + break; + case A_Quit: + exitNow(); + break; + case A_Screenshot: + screenshot(); + break; + case A_Inventory: + toggleInventory (); + break; + case A_Console: + toggleConsole (); + break; + case A_Activate: + activate(); + break; + case A_Journal: + toggleJournal (); + break; + case A_AutoMove: + toggleAutoMove (); + break; + case A_ToggleSneak: + /// \todo implement + break; + case A_ToggleWalk: + toggleWalking (); + break; + case A_ToggleWeapon: + toggleWeapon (); + break; + case A_ToggleSpell: + toggleSpell (); + break; + } + } } - //NOTE: Used to check for movement keys - void update () + void InputManager::update(float dt) { // Tell OIS to handle all input events - input.capture(); + mKeyboard->capture(); + mMouse->capture(); + + // update values of channels (as a result of pressed keys) + mInputCtrl->update(dt); // Update windows/gui as a result of input events // For instance this could mean opening a new window/dialog, @@ -359,150 +202,314 @@ private: // ensure that window/gui changes appear quickly while // avoiding that window/gui changes does not happen in // event callbacks (which may crash) - windows.update(); + mWindows.update(); // Disable movement in Gui mode + if (mWindows.isGuiMode()) return; - if (windows.isGuiMode()) return; // Configure player movement according to keyboard input. Actual movement will // be done in the physics system. - if (mControlSwitch["playercontrols"]) { - if (poller.isDown(A_MoveLeft)) + if (mControlSwitch["playercontrols"]) + { + if (actionIsActive(A_MoveLeft)) { - player.setAutoMove (false); - player.setLeftRight (1); + mPlayer.setAutoMove (false); + mPlayer.setLeftRight (1); } - else if (poller.isDown(A_MoveRight)) + else if (actionIsActive(A_MoveRight)) { - player.setAutoMove (false); - player.setLeftRight (-1); + mPlayer.setAutoMove (false); + mPlayer.setLeftRight (-1); } else - player.setLeftRight (0); + mPlayer.setLeftRight (0); - if (poller.isDown(A_MoveForward)) + if (actionIsActive(A_MoveForward)) { - player.setAutoMove (false); - player.setForwardBackward (1); + mPlayer.setAutoMove (false); + mPlayer.setForwardBackward (1); } - else if (poller.isDown(A_MoveBackward)) + else if (actionIsActive(A_MoveBackward)) { - player.setAutoMove (false); - player.setForwardBackward (-1); + mPlayer.setAutoMove (false); + mPlayer.setForwardBackward (-1); } else - player.setForwardBackward (0); + mPlayer.setForwardBackward (0); - if (poller.isDown(A_Jump) && mControlSwitch["playerjumping"]) - player.setUpDown (1); - else if (poller.isDown(A_Crouch)) - player.setUpDown (-1); + if (actionIsActive(A_Jump) && mControlSwitch["playerjumping"]) + mPlayer.setUpDown (1); + else if (actionIsActive(A_Crouch)) + mPlayer.setUpDown (-1); else - player.setUpDown (0); + mPlayer.setUpDown (0); } + + } + + void InputManager::setDragDrop(bool dragDrop) + { + mDragDrop = dragDrop; } - // Switch between gui modes. Besides controlling the Gui windows - // this also makes sure input is directed to the right place - void changeInputMode(bool guiMode) + void InputManager::changeInputMode(bool guiMode) { - // Are we in GUI mode now? - if(guiMode) + // Are we in GUI mode now? + if(guiMode) { - // Disable mouse look - mouse->disable(); + // Disable mouse look + mMouseLookEnabled = false; - // Enable GUI events - guiEvents->enabled = true; + // Enable GUI events + mGuiCursorEnabled = true; } - else + else { // Start mouse-looking again if allowed. if (mControlSwitch["playerlooking"]) { - mouse->enable(); + mMouseLookEnabled = true; } - // Disable GUI events - guiEvents->enabled = false; + // Disable GUI events + mGuiCursorEnabled = false; + } + } + + void InputManager::processChangedSettings(const Settings::CategorySettingVector& changed) + { + bool changeRes = false; + for (Settings::CategorySettingVector::const_iterator it = changed.begin(); + it != changed.end(); ++it) + { + if (it->first == "Video" && (it->second == "resolution x" || it->second == "resolution y")) + changeRes = true; } + + if (changeRes) + adjustMouseRegion(Settings::Manager::getInt("resolution x", "Video"), Settings::Manager::getInt("resolution y", "Video")); } - void toggleControlSwitch(std::string sw, bool value) + void InputManager::toggleControlSwitch (const std::string& sw, bool value) { if (mControlSwitch[sw] == value) { return; } /// \note 7 switches at all, if-else is relevant if (sw == "playercontrols" && !value) { - player.setLeftRight(0); - player.setForwardBackward(0); - player.setAutoMove(false); - player.setUpDown(0); + mPlayer.setLeftRight(0); + mPlayer.setForwardBackward(0); + mPlayer.setAutoMove(false); + mPlayer.setUpDown(0); } else if (sw == "playerjumping" && !value) { /// \fixme maybe crouching at this time - player.setUpDown(0); + mPlayer.setUpDown(0); } else if (sw == "playerlooking") { if (value) { - mouse->enable(); + mMouseLookEnabled = true; } else { - mouse->disable(); + mMouseLookEnabled = false; } } mControlSwitch[sw] = value; } - }; - - /***CONSTRUCTOR***/ - MWInputManager::MWInputManager(OEngine::Render::OgreRenderer &ogre, - MWWorld::Player &player, - MWBase::WindowManager &windows, - bool debug, - OMW::Engine& engine) - { - impl = new InputImpl(ogre,player,windows,debug, engine); - } - - /***DESTRUCTOR***/ - MWInputManager::~MWInputManager() - { - delete impl; - } - - void MWInputManager::update() - { - impl->update(); - } - - void MWInputManager::setDragDrop(bool dragDrop) - { - impl->setDragDrop(dragDrop); - } - - void MWInputManager::changeInputMode(bool guiMode) - { - impl->changeInputMode(guiMode); - } - - void MWInputManager::processChangedSettings(const Settings::CategorySettingVector& changed) - { - bool changeRes = false; - for (Settings::CategorySettingVector::const_iterator it = changed.begin(); - it != changed.end(); ++it) - { - if (it->first == "Video" && ( - it->second == "resolution x" - || it->second == "resolution y")) - changeRes = true; - } + void InputManager::adjustMouseRegion(int width, int height) + { + const OIS::MouseState &ms = mMouse->getMouseState(); + ms.width = width; + ms.height = height; + } - if (changeRes) - impl->adjustMouseRegion(Settings::Manager::getInt("resolution x", "Video"), Settings::Manager::getInt("resolution y", "Video")); - } + bool InputManager::keyPressed( const OIS::KeyEvent &arg ) + { + mInputCtrl->keyPressed (arg); + + if (mGuiCursorEnabled) + MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(arg.key), arg.text); + + return true; + } - void MWInputManager::toggleControlSwitch (const std::string& sw, bool value) + bool InputManager::keyReleased( const OIS::KeyEvent &arg ) { - impl->toggleControlSwitch(sw, value); + mInputCtrl->keyReleased (arg); + + if (mGuiCursorEnabled) + MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(arg.key)); + + return true; } + + bool InputManager::mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id ) + { + mInputCtrl->mousePressed (arg, id); + + if (mGuiCursorEnabled) + MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, MyGUI::MouseButton::Enum(id)); + + return true; + } + + bool InputManager::mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id ) + { + mInputCtrl->mouseReleased (arg, id); + + if (mGuiCursorEnabled) + MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, MyGUI::MouseButton::Enum(id)); + + return true; + } + + bool InputManager::mouseMoved( const OIS::MouseEvent &arg ) + { + mInputCtrl->mouseMoved (arg); + + if (mGuiCursorEnabled) + { + const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + + // We keep track of our own mouse position, so that moving the mouse while in + // game mode does not move the position of the GUI cursor + mMouseX += arg.state.X.rel; + mMouseY += arg.state.Y.rel; + mMouseX = std::max(0, std::min(mMouseX, viewSize.width)); + mMouseY = std::max(0, std::min(mMouseY, viewSize.height)); + + MyGUI::InputManager::getInstance().injectMouseMove(mMouseX, mMouseY, arg.state.Z.abs); + } + + if (mMouseLookEnabled) + { + float x = arg.state.X.rel * 0.2; + float y = arg.state.Y.rel * 0.2; + + MWBase::World *world = MWBase::Environment::get().getWorld(); + world->rotateObject(world->getPlayer().getPlayer(), -y, 0.f, x, true); + } + + return true; + } + + void InputManager::toggleMainMenu() + { + if (mWindows.isGuiMode () && (mWindows.getMode () == MWGui::GM_MainMenu || mWindows.getMode () == MWGui::GM_Settings)) + mWindows.popGuiMode(); + else + mWindows.pushGuiMode (MWGui::GM_MainMenu); + } + + void InputManager::toggleSpell() + { + if (mWindows.isGuiMode()) return; + + MWMechanics::DrawState_ state = mPlayer.getDrawState(); + if (state == MWMechanics::DrawState_Weapon || state == MWMechanics::DrawState_Nothing) + { + mPlayer.setDrawState(MWMechanics::DrawState_Spell); + std::cout << "Player has now readied his hands for spellcasting!\n" << std::endl; + } + else + { + mPlayer.setDrawState(MWMechanics::DrawState_Nothing); + std::cout << "Player does not have any kind of attack ready now.\n" << std::endl; + } + } + + void InputManager::toggleWeapon() + { + if (mWindows.isGuiMode()) return; + + MWMechanics::DrawState_ state = mPlayer.getDrawState(); + if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing) + { + mPlayer.setDrawState(MWMechanics::DrawState_Weapon); + std::cout << "Player is now drawing his weapon.\n" << std::endl; + } + else + { + mPlayer.setDrawState(MWMechanics::DrawState_Nothing); + std::cout << "Player does not have any kind of attack ready now.\n" << std::endl; + } + } + + void InputManager::screenshot() + { + mEngine.screenshot(); + + std::vector empty; + mWindows.messageBox ("Screenshot saved", empty); + } + + void InputManager::toggleInventory() + { + bool gameMode = !mWindows.isGuiMode(); + + // Toggle between game mode and inventory mode + if(gameMode) + mWindows.pushGuiMode(MWGui::GM_Inventory); + else if(mWindows.getMode() == MWGui::GM_Inventory) + mWindows.popGuiMode(); + + // .. but don't touch any other mode. + } + + void InputManager::toggleConsole() + { + bool gameMode = !mWindows.isGuiMode(); + + // Switch to console mode no matter what mode we are currently + // in, except of course if we are already in console mode + if (!gameMode) + { + if (mWindows.getMode() == MWGui::GM_Console) + mWindows.popGuiMode(); + else + mWindows.pushGuiMode(MWGui::GM_Console); + } + else + mWindows.pushGuiMode(MWGui::GM_Console); + } + + void InputManager::toggleJournal() + { + // Toggle between game mode and journal mode + bool gameMode = !mWindows.isGuiMode(); + + if(gameMode) + mWindows.pushGuiMode(MWGui::GM_Journal); + else if(mWindows.getMode() == MWGui::GM_Journal) + mWindows.popGuiMode(); + // .. but don't touch any other mode. + } + + void InputManager::activate() + { + mEngine.activate(); + } + + void InputManager::toggleAutoMove() + { + if (mWindows.isGuiMode()) return; + mPlayer.setAutoMove (!mPlayer.getAutoMove()); + } + + void InputManager::toggleWalking() + { + if (mWindows.isGuiMode()) return; + mPlayer.toggleRunning(); + } + + // Exit program now button (which is disabled in GUI mode) + void InputManager::exitNow() + { + if(!mWindows.isGuiMode()) + Ogre::Root::getSingleton().queueEndRendering (); + } + + bool InputManager::actionIsActive (int id) + { + return mInputCtrl->getChannel (id)->getValue () == 1; + } + } diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 5092198da..ba42327ee 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -9,20 +9,20 @@ namespace OEngine { - namespace Render - { - class OgreRenderer; - } + namespace Render + { + class OgreRenderer; + } } namespace MWWorld { - class Player; + class Player; } namespace MWBase { - class WindowManager; + class WindowManager; } namespace OMW @@ -30,37 +30,154 @@ namespace OMW class Engine; } +namespace ICS +{ + class InputControlSystem; +} + +namespace OIS +{ + class Keyboard; + class Mouse; + class InputManager; +} + +#include +#include + +#include + namespace MWInput { - // Forward declaration of the real implementation. - class InputImpl; - /* Class that handles all input and key bindings for OpenMW. + /** + * @brief Class that handles all input and key bindings for OpenMW. + */ + class InputManager : public MWBase::InputManager, public OIS::KeyListener, public OIS::MouseListener, public ICS::ChannelListener + { + public: + InputManager(OEngine::Render::OgreRenderer &_ogre, + MWWorld::Player&_player, + MWBase::WindowManager &_windows, + bool debug, + OMW::Engine& engine, + const std::string& defaultFile, + const std::string& userFile, bool userFileExists); + + virtual ~InputManager(); + + virtual void update(float dt); + + virtual void changeInputMode(bool guiMode); + + virtual void processChangedSettings(const Settings::CategorySettingVector& changed); + + virtual void setDragDrop(bool dragDrop); + + virtual void toggleControlSwitch (const std::string& sw, bool value); + + + public: + virtual bool keyPressed( const OIS::KeyEvent &arg ); + virtual bool keyReleased( const OIS::KeyEvent &arg ); + + virtual bool mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id ); + virtual bool mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id ); + virtual bool mouseMoved( const OIS::MouseEvent &arg ); + + virtual void channelChanged(ICS::Channel* channel, float currentValue, float previousValue); + + private: + OEngine::Render::OgreRenderer &mOgre; + MWWorld::Player &mPlayer; + MWBase::WindowManager &mWindows; + OMW::Engine& mEngine; + + ICS::InputControlSystem* mInputCtrl; + + OIS::Keyboard* mKeyboard; + OIS::Mouse* mMouse; + OIS::InputManager* mInputManager; + + std::string mUserFile; + + bool mDragDrop; + + bool mMouseLookEnabled; + bool mGuiCursorEnabled; + + int mMouseX; + int mMouseY; + + std::map mControlSwitch; + + + private: + void adjustMouseRegion(int width, int height); + + private: + void toggleMainMenu(); + void toggleSpell(); + void toggleWeapon(); + void toggleInventory(); + void toggleConsole(); + void screenshot(); + void toggleJournal(); + void activate(); + void toggleWalking(); + void toggleAutoMove(); + void exitNow(); + + bool actionIsActive (int id); + + private: + enum Actions + { + // please add new actions at the bottom, in order to preserve the channel IDs in the key configuration files + + A_GameMenu, + + A_Quit, // Exit the program + + A_Screenshot, // Take a screenshot + + A_Inventory, // Toggle inventory screen + + A_Console, // Toggle console screen - This class is just an interface. All the messy details are in - inputmanager.cpp. - */ - struct MWInputManager : public MWBase::InputManager - { - InputImpl *impl; + A_MoveLeft, // Move player left / right + A_MoveRight, + A_MoveForward, // Forward / Backward + A_MoveBackward, - public: - MWInputManager(OEngine::Render::OgreRenderer &_ogre, - MWWorld::Player&_player, - MWBase::WindowManager &_windows, - bool debug, - OMW::Engine& engine); - virtual ~MWInputManager(); + A_Activate, - virtual void update(); + A_Use, //Use weapon, spell, etc. + A_Jump, + A_AutoMove, //Toggle Auto-move forward + A_Rest, //Rest + A_Journal, //Journal + A_Weapon, //Draw/Sheath weapon + A_Spell, //Ready/Unready Casting + A_AlwaysRun, //Toggle Always Run + A_CycleSpellLeft, //cycling through spells + A_CycleSpellRight, + A_CycleWeaponLeft,//Cycling through weapons + A_CycleWeaponRight, + A_ToggleSneak, //Toggles Sneak, add Push-Sneak later + A_ToggleWalk, //Toggle Walking/Running + A_Crouch, - virtual void changeInputMode(bool guiMode); + A_QuickSave, + A_QuickLoad, + A_QuickMenu, + A_ToggleWeapon, + A_ToggleSpell, - virtual void processChangedSettings(const Settings::CategorySettingVector& changed); + A_LAST // Marker for the last item + }; - virtual void setDragDrop(bool dragDrop); - virtual void toggleControlSwitch (const std::string& sw, bool value); - }; + }; } #endif diff --git a/apps/openmw/mwinput/mouselookevent.cpp b/apps/openmw/mwinput/mouselookevent.cpp deleted file mode 100644 index f318ce666..000000000 --- a/apps/openmw/mwinput/mouselookevent.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "mouselookevent.hpp" - -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - -#include "../mwworld/player.hpp" - -#include -#include -#include - -using namespace OIS; -using namespace MWInput; - -void MouseLookEvent::event(Type type, int index, const void *p) -{ - if (type != EV_MouseMove || mDisabled) { - return; - } - - MouseEvent *arg = (MouseEvent*)(p); - - float x = arg->state.X.rel * sensX; - float y = arg->state.Y.rel * sensY; - - MWBase::World *world = MWBase::Environment::get().getWorld(); - world->rotateObject(world->getPlayer().getPlayer(), -y, 0.f, x, true); -} diff --git a/apps/openmw/mwinput/mouselookevent.hpp b/apps/openmw/mwinput/mouselookevent.hpp deleted file mode 100644 index af996643f..000000000 --- a/apps/openmw/mwinput/mouselookevent.hpp +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef _MWINPUT_MOUSELOOKEVENT_H -#define _MWINPUT_MOUSELOOKEVENT_H - -/* - A mouse-look class for Ogre. Accepts input events from Mangle::Input - and translates them. - - You can adjust the mouse sensibility and switch to a different - camera. The mouselook class also has an optional wrap protection - that keeps the camera from flipping upside down. - - You can disable the mouse looker at any time by calling - setCamera(NULL), and reenable it by setting the camera back. - - NOTE: The current implementation will ONLY work for native OIS - events. - */ - -#include - -namespace MWInput -{ - class MouseLookEvent : public Mangle::Input::Event - { - float sensX, sensY; // Mouse sensibility - bool flipProt; // Flip protection - bool mDisabled; - - public: - MouseLookEvent(float sX = 0.2, float sY = 0.2, bool prot=true) - : sensX(sX), sensY(sY), flipProt(prot) - {} - - void setSens(float sX, float sY) { - sensX = sX; - sensY = sY; - } - - void setProt(bool p) { - flipProt = p; - } - - void disable() { - mDisabled = true; - } - - void enable() { - mDisabled = false; - } - - void event(Type type, int index, const void *p); - }; - - typedef boost::shared_ptr MouseLookEventPtr; -} - -#endif diff --git a/extern/oics/CMakeLists.txt b/extern/oics/CMakeLists.txt new file mode 100644 index 000000000..7c14387a4 --- /dev/null +++ b/extern/oics/CMakeLists.txt @@ -0,0 +1,20 @@ +set(OICS_LIBRARY "oics") + +# Sources + +set(OICS_SOURCE_FILES + ICSChannel.cpp + ICSControl.cpp + ICSInputControlSystem.cpp + ICSInputControlSystem_keyboard.cpp + ICSInputControlSystem_mouse.cpp + ICSInputControlSystem_joystick.cpp + tinyxml.cpp + tinyxmlparser.cpp + tinyxmlerror.cpp + tinystr.cpp +) + +add_library(${OICS_LIBRARY} STATIC ${OICS_SOURCE_FILES}) + +link_directories(${CMAKE_CURRENT_BINARY_DIR}) diff --git a/extern/oics/ICSChannel.cpp b/extern/oics/ICSChannel.cpp new file mode 100644 index 000000000..703f2207c --- /dev/null +++ b/extern/oics/ICSChannel.cpp @@ -0,0 +1,258 @@ +/* ------------------------------------------------------- +Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es) + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of +the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------- */ + +#include "ICSInputControlSystem.h" + +#define B1(t) (t*t) +#define B2(t) (2*t*(1-t)) +#define B3(t) ((1-t)*(1-t)) + +namespace ICS +{ + Channel::Channel(int number, float initialValue + , float bezierMidPointY, float bezierMidPointX, float symmetricAt, float bezierStep) + : mNumber(number) + , mValue(initialValue) + , mSymmetricAt(symmetricAt) + , mBezierStep(bezierStep) + { + mBezierMidPoint.x = bezierMidPointX; + mBezierMidPoint.y = bezierMidPointY; + + setBezierFunction(bezierMidPointY, bezierMidPointX, symmetricAt, bezierStep); + } + + float Channel::getValue() + { + if(mValue == 0 || mValue == 1) + { + return mValue; + } + + BezierFunction::iterator it = mBezierFunction.begin(); + //size_t size_minus_1 = mBezierFunction.size() - 1; + BezierFunction::iterator last = mBezierFunction.end(); + last--; + for ( ; it != last ; ) + { + BezierPoint left = (*it); + BezierPoint right = (*(++it)); + + if( (left.x <= mValue) && (right.x > mValue) ) + { + float val = left.y - (left.x - mValue) * (left.y - right.y) / (left.x - right.x); + + return std::max(0.0,std::min(1.0, val)); + } + } + + return -1; + } + + void Channel::setValue(float value) + { + float previousValue = this->getValue(); + + mValue = value; + + if(previousValue != value) + { + notifyListeners(previousValue); + } + } + + void Channel::notifyListeners(float previousValue) + { + std::list::iterator pos = mListeners.begin(); + while (pos != mListeners.end()) + { + ((ChannelListener* )(*pos))->channelChanged((Channel*)this, this->getValue(), previousValue); + ++pos; + } + } + + void Channel::addControl(Control* control, Channel::ChannelDirection dir, float percentage) + { + ControlChannelBinderItem ccBinderItem; + ccBinderItem.control = control; + ccBinderItem.direction = dir; + ccBinderItem.percentage = percentage; + + mAttachedControls.push_back(ccBinderItem); + } + + Channel::ControlChannelBinderItem Channel::getAttachedControlBinding(Control* control) + { + for(std::vector::iterator it = mAttachedControls.begin() ; + it != mAttachedControls.end() ; it++) + { + if((*it).control == control) + { + return (*it); + } + } + + ControlChannelBinderItem nullBinderItem; + nullBinderItem.control = NULL; + nullBinderItem.direction = Channel/*::ChannelDirection*/::DIRECT; + nullBinderItem.percentage = 0; + return nullBinderItem; + } + + void Channel::update() + { + if(this->getControlsCount() == 1) + { + ControlChannelBinderItem ccBinderItem = mAttachedControls.back(); + float diff = ccBinderItem.control->getValue() - ccBinderItem.control->getInitialValue(); + + if(ccBinderItem.direction == ICS::Channel::DIRECT) + { + this->setValue(ccBinderItem.control->getInitialValue() + (ccBinderItem.percentage * diff)); + } + else + { + this->setValue(ccBinderItem.control->getInitialValue() - (ccBinderItem.percentage * diff)); + } + } + else + { + float val = 0; + std::vector::const_iterator it; + for(it=mAttachedControls.begin(); it!=mAttachedControls.end(); ++it) + { + ControlChannelBinderItem ccBinderItem = (*it); + float diff = ccBinderItem.control->getValue() - ccBinderItem.control->getInitialValue(); + + if(ccBinderItem.direction == ICS::Channel::DIRECT) + { + val += (ccBinderItem.percentage * diff); + } + else + { + val -= (ccBinderItem.percentage * diff); + } + } + + if(mAttachedControls.size() > 0) + { + this->setValue(mAttachedControls.begin()->control->getInitialValue() + val); + } + } + } + + void Channel::setBezierFunction(float bezierMidPointY, float bezierMidPointX, float symmetricAt, float bezierStep) + { + mBezierMidPoint.x = bezierMidPointX; + mBezierMidPoint.y = bezierMidPointY; + mBezierStep = bezierStep; + mSymmetricAt = symmetricAt; + + mBezierFunction.clear(); + + BezierPoint start; + start.x = 0; + start.y = 0; + + BezierPoint end; + end.x = 1; + end.y = 1; + mBezierFunction.push_front(end); + + FilterInterval interval; + interval.startX = start.x; + interval.startY = start.y; + interval.midX = mBezierMidPoint.x; + interval.midY = mBezierMidPoint.y; + interval.endX = end.x; + interval.endY = end.y; + interval.step = bezierStep; + mIntervals.push_back(interval); + + if(!(mBezierMidPoint.x == 0.5 && mBezierMidPoint.y == 0.5)) + { + float t = mBezierStep; + while(t < 1) + { + BezierPoint p; + p.x = start.x * B1(t) + mBezierMidPoint.x * B2(t) + end.x * B3(t); + p.y = start.y * B1(t) + mBezierMidPoint.y * B2(t) + end.y * B3(t); + mBezierFunction.push_front(p); + + t += mBezierStep; + } + } + + mBezierFunction.push_front(start); + } + + void Channel::addBezierInterval(float startX, float startY, float midX, float midY + , float endX, float endY, float step) + { + FilterInterval interval; + interval.startX = startX; + interval.startY = startY; + interval.midX = midX; + interval.midY = midY; + interval.endX = endX; + interval.endY = endY; + interval.step = step; + mIntervals.push_back(interval); + + float t = 0; + while(t <= 1) + { + BezierPoint p; + p.x = startX * B1(t) + midX * B2(t) + endX * B3(t); + p.y = startY * B1(t) + midY * B2(t) + endY * B3(t); + + BezierFunction::iterator it = mBezierFunction.begin(); + while( it != mBezierFunction.end() ) + { + BezierPoint left = (*it); + BezierPoint right; + ++it; + if( it != mBezierFunction.end() ) + { + right = (*it); + } + else + { + right.x = endX; + right.y = endY; + } + + if(p.x > left.x && p.x < right.x) + { + mBezierFunction.insert(it, p); + break; + } + } + + t += 1.0f / ((endX-startX)/step); + } + } +} \ No newline at end of file diff --git a/extern/oics/ICSChannel.h b/extern/oics/ICSChannel.h new file mode 100644 index 000000000..f98f0d94d --- /dev/null +++ b/extern/oics/ICSChannel.h @@ -0,0 +1,122 @@ +/* ------------------------------------------------------- +Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es) + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of +the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------- */ + +#ifndef _Channel_H_ +#define _Channel_H_ + +#include "ICSPrerequisites.h" + +#include "ICSChannelListener.h" + +namespace ICS +{ + struct FilterInterval{ + //std::string type; //! @todo uncomment when more types implemented + float startX; + float startY; + float midX; + float midY; + float endX; + float endY; + float step; + }; + + typedef std::list IntervalList; + + class DllExport Channel + { + public: + enum ChannelDirection + { + INVERSE = -1, DIRECT = 1 + }; + + typedef struct { + ChannelDirection direction; + float percentage; + Control* control; + } ControlChannelBinderItem; + + + Channel(int number, float initialValue = 0.5 + , float bezierMidPointY = 0.5, float bezierMidPointX = 0.5 + , float symmetricAt = 0, float bezierStep = 0.2); //! @todo implement symetry + ~Channel(){}; + + void setValue(float value); + float getValue(); + + inline int getNumber(){ return mNumber; }; + + void addControl(Control* control, Channel::ChannelDirection dir, float percentage); + inline size_t getControlsCount(){ return mAttachedControls.size(); }; + std::vector getAttachedControls(){ return mAttachedControls; }; + ControlChannelBinderItem getAttachedControlBinding(Control* control); + + void addListener(ChannelListener* ob){ mListeners.push_back(ob); }; + void removeListener(ChannelListener* ob){ mListeners.remove(ob); }; + + void update(); + + void setBezierFunction(float bezierMidPointY, float bezierMidPointX = 0.5 + , float symmetricAt = 0, float bezierStep = 0.2); + + void addBezierInterval(float startX, float startY, float midX, float midY + , float endX, float endY, float step = 0.1); + + IntervalList& getIntervals(){ return mIntervals; }; + + protected: + + int mNumber; + float mValue; + + struct BezierPoint{ + float x; + float y; + bool operator < (const BezierPoint& other){ return x < other.x; } + }; + + typedef std::list BezierFunction; + + BezierPoint mBezierMidPoint; + BezierFunction mBezierFunction; + float mSymmetricAt; + float mBezierStep; + + IntervalList mIntervals; + + std::vector mAttachedControls; + + std::list mListeners; + void notifyListeners(float previousValue); + + }; + +} + + +#endif \ No newline at end of file diff --git a/extern/oics/ICSChannelListener.h b/extern/oics/ICSChannelListener.h new file mode 100644 index 000000000..d520b3bce --- /dev/null +++ b/extern/oics/ICSChannelListener.h @@ -0,0 +1,46 @@ +/* ------------------------------------------------------- +Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es) + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of +the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------- */ + +#ifndef _ChannelListener_H_ +#define _ChannelListener_H_ + +#include "ICSPrerequisites.h" + +#include "ICSChannel.h" + +namespace ICS +{ + + class DllExport ChannelListener + { + public: + virtual void channelChanged(Channel* channel, float currentValue, float previousValue) = 0; + }; + +} + + +#endif \ No newline at end of file diff --git a/extern/oics/ICSControl.cpp b/extern/oics/ICSControl.cpp new file mode 100644 index 000000000..d43733727 --- /dev/null +++ b/extern/oics/ICSControl.cpp @@ -0,0 +1,161 @@ +/* ------------------------------------------------------- +Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es) + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of +the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------- */ + +#include "ICSInputControlSystem.h" + +#include "ICSControl.h" + +namespace ICS +{ + Control::Control(const std::string name, bool autoChangeDirectionOnLimitsAfterStop, bool autoReverseToInitialValue + , float initialValue, float stepSize, float stepsPerSeconds, bool axisBindable) + : mName(name) + , mValue(initialValue) + , mInitialValue(initialValue) + , mStepSize(stepSize) + , mStepsPerSeconds(stepsPerSeconds) + , mAutoReverseToInitialValue(autoReverseToInitialValue) + , mIgnoreAutoReverse(false) + , mAutoChangeDirectionOnLimitsAfterStop(autoChangeDirectionOnLimitsAfterStop) + , mAxisBindable(axisBindable) + , currentChangingDirection(STOP) + { + + } + + Control::~Control() + { + mAttachedChannels.clear(); + } + + void Control::setValue(float value) + { + float previousValue = mValue; + + mValue = std::max(0.0,std::min(1.0,value)); + + if(mValue != previousValue) + { + updateChannels(); + + notifyListeners(previousValue); + } + } + + void Control::attachChannel(Channel* channel, Channel::ChannelDirection direction, float percentage) + { + mAttachedChannels.push_back(channel); + channel->addControl(this, direction, percentage); + } + + void Control::updateChannels() + { + std::list::iterator pos = mAttachedChannels.begin(); + while (pos != mAttachedChannels.end()) + { + ((Channel* )(*pos))->update(); + ++pos; + } + } + + void Control::notifyListeners(float previousValue) + { + std::list::iterator pos = mListeners.begin(); + while (pos != mListeners.end()) + { + ((ControlListener* )(*pos))->controlChanged((Control*)this, this->getValue(), previousValue); + ++pos; + } + } + + void Control::setChangingDirection(ControlChangingDirection direction) + { + currentChangingDirection = direction; + mPendingActions.push_back(direction); + } + + void Control::update(float timeSinceLastFrame) + { + if(mPendingActions.size() > 0) + { + size_t timedActionsCount = 0; + + std::list::iterator cached_end = mPendingActions.end(); + for(std::list::iterator it = mPendingActions.begin() ; + it != cached_end ; it++) + { + if( (*it) != Control::STOP ) + { + timedActionsCount++; + } + } + + float timeSinceLastFramePart = timeSinceLastFrame / std::max(1, timedActionsCount); + for(std::list::iterator it = mPendingActions.begin() ; + it != cached_end ; it++) + { + if( (*it) != Control::STOP ) + { + this->setValue(mValue + + (((int)(*it)) * mStepSize * mStepsPerSeconds * (timeSinceLastFramePart))); + } + else if(mAutoReverseToInitialValue && !mIgnoreAutoReverse && mValue != mInitialValue ) + { + + if(mValue > mInitialValue) + { + this->setValue( std::max( mInitialValue, + mValue - (mStepSize * mStepsPerSeconds * (timeSinceLastFramePart)))); + } + else if(mValue < mInitialValue) + { + this->setValue( std::min( mInitialValue, + mValue + (mStepSize * mStepsPerSeconds * (timeSinceLastFramePart)))); + } + } + } + mPendingActions.clear(); + } + else if( currentChangingDirection != Control::STOP ) + { + this->setValue(mValue + + (((int)currentChangingDirection) * mStepSize * mStepsPerSeconds * (timeSinceLastFrame))); + } + else if(mAutoReverseToInitialValue && !mIgnoreAutoReverse && mValue != mInitialValue ) + { + if(mValue > mInitialValue) + { + this->setValue( std::max( mInitialValue, + mValue - (mStepSize * mStepsPerSeconds * (timeSinceLastFrame)))); + } + else if(mValue < mInitialValue) + { + this->setValue( std::min( mInitialValue, + mValue + (mStepSize * mStepsPerSeconds * (timeSinceLastFrame)))); + } + } + } +} diff --git a/extern/oics/ICSControl.h b/extern/oics/ICSControl.h new file mode 100644 index 000000000..73f1d5494 --- /dev/null +++ b/extern/oics/ICSControl.h @@ -0,0 +1,107 @@ +/* ------------------------------------------------------- +Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es) + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of +the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------- */ + +#ifndef _Control_H_ +#define _Control_H_ + +#include "ICSPrerequisites.h" + +#include "ICSChannel.h" +#include "ICSControlListener.h" + +namespace ICS +{ + + class DllExport Control + { + public: + + enum ControlChangingDirection + { + DECREASE = -1, STOP = 0, INCREASE = 1 + }; + + Control(const std::string name, bool autoChangeDirectionOnLimitsAfterStop = false, bool autoReverseToInitialValue = false, float initialValue = 0.5, float stepSize = 0.1, float stepsPerSeconds = 2.0, bool axisBindable = true); + ~Control(); + + void setChangingDirection(ControlChangingDirection direction); + inline ControlChangingDirection getChangingDirection(){ return currentChangingDirection; }; + + void setValue(float value); + inline float getValue(){ return mValue; }; + inline float getInitialValue(){ return mInitialValue; }; + + void attachChannel(Channel* channel, Channel::ChannelDirection direction, float percentage = 1.0); + std::list getAttachedChannels(){ return mAttachedChannels; }; + + inline float getStepSize(){ return mStepSize; }; + inline float getStepsPerSeconds(){ return mStepsPerSeconds; }; + + inline void setIgnoreAutoReverse(bool value){ mIgnoreAutoReverse = value; }; // mouse disable autoreverse + inline bool isAutoReverseIgnored(){ return mIgnoreAutoReverse; }; + inline bool getAutoReverse(){ return mAutoReverseToInitialValue; }; + + inline bool getAutoChangeDirectionOnLimitsAfterStop(){ return mAutoChangeDirectionOnLimitsAfterStop; }; + + inline std::string getName(){ return mName; }; + + inline bool isAxisBindable(){ return mAxisBindable; }; + inline void setAxisBindable(bool value){ mAxisBindable = value; }; + + inline void addListener(ControlListener* ob){ mListeners.push_back(ob); }; + inline void removeListener(ControlListener* ob){ mListeners.remove(ob); }; + + void update(float timeSinceLastFrame); + + protected: + float mValue; + float mInitialValue; + std::string mName; + float mStepSize; + float mStepsPerSeconds; + bool mAutoReverseToInitialValue; + bool mIgnoreAutoReverse; + bool mAutoChangeDirectionOnLimitsAfterStop; + bool mAxisBindable; + + Control::ControlChangingDirection currentChangingDirection; + std::list mAttachedChannels; + + std::list mListeners; + + std::list mPendingActions; + + protected: + + void updateChannels(); + void notifyListeners(float previousValue); + + }; + +} + + +#endif \ No newline at end of file diff --git a/extern/oics/ICSControlListener.h b/extern/oics/ICSControlListener.h new file mode 100644 index 000000000..067b2d6f2 --- /dev/null +++ b/extern/oics/ICSControlListener.h @@ -0,0 +1,46 @@ +/* ------------------------------------------------------- +Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es) + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of +the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------- */ + +#ifndef _ControlListener_H_ +#define _ControlListener_H_ + +#include "ICSPrerequisites.h" + +#include "ICSControl.h" + +namespace ICS +{ + + class DllExport ControlListener + { + public: + virtual void controlChanged(Control* control, float currentValue, float previousValue) = 0; + }; + +} + + +#endif \ No newline at end of file diff --git a/extern/oics/ICSInputControlSystem.cpp b/extern/oics/ICSInputControlSystem.cpp new file mode 100644 index 000000000..1702c853e --- /dev/null +++ b/extern/oics/ICSInputControlSystem.cpp @@ -0,0 +1,929 @@ +/* ------------------------------------------------------- +Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es) + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of +the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------- */ + +#include "ICSInputControlSystem.h" + +namespace ICS +{ + InputControlSystem::InputControlSystem(std::string file, bool active + , DetectingBindingListener* detectingBindingListener + , InputControlSystemLog* log, size_t channelCount) + : mFileName(file) + , mDetectingBindingListener(detectingBindingListener) + , mDetectingBindingControl(NULL) + , mLog(log) + , mXmouseAxisBinded(false), mYmouseAxisBinded(false) + { + ICS_LOG(" - Creating InputControlSystem - "); + + this->mActive = active; + + this->fillOISKeysMap(); + + ICS_LOG("Channel count = " + ToString(channelCount) ); + for(size_t i=0;iLoadFile(); + + if(xmlDoc->Error()) + { + std::ostringstream message; + message << "TinyXml reported an error reading \""+ file + "\". Row " << + (int)xmlDoc->ErrorRow() << ", Col " << (int)xmlDoc->ErrorCol() << ": " << + xmlDoc->ErrorDesc() ; + ICS_LOG(message.str()); + + delete xmlDoc; + return; + } + + xmlRoot = xmlDoc->RootElement(); + if(std::string(xmlRoot->Value()) != "Controller") { + ICS_LOG("Error: Invalid Controller file. Missing element."); + delete xmlDoc; + return; + } + + TiXmlElement* xmlControl = xmlRoot->FirstChildElement("Control"); + + size_t controlChannelCount = 0; + while(xmlControl) + { + TiXmlElement* xmlChannel = xmlControl->FirstChildElement("Channel"); + while(xmlChannel) + { + controlChannelCount = std::max(channelCount, FromString(xmlChannel->Attribute("number"))); + + xmlChannel = xmlChannel->NextSiblingElement("Channel"); + } + + xmlControl = xmlControl->NextSiblingElement("Control"); + } + + if(controlChannelCount > channelCount) + { + size_t dif = controlChannelCount - channelCount; + ICS_LOG("Warning: default channel count exceeded. Adding " + ToString(dif) + " channels" ); + for(size_t i = channelCount ; i < controlChannelCount ; i++) + { + mChannels.push_back(new Channel((int)i)); + } + } + + ICS_LOG("Applying filters to channels"); + // + // + // + // + + TiXmlElement* xmlChannelFilter = xmlRoot->FirstChildElement("ChannelFilter"); + while(xmlChannelFilter) + { + int ch = FromString(xmlChannelFilter->Attribute("number")); + + TiXmlElement* xmlInterval = xmlChannelFilter->FirstChildElement("Interval"); + while(xmlInterval) + { + std::string type = xmlInterval->Attribute("type"); + + if(type == "bezier") + { + float step = 0.1; + + float startX = FromString(xmlInterval->Attribute("startX")); + float startY = FromString(xmlInterval->Attribute("startY")); + float midX = FromString(xmlInterval->Attribute("midX")); + float midY = FromString(xmlInterval->Attribute("midY")); + float endX = FromString(xmlInterval->Attribute("endX")); + float endY = FromString(xmlInterval->Attribute("endY")); + + step = FromString(xmlInterval->Attribute("step")); + + ICS_LOG("Applying Bezier filter to channel [number=" + + ToString(ch) + ", startX=" + + ToString(startX) + ", startY=" + + ToString(startY) + ", midX=" + + ToString(midX) + ", midY=" + + ToString(midY) + ", endX=" + + ToString(endX) + ", endY=" + + ToString(endY) + ", step=" + + ToString(step) + "]"); + + mChannels.at(ch)->addBezierInterval(startX, startY, midX, midY, endX, endY, step); + } + + xmlInterval = xmlInterval->NextSiblingElement("Interval"); + } + + + xmlChannelFilter = xmlChannelFilter->NextSiblingElement("ChannelFilter"); + } + + xmlControl = xmlRoot->FirstChildElement("Control"); + while(xmlControl) + { + bool axisBindable = true; + if(xmlControl->Attribute("axisBindable")) + { + axisBindable = (std::string( xmlControl->Attribute("axisBindable") ) == "true"); + } + + ICS_LOG("Adding Control [name=" + + std::string( xmlControl->Attribute("name") ) + ", autoChangeDirectionOnLimitsAfterStop=" + + std::string( xmlControl->Attribute("autoChangeDirectionOnLimitsAfterStop") ) + ", autoReverseToInitialValue=" + + std::string( xmlControl->Attribute("autoReverseToInitialValue") ) + ", initialValue=" + + std::string( xmlControl->Attribute("initialValue") ) + ", stepSize=" + + std::string( xmlControl->Attribute("stepSize") ) + ", stepsPerSeconds=" + + std::string( xmlControl->Attribute("stepsPerSeconds") ) + ", axisBindable=" + + std::string( (axisBindable)? "true" : "false" ) + "]"); + + float _stepSize = 0; + if(xmlControl->Attribute("stepSize")) + { + std::string value(xmlControl->Attribute("stepSize")); + if(value == "MAX") + { + _stepSize = ICS_MAX; + } + else + { + _stepSize = FromString(value.c_str()); + } + } + else + { + ICS_LOG("Warning: no stepSize value found. Default value is 0."); + } + + float _stepsPerSeconds = 0; + if(xmlControl->Attribute("stepsPerSeconds")) + { + std::string value(xmlControl->Attribute("stepsPerSeconds")); + if(value == "MAX") + { + _stepsPerSeconds = ICS_MAX; + } + else + { + _stepsPerSeconds = FromString(value.c_str()); + } + } + else + { + ICS_LOG("Warning: no stepSize value found. Default value is 0."); + } + + addControl( new Control(xmlControl->Attribute("name") + , std::string( xmlControl->Attribute("autoChangeDirectionOnLimitsAfterStop") ) == "true" + , std::string( xmlControl->Attribute("autoReverseToInitialValue") ) == "true" + , FromString(xmlControl->Attribute("initialValue")) + , _stepSize + , _stepsPerSeconds + , axisBindable) ); + + loadKeyBinders(xmlControl); + + loadMouseAxisBinders(xmlControl); + + loadMouseButtonBinders(xmlControl); + + loadJoystickAxisBinders(xmlControl); + + loadJoystickButtonBinders(xmlControl); + + loadJoystickPOVBinders(xmlControl); + + loadJoystickSliderBinders(xmlControl); + + // Attach controls to channels + TiXmlElement* xmlChannel = xmlControl->FirstChildElement("Channel"); + while(xmlChannel) + { + ICS_LOG("\tAttaching control to channel [number=" + + std::string( xmlChannel->Attribute("number") ) + ", direction=" + + std::string( xmlChannel->Attribute("direction") ) + "]"); + + float percentage = 1; + if(xmlChannel->Attribute("percentage")) + { + if(StringIsNumber(xmlChannel->Attribute("percentage"))) + { + float val = FromString(xmlChannel->Attribute("percentage")); + if(val > 1 || val < 0) + { + ICS_LOG("ERROR: attaching percentage value range is [0,1]"); + } + else + { + percentage = val; + } + } + else + { + ICS_LOG("ERROR: attaching percentage value range is [0,1]"); + } + } + + int chNumber = FromString(xmlChannel->Attribute("number")); + if(std::string(xmlChannel->Attribute("direction")) == "DIRECT") + { + mControls.back()->attachChannel(mChannels[ chNumber ],Channel::DIRECT, percentage); + } + else if(std::string(xmlChannel->Attribute("direction")) == "INVERSE") + { + mControls.back()->attachChannel(mChannels[ chNumber ],Channel::INVERSE, percentage); + } + + xmlChannel = xmlChannel->NextSiblingElement("Channel"); + } + + xmlControl = xmlControl->NextSiblingElement("Control"); + } + + std::vector::const_iterator o; + for(o = mChannels.begin(); o != mChannels.end(); ++o) + { + (*o)->update(); + } + + delete xmlDoc; + } + + ICS_LOG(" - InputControlSystem Created - "); + } + + InputControlSystem::~InputControlSystem() + { + ICS_LOG(" - Deleting InputControlSystem (" + mFileName + ") - "); + + mJoystickIDList.clear(); + + std::vector::const_iterator o; + for(o = mChannels.begin(); o != mChannels.end(); ++o) + { + delete (*o); + } + mChannels.clear(); + + std::vector::const_iterator o2; + for(o2 = mControls.begin(); o2 != mControls.end(); ++o2) + { + delete (*o2); + } + mControls.clear(); + + mControlsKeyBinderMap.clear(); + mControlsMouseButtonBinderMap.clear(); + mControlsJoystickButtonBinderMap.clear(); + + mKeys.clear(); + mKeyCodes.clear(); + + ICS_LOG(" - InputControlSystem deleted - "); + } + + std::string InputControlSystem::getBaseFileName() + { + size_t found = mFileName.find_last_of("/\\"); + std::string file = mFileName.substr(found+1); + + return file.substr(0, file.find_last_of(".")); + } + + bool InputControlSystem::save(std::string fileName) + { + if(fileName != "") + { + mFileName = fileName; + } + + TiXmlDocument doc( mFileName.c_str() ); + + TiXmlDeclaration dec; + dec.Parse( "", 0, TIXML_ENCODING_UNKNOWN ); + doc.InsertEndChild(dec); + + TiXmlElement Controller( "Controller" ); + + for(std::vector::const_iterator o = mChannels.begin() ; o != mChannels.end(); o++) + { + ICS::IntervalList intervals = (*o)->getIntervals(); + + if(intervals.size() > 1) // all channels have a default linear filter + { + TiXmlElement ChannelFilter( "ChannelFilter" ); + + ChannelFilter.SetAttribute("number", ToString((*o)->getNumber()).c_str()); + + ICS::IntervalList::const_iterator interval = intervals.begin(); + while( interval != intervals.end() ) + { + // if not default linear filter + if(!( interval->step == 0.2f + && interval->startX == 0.0f + && interval->startY == 0.0f + && interval->midX == 0.5f + && interval->midY == 0.5f + && interval->endX == 1.0f + && interval->endY == 1.0f )) + { + TiXmlElement XMLInterval( "Interval" ); + + XMLInterval.SetAttribute("type", "bezier"); + XMLInterval.SetAttribute("step", ToString(interval->step).c_str()); + + XMLInterval.SetAttribute("startX", ToString(interval->startX).c_str()); + XMLInterval.SetAttribute("startY", ToString(interval->startY).c_str()); + XMLInterval.SetAttribute("midX", ToString(interval->midX).c_str()); + XMLInterval.SetAttribute("midY", ToString(interval->midY).c_str()); + XMLInterval.SetAttribute("endX", ToString(interval->endX).c_str()); + XMLInterval.SetAttribute("endY", ToString(interval->endY).c_str()); + + ChannelFilter.InsertEndChild(XMLInterval); + } + + interval++; + } + + Controller.InsertEndChild(ChannelFilter); + } + } + + for(std::vector::const_iterator o = mControls.begin() ; o != mControls.end(); o++) + { + TiXmlElement control( "Control" ); + + control.SetAttribute( "name", (*o)->getName().c_str() ); + if((*o)->getAutoChangeDirectionOnLimitsAfterStop()) + { + control.SetAttribute( "autoChangeDirectionOnLimitsAfterStop", "true" ); + } + else + { + control.SetAttribute( "autoChangeDirectionOnLimitsAfterStop", "false" ); + } + if((*o)->getAutoReverse()) + { + control.SetAttribute( "autoReverseToInitialValue", "true" ); + } + else + { + control.SetAttribute( "autoReverseToInitialValue", "false" ); + } + control.SetAttribute( "initialValue", ToString((*o)->getInitialValue()).c_str() ); + + if((*o)->getStepSize() == ICS_MAX) + { + control.SetAttribute( "stepSize", "MAX" ); + } + else + { + control.SetAttribute( "stepSize", ToString((*o)->getStepSize()).c_str() ); + } + + if((*o)->getStepsPerSeconds() == ICS_MAX) + { + control.SetAttribute( "stepsPerSeconds", "MAX" ); + } + else + { + control.SetAttribute( "stepsPerSeconds", ToString((*o)->getStepsPerSeconds()).c_str() ); + } + + if(!(*o)->isAxisBindable()) + { + control.SetAttribute( "axisBindable", "false" ); + } + + if(getKeyBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) != OIS::KC_UNASSIGNED) + { + TiXmlElement keyBinder( "KeyBinder" ); + + keyBinder.SetAttribute( "key", keyCodeToString( + getKeyBinding(*o, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); + keyBinder.SetAttribute( "direction", "INCREASE" ); + control.InsertEndChild(keyBinder); + } + + if(getKeyBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) != OIS::KC_UNASSIGNED) + { + TiXmlElement keyBinder( "KeyBinder" ); + + keyBinder.SetAttribute( "key", keyCodeToString( + getKeyBinding(*o, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); + keyBinder.SetAttribute( "direction", "DECREASE" ); + control.InsertEndChild(keyBinder); + } + + if(getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) + != InputControlSystem/*::NamedAxis*/::UNASSIGNED) + { + TiXmlElement binder( "MouseBinder" ); + + InputControlSystem::NamedAxis axis = + getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE); + if(axis == InputControlSystem/*::NamedAxis*/::X) + { + binder.SetAttribute( "axis", "X" ); + } + else if(axis == InputControlSystem/*::NamedAxis*/::Y) + { + binder.SetAttribute( "axis", "Y" ); + } + else if(axis == InputControlSystem/*::NamedAxis*/::Z) + { + binder.SetAttribute( "axis", "Z" ); + } + + binder.SetAttribute( "direction", "INCREASE" ); + control.InsertEndChild(binder); + } + + if(getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) + != InputControlSystem/*::NamedAxis*/::UNASSIGNED) + { + TiXmlElement binder( "MouseBinder" ); + + InputControlSystem::NamedAxis axis = + getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE); + if(axis == InputControlSystem/*::NamedAxis*/::X) + { + binder.SetAttribute( "axis", "X" ); + } + else if(axis == InputControlSystem/*::NamedAxis*/::Y) + { + binder.SetAttribute( "axis", "Y" ); + } + else if(axis == InputControlSystem/*::NamedAxis*/::Z) + { + binder.SetAttribute( "axis", "Z" ); + } + + binder.SetAttribute( "direction", "DECREASE" ); + control.InsertEndChild(binder); + } + + if(getMouseButtonBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) + != ICS_MAX_DEVICE_BUTTONS) + { + TiXmlElement binder( "MouseButtonBinder" ); + + unsigned int button = getMouseButtonBinding(*o, Control/*::ControlChangingDirection*/::INCREASE); + if(button == OIS::/*MouseButtonID::*/MB_Left) + { + binder.SetAttribute( "button", "LEFT" ); + } + else if(button == OIS::/*MouseButtonID::*/MB_Middle) + { + binder.SetAttribute( "button", "MIDDLE" ); + } + else if(button == OIS::/*MouseButtonID::*/MB_Right) + { + binder.SetAttribute( "button", "RIGHT" ); + } + else + { + binder.SetAttribute( "button", ToString(button).c_str() ); + } + binder.SetAttribute( "direction", "INCREASE" ); + control.InsertEndChild(binder); + } + + if(getMouseButtonBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) + != ICS_MAX_DEVICE_BUTTONS) + { + TiXmlElement binder( "MouseButtonBinder" ); + + unsigned int button = getMouseButtonBinding(*o, Control/*::ControlChangingDirection*/::DECREASE); + if(button == OIS::/*MouseButtonID::*/MB_Left) + { + binder.SetAttribute( "button", "LEFT" ); + } + else if(button == OIS::/*MouseButtonID::*/MB_Middle) + { + binder.SetAttribute( "button", "MIDDLE" ); + } + else if(button == OIS::/*MouseButtonID::*/MB_Right) + { + binder.SetAttribute( "button", "RIGHT" ); + } + else + { + binder.SetAttribute( "button", ToString(button).c_str() ); + } + binder.SetAttribute( "direction", "DECREASE" ); + control.InsertEndChild(binder); + } + + JoystickIDList::const_iterator it = mJoystickIDList.begin(); + while(it != mJoystickIDList.end()) + { + int deviceId = *it; + + if(getJoystickAxisBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE) + != /*NamedAxis::*/UNASSIGNED) + { + TiXmlElement binder( "JoystickAxisBinder" ); + + binder.SetAttribute( "axis", ToString( + getJoystickAxisBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); + + binder.SetAttribute( "direction", "INCREASE" ); + + binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); + + control.InsertEndChild(binder); + } + + if(getJoystickAxisBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE) + != /*NamedAxis::*/UNASSIGNED) + { + TiXmlElement binder( "JoystickAxisBinder" ); + + binder.SetAttribute( "axis", ToString( + getJoystickAxisBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); + + binder.SetAttribute( "direction", "DECREASE" ); + + binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); + + control.InsertEndChild(binder); + } + + if(getJoystickButtonBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE) + != ICS_MAX_DEVICE_BUTTONS) + { + TiXmlElement binder( "JoystickButtonBinder" ); + + binder.SetAttribute( "button", ToString( + getJoystickButtonBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); + + binder.SetAttribute( "direction", "INCREASE" ); + + binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); + + control.InsertEndChild(binder); + } + + if(getJoystickButtonBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE) + != ICS_MAX_DEVICE_BUTTONS) + { + TiXmlElement binder( "JoystickButtonBinder" ); + + binder.SetAttribute( "button", ToString( + getJoystickButtonBinding(*o, *it, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); + + binder.SetAttribute( "direction", "DECREASE" ); + + binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); + + control.InsertEndChild(binder); + } + + if(getJoystickPOVBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE).index >= 0) + { + TiXmlElement binder( "JoystickPOVBinder" ); + + POVBindingPair POVPair = getJoystickPOVBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE); + + binder.SetAttribute( "pov", ToString(POVPair.index).c_str() ); + + binder.SetAttribute( "direction", "INCREASE" ); + + binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); + + if(POVPair.axis == ICS::InputControlSystem::EastWest) + { + binder.SetAttribute( "axis", "EastWest" ); + } + else + { + binder.SetAttribute( "axis", "NorthSouth" ); + } + + control.InsertEndChild(binder); + } + + if(getJoystickPOVBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE).index >= 0) + { + TiXmlElement binder( "JoystickPOVBinder" ); + + POVBindingPair POVPair = getJoystickPOVBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE); + + binder.SetAttribute( "pov", ToString(POVPair.index).c_str() ); + + binder.SetAttribute( "direction", "DECREASE" ); + + binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); + + if(POVPair.axis == ICS::InputControlSystem::EastWest) + { + binder.SetAttribute( "axis", "EastWest" ); + } + else + { + binder.SetAttribute( "axis", "NorthSouth" ); + } + + control.InsertEndChild(binder); + } + + if(getJoystickSliderBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE) + != /*NamedAxis::*/UNASSIGNED) + { + TiXmlElement binder( "JoystickSliderBinder" ); + + binder.SetAttribute( "slider", ToString( + getJoystickSliderBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); + + binder.SetAttribute( "direction", "INCREASE" ); + + binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); + + control.InsertEndChild(binder); + } + + if(getJoystickSliderBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE) + != /*NamedAxis::*/UNASSIGNED) + { + TiXmlElement binder( "JoystickSliderBinder" ); + + binder.SetAttribute( "slider", ToString( + getJoystickSliderBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); + + binder.SetAttribute( "direction", "DECREASE" ); + + binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); + + control.InsertEndChild(binder); + } + + it++; + } + + + std::list channels = (*o)->getAttachedChannels(); + for(std::list::iterator it = channels.begin() ; + it != channels.end() ; it++) + { + TiXmlElement binder( "Channel" ); + + binder.SetAttribute( "number", ToString((*it)->getNumber()).c_str() ); + + Channel::ChannelDirection direction = (*it)->getAttachedControlBinding(*o).direction; + if(direction == Channel/*::ChannelDirection*/::DIRECT) + { + binder.SetAttribute( "direction", "DIRECT" ); + } + else + { + binder.SetAttribute( "direction", "INVERSE" ); + } + + float percentage = (*it)->getAttachedControlBinding(*o).percentage; + binder.SetAttribute( "percentage", ToString(percentage).c_str() ); + + control.InsertEndChild(binder); + } + + Controller.InsertEndChild(control); + } + + doc.InsertEndChild(Controller); + return doc.SaveFile(); + } + + void InputControlSystem::update(float lTimeSinceLastFrame) + { + if(mActive) + { + std::vector::const_iterator it; + for(it=mControls.begin(); it!=mControls.end(); ++it) + { + (*it)->update(lTimeSinceLastFrame); + } + } + + //! @todo Future versions should consider channel exponentials and mixtures, so + // after updating Controls, Channels should be updated according to their values + } + + float InputControlSystem::getChannelValue(int i) + { + return std::max(0.0,std::min(1.0,mChannels[i]->getValue())); + } + + float InputControlSystem::getControlValue(int i) + { + return mControls[i]->getValue(); + } + + void InputControlSystem::addJoystick(int deviceId) + { + ICS_LOG("Adding joystick (device id: " + ToString(deviceId) + ")"); + + for(int j = 0 ; j < ICS_MAX_JOYSTICK_AXIS ; j++) + { + if(mControlsJoystickAxisBinderMap[deviceId].find(j) == mControlsJoystickAxisBinderMap[deviceId].end()) + { + ControlAxisBinderItem controlJoystickBinderItem; + controlJoystickBinderItem.direction = Control::STOP; + controlJoystickBinderItem.control = NULL; + mControlsJoystickAxisBinderMap[deviceId][j] = controlJoystickBinderItem; + } + } + + mJoystickIDList.push_back(deviceId); + } + + Control* InputControlSystem::findControl(std::string name) + { + if(mActive) + { + std::vector::const_iterator it; + for(it = mControls.begin(); it != mControls.end(); ++it) + { + if( ((Control*)(*it))->getName() == name) + { + return (Control*)(*it); + } + } + } + + return NULL; + } + + void InputControlSystem::enableDetectingBindingState(Control* control + , Control::ControlChangingDirection direction) + { + mDetectingBindingControl = control; + mDetectingBindingDirection = direction; + + mMouseAxisBindingInitialValues[0] = ICS_MOUSE_AXIS_BINDING_NULL_VALUE; + } + + void InputControlSystem::cancelDetectingBindingState() + { + mDetectingBindingControl = NULL; + } + + void InputControlSystem::fillOISKeysMap() + { + mKeys["UNASSIGNED"]= OIS::KC_UNASSIGNED; + mKeys["ESCAPE"]= OIS::KC_ESCAPE; + mKeys["1"]= OIS::KC_1; + mKeys["2"]= OIS::KC_2; + mKeys["3"]= OIS::KC_3; + mKeys["4"]= OIS::KC_4; + mKeys["5"]= OIS::KC_5; + mKeys["6"]= OIS::KC_6; + mKeys["7"]= OIS::KC_7; + mKeys["8"]= OIS::KC_8; + mKeys["9"]= OIS::KC_9; + mKeys["0"]= OIS::KC_0; + mKeys["MINUS"]= OIS::KC_MINUS; + mKeys["EQUALS"]= OIS::KC_EQUALS; + mKeys["BACK"]= OIS::KC_BACK; + mKeys["TAB"]= OIS::KC_TAB; + mKeys["Q"]= OIS::KC_Q; + mKeys["W"]= OIS::KC_W; + mKeys["E"]= OIS::KC_E; + mKeys["R"]= OIS::KC_R; + mKeys["T"]= OIS::KC_T; + mKeys["Y"]= OIS::KC_Y; + mKeys["U"]= OIS::KC_U; + mKeys["I"]= OIS::KC_I; + mKeys["O"]= OIS::KC_O; + mKeys["P"]= OIS::KC_P; + mKeys["LBRACKET"]= OIS::KC_LBRACKET; + mKeys["RBRACKET"]= OIS::KC_RBRACKET; + mKeys["RETURN"]= OIS::KC_RETURN; + mKeys["LCONTROL"]= OIS::KC_LCONTROL; + mKeys["A"]= OIS::KC_A; + mKeys["S"]= OIS::KC_S; + mKeys["D"]= OIS::KC_D; + mKeys["F"]= OIS::KC_F; + mKeys["G"]= OIS::KC_G; + mKeys["H"]= OIS::KC_H; + mKeys["J"]= OIS::KC_J; + mKeys["K"]= OIS::KC_K; + mKeys["L"]= OIS::KC_L; + mKeys["SEMICOLON"]= OIS::KC_SEMICOLON; + mKeys["APOSTROPHE"]= OIS::KC_APOSTROPHE; + mKeys["GRAVE"]= OIS::KC_GRAVE; + mKeys["LSHIFT"]= OIS::KC_LSHIFT; + mKeys["BACKSLASH"]= OIS::KC_BACKSLASH; + mKeys["Z"]= OIS::KC_Z; + mKeys["X"]= OIS::KC_X; + mKeys["C"]= OIS::KC_C; + mKeys["V"]= OIS::KC_V; + mKeys["B"]= OIS::KC_B; + mKeys["N"]= OIS::KC_N; + mKeys["M"]= OIS::KC_M; + mKeys["COMMA"]= OIS::KC_COMMA; + mKeys["PERIOD"]= OIS::KC_PERIOD; + mKeys["SLASH"]= OIS::KC_SLASH; + mKeys["RSHIFT"]= OIS::KC_RSHIFT; + mKeys["MULTIPLY"]= OIS::KC_MULTIPLY; + mKeys["LMENU"]= OIS::KC_LMENU; + mKeys["SPACE"]= OIS::KC_SPACE; + mKeys["CAPITAL"]= OIS::KC_CAPITAL; + mKeys["F1"]= OIS::KC_F1; + mKeys["F2"]= OIS::KC_F2; + mKeys["F3"]= OIS::KC_F3; + mKeys["F4"]= OIS::KC_F4; + mKeys["F5"]= OIS::KC_F5; + mKeys["F6"]= OIS::KC_F6; + mKeys["F7"]= OIS::KC_F7; + mKeys["F8"]= OIS::KC_F8; + mKeys["F9"]= OIS::KC_F9; + mKeys["F10"]= OIS::KC_F10; + mKeys["F11"]= OIS::KC_F11; + mKeys["F12"]= OIS::KC_F12; + mKeys["NUMLOCK"]= OIS::KC_NUMLOCK; + mKeys["SCROLL"]= OIS::KC_SCROLL; + mKeys["NUMPAD7"]= OIS::KC_NUMPAD7; + mKeys["NUMPAD8"]= OIS::KC_NUMPAD8; + mKeys["NUMPAD9"]= OIS::KC_NUMPAD9; + mKeys["SUBTRACT"]= OIS::KC_SUBTRACT; + mKeys["NUMPAD4"]= OIS::KC_NUMPAD4; + mKeys["NUMPAD5"]= OIS::KC_NUMPAD5; + mKeys["NUMPAD6"]= OIS::KC_NUMPAD6; + mKeys["ADD"]= OIS::KC_ADD; + mKeys["NUMPAD1"]= OIS::KC_NUMPAD1; + mKeys["NUMPAD2"]= OIS::KC_NUMPAD2; + mKeys["NUMPAD3"]= OIS::KC_NUMPAD3; + mKeys["NUMPAD0"]= OIS::KC_NUMPAD0; + mKeys["DECIMAL"]= OIS::KC_DECIMAL; + mKeys["RCONTROL"]= OIS::KC_RCONTROL; + mKeys["DIVIDE"]= OIS::KC_DIVIDE; + mKeys["SYSRQ"]= OIS::KC_SYSRQ; + mKeys["RMENU"]= OIS::KC_RMENU; + mKeys["PAUSE"]= OIS::KC_PAUSE; + mKeys["HOME"]= OIS::KC_HOME; + mKeys["UP"]= OIS::KC_UP; + mKeys["PGUP"]= OIS::KC_PGUP; + mKeys["LEFT"]= OIS::KC_LEFT; + mKeys["RIGHT"]= OIS::KC_RIGHT; + mKeys["END"]= OIS::KC_END; + mKeys["DOWN"]= OIS::KC_DOWN; + mKeys["PGDOWN"]= OIS::KC_PGDOWN; + mKeys["INSERT"]= OIS::KC_INSERT; + mKeys["DELETE"]= OIS::KC_DELETE; + mKeys["LWIN"]= OIS::KC_LWIN; + mKeys["RWIN"]= OIS::KC_RWIN; + mKeys["APPS"]= OIS::KC_APPS; + + mKeys["NUMPADENTER"]= OIS::KC_NUMPADENTER; + + for(std::map::iterator it = mKeys.begin() + ; it != mKeys.end() ; it++) + { + mKeyCodes[ it->second ] = it->first; + } + } + + std::string InputControlSystem::keyCodeToString(OIS::KeyCode key) + { + return mKeyCodes[key]; + } + + OIS::KeyCode InputControlSystem::stringToKeyCode(std::string key) + { + return mKeys[key]; + } +} \ No newline at end of file diff --git a/extern/oics/ICSInputControlSystem.h b/extern/oics/ICSInputControlSystem.h new file mode 100644 index 000000000..f1c12d3b5 --- /dev/null +++ b/extern/oics/ICSInputControlSystem.h @@ -0,0 +1,256 @@ +/* ------------------------------------------------------- +Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es) + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of +the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------- */ + +#ifndef _InputControlSystem_H_ +#define _InputControlSystem_H_ + +#include "ICSPrerequisites.h" + +#include "ICSControl.h" +#include "ICSChannel.h" + +#define ICS_LOG(text) if(mLog) mLog->logMessage( ("ICS: " + std::string(text)).c_str() ); +#define ICS_MAX_JOYSTICK_AXIS 16 +#define ICS_MOUSE_BINDING_MARGIN 30 +#define ICS_JOYSTICK_AXIS_BINDING_MARGIN 10000 +#define ICS_JOYSTICK_SLIDER_BINDING_MARGIN 10000 +#define ICS_MOUSE_AXIS_BINDING_NULL_VALUE std::numeric_limits::max() + +namespace ICS +{ + class DllExport InputControlSystemLog + { + public: + virtual void logMessage(const char* text) = 0; + }; + + class DllExport InputControlSystem : + public OIS::MouseListener, + public OIS::KeyListener, + public OIS::JoyStickListener + { + + public: + + enum NamedAxis { X = -1, Y = -2, Z = -3, UNASSIGNED = -4 }; + enum POVAxis { NorthSouth = 0, EastWest = 1 }; + + typedef NamedAxis MouseAxis; // MouseAxis is deprecated. It will be removed in future versions + + typedef std::list JoystickIDList; + + typedef struct + { + int index; + POVAxis axis; + } POVBindingPair; + + InputControlSystem(std::string file = "", bool active = true + , DetectingBindingListener* detectingBindingListener = NULL + , InputControlSystemLog* log = NULL, size_t channelCount = 16); + ~InputControlSystem(); + + std::string getFileName(){ return mFileName; }; + std::string getBaseFileName(); + + void setDetectingBindingListener(DetectingBindingListener* detectingBindingListener){ mDetectingBindingListener = detectingBindingListener; }; + DetectingBindingListener* getDetectingBindingListener(){ return mDetectingBindingListener; }; + + // in seconds + void update(float timeSinceLastFrame); + + inline Channel* getChannel(int i){ return mChannels[i]; }; + float getChannelValue(int i); + inline int getChannelCount(){ return (int)mChannels.size(); }; + + inline Control* getControl(int i){ return mControls[i]; }; + float getControlValue(int i); + inline int getControlCount(){ return (int)mControls.size(); }; + inline void addControl(Control* control){ mControls.push_back(control); }; + + Control* findControl(std::string name); + + inline void activate(){ this->mActive = true; }; + inline void deactivate(){ this->mActive = false; }; + + void addJoystick(int deviceId); + JoystickIDList& getJoystickIdList(){ return mJoystickIDList; }; + + // MouseListener + bool mouseMoved(const OIS::MouseEvent &evt); + bool mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID); + bool mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID); + + // KeyListener + bool keyPressed(const OIS::KeyEvent &evt); + bool keyReleased(const OIS::KeyEvent &evt); + + // JoyStickListener + bool buttonPressed(const OIS::JoyStickEvent &evt, int button); + bool buttonReleased(const OIS::JoyStickEvent &evt, int button); + bool axisMoved(const OIS::JoyStickEvent &evt, int axis); + bool povMoved(const OIS::JoyStickEvent &evt, int index); + bool sliderMoved(const OIS::JoyStickEvent &evt, int index); + + void addKeyBinding(Control* control, OIS::KeyCode key, Control::ControlChangingDirection direction); + void addMouseAxisBinding(Control* control, NamedAxis axis, Control::ControlChangingDirection direction); + void addMouseButtonBinding(Control* control, unsigned int button, Control::ControlChangingDirection direction); + void addJoystickAxisBinding(Control* control, int deviceId, int axis, Control::ControlChangingDirection direction); + void addJoystickButtonBinding(Control* control, int deviceId, unsigned int button, Control::ControlChangingDirection direction); + void addJoystickPOVBinding(Control* control, int deviceId, int index, POVAxis axis, Control::ControlChangingDirection direction); + void addJoystickSliderBinding(Control* control, int deviceId, int index, Control::ControlChangingDirection direction); + void removeKeyBinding(OIS::KeyCode key); + void removeMouseAxisBinding(NamedAxis axis); + void removeMouseButtonBinding(unsigned int button); + void removeJoystickAxisBinding(int deviceId, int axis); + void removeJoystickButtonBinding(int deviceId, unsigned int button); + void removeJoystickPOVBinding(int deviceId, int index, POVAxis axis); + void removeJoystickSliderBinding(int deviceId, int index); + + OIS::KeyCode getKeyBinding(Control* control, ICS::Control::ControlChangingDirection direction); + NamedAxis getMouseAxisBinding(Control* control, ICS::Control::ControlChangingDirection direction); + unsigned int getMouseButtonBinding(Control* control, ICS::Control::ControlChangingDirection direction); + int getJoystickAxisBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction); + unsigned int getJoystickButtonBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction); + POVBindingPair getJoystickPOVBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction); + int getJoystickSliderBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction); + + std::string keyCodeToString(OIS::KeyCode key); + OIS::KeyCode stringToKeyCode(std::string key); + + void enableDetectingBindingState(Control* control, Control::ControlChangingDirection direction); + void cancelDetectingBindingState(); + + bool save(std::string fileName = ""); + + protected: + + void loadKeyBinders(TiXmlElement* xmlControlNode); + void loadMouseAxisBinders(TiXmlElement* xmlControlNode); + void loadMouseButtonBinders(TiXmlElement* xmlControlNode); + void loadJoystickAxisBinders(TiXmlElement* xmlControlNode); + void loadJoystickButtonBinders(TiXmlElement* xmlControlNode); + void loadJoystickPOVBinders(TiXmlElement* xmlControlNode); + void loadJoystickSliderBinders(TiXmlElement* xmlControlNode); + + void addMouseAxisBinding_(Control* control, int axis, Control::ControlChangingDirection direction); + void removeMouseAxisBinding_(int axis); + + protected: + + typedef struct { + Control::ControlChangingDirection direction; + Control* control; + } ControlKeyBinderItem; + + typedef ControlKeyBinderItem ControlAxisBinderItem; + typedef ControlKeyBinderItem ControlButtonBinderItem; + typedef ControlKeyBinderItem ControlPOVBinderItem; + typedef ControlKeyBinderItem ControlSliderBinderItem; + + typedef struct { + Control* control; + Control::ControlChangingDirection direction; + } PendingActionItem; + + std::list mPendingActions; + + std::string mFileName; + + typedef std::map ControlsKeyBinderMapType; // + typedef std::map ControlsAxisBinderMapType; // + typedef std::map ControlsButtonBinderMapType; // + typedef std::map ControlsPOVBinderMapType; // + typedef std::map ControlsSliderBinderMapType; // + + typedef std::map JoystickAxisBinderMapType; // > + typedef std::map JoystickButtonBinderMapType; // > + typedef std::map > JoystickPOVBinderMapType; // > > + typedef std::map JoystickSliderBinderMapType; // > + + ControlsAxisBinderMapType mControlsMouseAxisBinderMap; // + ControlsButtonBinderMapType mControlsMouseButtonBinderMap; // + JoystickAxisBinderMapType mControlsJoystickAxisBinderMap; // > + JoystickButtonBinderMapType mControlsJoystickButtonBinderMap; // > + JoystickPOVBinderMapType mControlsJoystickPOVBinderMap; // > > + JoystickSliderBinderMapType mControlsJoystickSliderBinderMap; // > + + std::vector mControls; + std::vector mChannels; + + ControlsKeyBinderMapType mControlsKeyBinderMap; + std::map mKeys; + std::map mKeyCodes; + + bool mActive; + InputControlSystemLog* mLog; + + DetectingBindingListener* mDetectingBindingListener; + Control* mDetectingBindingControl; + Control::ControlChangingDirection mDetectingBindingDirection; + + bool mXmouseAxisBinded; + bool mYmouseAxisBinded; + + JoystickIDList mJoystickIDList; + + int mMouseAxisBindingInitialValues[3]; + + private: + + void fillOISKeysMap(); + }; + + class DllExport DetectingBindingListener + { + public: + virtual void keyBindingDetected(InputControlSystem* ICS, Control* control + , OIS::KeyCode key, Control::ControlChangingDirection direction); + + virtual void mouseAxisBindingDetected(InputControlSystem* ICS, Control* control + , InputControlSystem::NamedAxis axis, Control::ControlChangingDirection direction); + + virtual void mouseButtonBindingDetected(InputControlSystem* ICS, Control* control + , unsigned int button, Control::ControlChangingDirection direction); + + virtual void joystickAxisBindingDetected(InputControlSystem* ICS, Control* control + , int deviceId, int axis, Control::ControlChangingDirection direction); + + virtual void joystickButtonBindingDetected(InputControlSystem* ICS, Control* control + , int deviceId, unsigned int button, Control::ControlChangingDirection direction); + + virtual void joystickPOVBindingDetected(InputControlSystem* ICS, Control* control + , int deviceId, int pov, InputControlSystem::POVAxis axis, Control::ControlChangingDirection direction); + + virtual void joystickSliderBindingDetected(InputControlSystem* ICS, Control* control + , int deviceId, int slider, Control::ControlChangingDirection direction); + }; + + static const float ICS_MAX = std::numeric_limits::max(); +} + + +#endif diff --git a/extern/oics/ICSInputControlSystem_joystick.cpp b/extern/oics/ICSInputControlSystem_joystick.cpp new file mode 100644 index 000000000..1e66599ea --- /dev/null +++ b/extern/oics/ICSInputControlSystem_joystick.cpp @@ -0,0 +1,665 @@ +/* ------------------------------------------------------- +Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es) + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of +the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------- */ + +#include "ICSInputControlSystem.h" + +namespace ICS +{ + // load xml + void InputControlSystem::loadJoystickAxisBinders(TiXmlElement* xmlControlNode) + { + TiXmlElement* xmlJoystickBinder = xmlControlNode->FirstChildElement("JoystickAxisBinder"); + while(xmlJoystickBinder) + { + Control::ControlChangingDirection dir = Control::STOP; + if(std::string(xmlJoystickBinder->Attribute("direction")) == "INCREASE") + { + dir = Control::INCREASE; + } + else if(std::string(xmlJoystickBinder->Attribute("direction")) == "DECREASE") + { + dir = Control::DECREASE; + } + + addJoystickAxisBinding(mControls.back(), FromString(xmlJoystickBinder->Attribute("deviceId")) + , FromString(xmlJoystickBinder->Attribute("axis")), dir); + + xmlJoystickBinder = xmlJoystickBinder->NextSiblingElement("JoystickAxisBinder"); + } + } + + void InputControlSystem::loadJoystickButtonBinders(TiXmlElement* xmlControlNode) + { + TiXmlElement* xmlJoystickButtonBinder = xmlControlNode->FirstChildElement("JoystickButtonBinder"); + while(xmlJoystickButtonBinder) + { + Control::ControlChangingDirection dir = Control::STOP; + if(std::string(xmlJoystickButtonBinder->Attribute("direction")) == "INCREASE") + { + dir = Control::INCREASE; + } + else if(std::string(xmlJoystickButtonBinder->Attribute("direction")) == "DECREASE") + { + dir = Control::DECREASE; + } + + addJoystickButtonBinding(mControls.back(), FromString(xmlJoystickButtonBinder->Attribute("deviceId")) + , FromString(xmlJoystickButtonBinder->Attribute("button")), dir); + + xmlJoystickButtonBinder = xmlJoystickButtonBinder->NextSiblingElement("JoystickButtonBinder"); + } + } + + void InputControlSystem::loadJoystickPOVBinders(TiXmlElement* xmlControlNode) + { + TiXmlElement* xmlJoystickPOVBinder = xmlControlNode->FirstChildElement("JoystickPOVBinder"); + while(xmlJoystickPOVBinder) + { + Control::ControlChangingDirection dir = Control::STOP; + if(std::string(xmlJoystickPOVBinder->Attribute("direction")) == "INCREASE") + { + dir = Control::INCREASE; + } + else if(std::string(xmlJoystickPOVBinder->Attribute("direction")) == "DECREASE") + { + dir = Control::DECREASE; + } + + InputControlSystem::POVAxis axis = /*POVAxis::*/NorthSouth; + if(std::string(xmlJoystickPOVBinder->Attribute("axis")) == "EastWest") + { + axis = /*POVAxis::*/EastWest; + } + + addJoystickPOVBinding(mControls.back(), FromString(xmlJoystickPOVBinder->Attribute("deviceId")) + , FromString(xmlJoystickPOVBinder->Attribute("pov")), axis, dir); + + xmlJoystickPOVBinder = xmlJoystickPOVBinder->NextSiblingElement("JoystickPOVBinder"); + } + } + + void InputControlSystem::loadJoystickSliderBinders(TiXmlElement* xmlControlNode) + { + TiXmlElement* xmlJoystickSliderBinder = xmlControlNode->FirstChildElement("JoystickSliderBinder"); + while(xmlJoystickSliderBinder) + { + Control::ControlChangingDirection dir = Control::STOP; + if(std::string(xmlJoystickSliderBinder->Attribute("direction")) == "INCREASE") + { + dir = Control::INCREASE; + } + else if(std::string(xmlJoystickSliderBinder->Attribute("direction")) == "DECREASE") + { + dir = Control::DECREASE; + } + + addJoystickSliderBinding(mControls.back(), FromString(xmlJoystickSliderBinder->Attribute("deviceId")) + , FromString(xmlJoystickSliderBinder->Attribute("slider")), dir); + + xmlJoystickSliderBinder = xmlJoystickSliderBinder->NextSiblingElement("JoystickSliderBinder"); + } + } + + // add bindings + void InputControlSystem::addJoystickAxisBinding(Control* control, int deviceId, int axis, Control::ControlChangingDirection direction) + { + ICS_LOG("\tAdding AxisBinder [deviceid=" + + ToString(deviceId) + ", axis=" + + ToString(axis) + ", direction=" + + ToString(direction) + "]"); + + ControlAxisBinderItem controlAxisBinderItem; + controlAxisBinderItem.control = control; + controlAxisBinderItem.direction = direction; + mControlsJoystickAxisBinderMap[ deviceId ][ axis ] = controlAxisBinderItem; + } + + void InputControlSystem::addJoystickButtonBinding(Control* control, int deviceId, unsigned int button, Control::ControlChangingDirection direction) + { + ICS_LOG("\tAdding JoystickButtonBinder [deviceId=" + + ToString(deviceId) + ", button=" + + ToString(button) + ", direction=" + + ToString(direction) + "]"); + + ControlButtonBinderItem controlJoystickButtonBinderItem; + controlJoystickButtonBinderItem.direction = direction; + controlJoystickButtonBinderItem.control = control; + mControlsJoystickButtonBinderMap[ deviceId ][ button ] = controlJoystickButtonBinderItem; + } + + void InputControlSystem::addJoystickPOVBinding(Control* control, int deviceId, int index, InputControlSystem::POVAxis axis, Control::ControlChangingDirection direction) + { + ICS_LOG("\tAdding JoystickPOVBinder [deviceId=" + + ToString(deviceId) + ", pov=" + + ToString(index) + ", axis=" + + ToString(axis) + ", direction=" + + ToString(direction) + "]"); + + ControlPOVBinderItem ControlPOVBinderItem; + ControlPOVBinderItem.direction = direction; + ControlPOVBinderItem.control = control; + mControlsJoystickPOVBinderMap[ deviceId ][ index ][ axis ] = ControlPOVBinderItem; + } + + void InputControlSystem::addJoystickSliderBinding(Control* control, int deviceId, int index, Control::ControlChangingDirection direction) + { + ICS_LOG("\tAdding JoystickSliderBinder [deviceId=" + + ToString(deviceId) + ", direction=" + + ToString(index) + ", direction=" + + ToString(direction) + "]"); + + ControlSliderBinderItem ControlSliderBinderItem; + ControlSliderBinderItem.direction = direction; + ControlSliderBinderItem.control = control; + mControlsJoystickSliderBinderMap[ deviceId ][ index ] = ControlSliderBinderItem; + } + + // get bindings + int InputControlSystem::getJoystickAxisBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction) + { + if(mControlsJoystickAxisBinderMap.find(deviceId) != mControlsJoystickAxisBinderMap.end()) + { + ControlsAxisBinderMapType::iterator it = mControlsJoystickAxisBinderMap[deviceId].begin(); + while(it != mControlsJoystickAxisBinderMap[deviceId].end()) + { + if(it->first >= 0 && it->second.control == control && it->second.direction == direction) + { + return it->first; + } + it++; + } + } + + return /*NamedAxis::*/UNASSIGNED; + } + + unsigned int InputControlSystem::getJoystickButtonBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction) + { + if(mControlsJoystickButtonBinderMap.find(deviceId) != mControlsJoystickButtonBinderMap.end()) + { + ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap[deviceId].begin(); + while(it != mControlsJoystickButtonBinderMap[deviceId].end()) + { + if(it->second.control == control && it->second.direction == direction) + { + return it->first; + } + it++; + } + } + + return ICS_MAX_DEVICE_BUTTONS; + } + + InputControlSystem::POVBindingPair InputControlSystem::getJoystickPOVBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction) + { + POVBindingPair result; + result.index = -1; + + if(mControlsJoystickPOVBinderMap.find(deviceId) != mControlsJoystickPOVBinderMap.end()) + { + //ControlsAxisBinderMapType::iterator it = mControlsJoystickPOVBinderMap[deviceId].begin(); + std::map::iterator it = mControlsJoystickPOVBinderMap[deviceId].begin(); + while(it != mControlsJoystickPOVBinderMap[deviceId].end()) + { + ControlsPOVBinderMapType::const_iterator it2 = it->second.begin(); + while(it2 != it->second.end()) + { + if(it2->second.control == control && it2->second.direction == direction) + { + result.index = it->first; + result.axis = (POVAxis)it2->first; + return result; + } + it2++; + } + + it++; + } + } + + return result; + } + + int InputControlSystem::getJoystickSliderBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction) + { + if(mControlsJoystickSliderBinderMap.find(deviceId) != mControlsJoystickSliderBinderMap.end()) + { + ControlsButtonBinderMapType::iterator it = mControlsJoystickSliderBinderMap[deviceId].begin(); + while(it != mControlsJoystickSliderBinderMap[deviceId].end()) + { + if(it->second.control == control && it->second.direction == direction) + { + return it->first; + } + it++; + } + } + + return /*NamedAxis::*/UNASSIGNED; + } + + // remove bindings + void InputControlSystem::removeJoystickAxisBinding(int deviceId, int axis) + { + if(mControlsJoystickAxisBinderMap.find(deviceId) != mControlsJoystickAxisBinderMap.end()) + { + ControlsButtonBinderMapType::iterator it = mControlsJoystickAxisBinderMap[deviceId].find(axis); + if(it != mControlsJoystickAxisBinderMap[deviceId].end()) + { + mControlsJoystickAxisBinderMap[deviceId].erase(it); + } + } + } + + void InputControlSystem::removeJoystickButtonBinding(int deviceId, unsigned int button) + { + if(mControlsJoystickButtonBinderMap.find(deviceId) != mControlsJoystickButtonBinderMap.end()) + { + ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap[deviceId].find(button); + if(it != mControlsJoystickButtonBinderMap[deviceId].end()) + { + mControlsJoystickButtonBinderMap[deviceId].erase(it); + } + } + } + + void InputControlSystem::removeJoystickPOVBinding(int deviceId, int index, POVAxis axis) + { + if(mControlsJoystickPOVBinderMap.find(deviceId) != mControlsJoystickPOVBinderMap.end()) + { + std::map::iterator it = mControlsJoystickPOVBinderMap[deviceId].find(index); + if(it != mControlsJoystickPOVBinderMap[deviceId].end()) + { + if(it->second.find(axis) != it->second.end()) + { + mControlsJoystickPOVBinderMap[deviceId].find(index)->second.erase( it->second.find(axis) ); + } + } + } + } + + void InputControlSystem::removeJoystickSliderBinding(int deviceId, int index) + { + if(mControlsJoystickSliderBinderMap.find(deviceId) != mControlsJoystickSliderBinderMap.end()) + { + ControlsButtonBinderMapType::iterator it = mControlsJoystickSliderBinderMap[deviceId].find(index); + if(it != mControlsJoystickSliderBinderMap[deviceId].end()) + { + mControlsJoystickSliderBinderMap[deviceId].erase(it); + } + } + } + + // joyStick listeners + bool InputControlSystem::buttonPressed(const OIS::JoyStickEvent &evt, int button) + { + if(mActive) + { + if(!mDetectingBindingControl) + { + if(mControlsJoystickButtonBinderMap.find(evt.device->getID()) != mControlsJoystickButtonBinderMap.end()) + { + ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[evt.device->getID()].find(button); + if(it != mControlsJoystickButtonBinderMap[evt.device->getID()].end()) + { + it->second.control->setIgnoreAutoReverse(false); + if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) + { + it->second.control->setChangingDirection(it->second.direction); + } + else + { + if(it->second.control->getValue() == 1) + { + it->second.control->setChangingDirection(Control::DECREASE); + } + else if(it->second.control->getValue() == 0) + { + it->second.control->setChangingDirection(Control::INCREASE); + } + } + } + } + } + else if(mDetectingBindingListener) + { + mDetectingBindingListener->joystickButtonBindingDetected(this, + mDetectingBindingControl, evt.device->getID(), button, mDetectingBindingDirection); + } + } + + return true; + } + + bool InputControlSystem::buttonReleased(const OIS::JoyStickEvent &evt, int button) + { + if(mActive) + { + if(mControlsJoystickButtonBinderMap.find(evt.device->getID()) != mControlsJoystickButtonBinderMap.end()) + { + ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[evt.device->getID()].find(button); + if(it != mControlsJoystickButtonBinderMap[evt.device->getID()].end()) + { + it->second.control->setChangingDirection(Control::STOP); + } + } + } + return true; + } + + bool InputControlSystem::axisMoved(const OIS::JoyStickEvent &evt, int axis) + { + if(mActive) + { + if(!mDetectingBindingControl) + { + if(mControlsJoystickAxisBinderMap.find(evt.device->getID()) != mControlsJoystickAxisBinderMap.end()) + { + ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[ evt.device->getID() ][ axis ]; // joystic axis start at 0 index + Control* ctrl = joystickBinderItem.control; + if(ctrl) + { + ctrl->setIgnoreAutoReverse(true); + if(joystickBinderItem.direction == Control::INCREASE) + { + float axisRange = OIS::JoyStick::MAX_AXIS - OIS::JoyStick::MIN_AXIS; + float valDisplaced = (float)( evt.state.mAxes[axis].abs - OIS::JoyStick::MIN_AXIS); + + ctrl->setValue( valDisplaced / axisRange ); + } + else if(joystickBinderItem.direction == Control::DECREASE) + { + float axisRange = OIS::JoyStick::MAX_AXIS - OIS::JoyStick::MIN_AXIS; + float valDisplaced = (float)(evt.state.mAxes[axis].abs - OIS::JoyStick::MIN_AXIS); + + ctrl->setValue( 1 - ( valDisplaced / axisRange ) ); + } + } + } + } + else if(mDetectingBindingListener) + { + //ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[ evt.device->getID() ][ axis ]; // joystic axis start at 0 index + //Control* ctrl = joystickBinderItem.control; + //if(ctrl && ctrl->isAxisBindable()) + if(mDetectingBindingControl && mDetectingBindingControl->isAxisBindable()) + { + if( abs( evt.state.mAxes[axis].abs ) > ICS_JOYSTICK_AXIS_BINDING_MARGIN) + { + mDetectingBindingListener->joystickAxisBindingDetected(this, + mDetectingBindingControl, evt.device->getID(), axis, mDetectingBindingDirection); + } + } + } + } + + return true; + } + + bool InputControlSystem::povMoved(const OIS::JoyStickEvent &evt, int index) + { + if(mActive) + { + if(!mDetectingBindingControl) + { + if(mControlsJoystickPOVBinderMap.find(evt.device->getID()) != mControlsJoystickPOVBinderMap.end()) + { + std::map::const_iterator i = mControlsJoystickPOVBinderMap[ evt.device->getID() ].find(index); + if(i != mControlsJoystickPOVBinderMap[ evt.device->getID() ].end()) + { + if(evt.state.mPOV[index].direction != OIS::Pov::West + && evt.state.mPOV[index].direction != OIS::Pov::East + && evt.state.mPOV[index].direction != OIS::Pov::Centered) + { + ControlsPOVBinderMapType::const_iterator it = i->second.find( /*POVAxis::*/NorthSouth ); + if(it != i->second.end()) + { + it->second.control->setIgnoreAutoReverse(false); + if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) + { + if(evt.state.mPOV[index].direction == OIS::Pov::North + || evt.state.mPOV[index].direction == OIS::Pov::NorthWest + || evt.state.mPOV[index].direction == OIS::Pov::NorthEast) + { + it->second.control->setChangingDirection(it->second.direction); + } + else + { + it->second.control->setChangingDirection((Control::ControlChangingDirection)(-1 * it->second.direction)); + } + } + else + { + if(it->second.control->getValue() == 1) + { + it->second.control->setChangingDirection(Control::DECREASE); + } + else if(it->second.control->getValue() == 0) + { + it->second.control->setChangingDirection(Control::INCREASE); + } + } + } + } + + if(evt.state.mPOV[index].direction != OIS::Pov::North + && evt.state.mPOV[index].direction != OIS::Pov::South + && evt.state.mPOV[index].direction != OIS::Pov::Centered) + { + ControlsPOVBinderMapType::const_iterator it = i->second.find( /*POVAxis::*/EastWest ); + if(it != i->second.end()) + { + it->second.control->setIgnoreAutoReverse(false); + if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) + { + if(evt.state.mPOV[index].direction == OIS::Pov::East + || evt.state.mPOV[index].direction == OIS::Pov::NorthEast + || evt.state.mPOV[index].direction == OIS::Pov::SouthEast) + { + it->second.control->setChangingDirection(it->second.direction); + } + else + { + it->second.control->setChangingDirection((Control::ControlChangingDirection)(-1 * it->second.direction)); + } + } + else + { + if(it->second.control->getValue() == 1) + { + it->second.control->setChangingDirection(Control::DECREASE); + } + else if(it->second.control->getValue() == 0) + { + it->second.control->setChangingDirection(Control::INCREASE); + } + } + } + } + + if(evt.state.mPOV[index].direction == OIS::Pov::Centered) + { + ControlsPOVBinderMapType::const_iterator it = i->second.find( /*POVAxis::*/NorthSouth ); + if(it != i->second.end()) + { + it->second.control->setChangingDirection(Control::STOP); + } + + it = i->second.find( /*POVAxis::*/EastWest ); + if(it != i->second.end()) + { + it->second.control->setChangingDirection(Control::STOP); + } + } + } + } + } + else if(mDetectingBindingListener) + { + if(mDetectingBindingControl && mDetectingBindingControl->isAxisBindable()) + { + if(evt.state.mPOV[index].direction == OIS::Pov::West + || evt.state.mPOV[index].direction == OIS::Pov::East + || evt.state.mPOV[index].direction == OIS::Pov::North + || evt.state.mPOV[index].direction == OIS::Pov::South) + { + POVAxis povAxis = NorthSouth; + if(evt.state.mPOV[index].direction == OIS::Pov::West + || evt.state.mPOV[index].direction == OIS::Pov::East) + { + povAxis = EastWest; + } + + mDetectingBindingListener->joystickPOVBindingDetected(this, + mDetectingBindingControl, evt.device->getID(), index, povAxis, mDetectingBindingDirection); + } + } + } + } + + return true; + } + + bool InputControlSystem::sliderMoved(const OIS::JoyStickEvent &evt, int index) + { + if(mActive) + { + if(!mDetectingBindingControl) + { + if(mControlsJoystickSliderBinderMap.find(evt.device->getID()) != mControlsJoystickSliderBinderMap.end()) + { + ControlSliderBinderItem joystickBinderItem = mControlsJoystickSliderBinderMap[ evt.device->getID() ][ index ]; + Control* ctrl = joystickBinderItem.control; + if(ctrl) + { + ctrl->setIgnoreAutoReverse(true); + if(joystickBinderItem.direction == Control::INCREASE) + { + float axisRange = OIS::JoyStick::MAX_AXIS - OIS::JoyStick::MIN_AXIS; + float valDisplaced = (float)( evt.state.mSliders[index].abX - OIS::JoyStick::MIN_AXIS); + + ctrl->setValue( valDisplaced / axisRange ); + } + else if(joystickBinderItem.direction == Control::DECREASE) + { + float axisRange = OIS::JoyStick::MAX_AXIS - OIS::JoyStick::MIN_AXIS; + float valDisplaced = (float)(evt.state.mSliders[index].abX - OIS::JoyStick::MIN_AXIS); + + ctrl->setValue( 1 - ( valDisplaced / axisRange ) ); + } + } + } + } + else if(mDetectingBindingListener) + { + /*ControlSliderBinderItem joystickBinderItem = mControlsJoystickSliderBinderMap[ evt.device->getID() ][ index ]; + Control* ctrl = joystickBinderItem.control; + if(ctrl && ctrl->isAxisBindable()) + {*/ + if(mDetectingBindingControl && mDetectingBindingControl->isAxisBindable()) + { + if( abs( evt.state.mSliders[index].abX ) > ICS_JOYSTICK_SLIDER_BINDING_MARGIN) + { + mDetectingBindingListener->joystickSliderBindingDetected(this, + mDetectingBindingControl, evt.device->getID(), index, mDetectingBindingDirection); + } + } + } + } + + return true; + } + + // joystick auto bindings + void DetectingBindingListener::joystickAxisBindingDetected(InputControlSystem* ICS, Control* control + , int deviceId, int axis, Control::ControlChangingDirection direction) + { + // if the joystick axis is used by another control, remove it + ICS->removeJoystickAxisBinding(deviceId, axis); + + // if the control has an axis assigned, remove it + int oldAxis = ICS->getJoystickAxisBinding(control, deviceId, direction); + if(oldAxis != InputControlSystem::UNASSIGNED) + { + ICS->removeJoystickAxisBinding(deviceId, oldAxis); + } + + ICS->addJoystickAxisBinding(control, deviceId, axis, direction); + ICS->cancelDetectingBindingState(); + } + void DetectingBindingListener::joystickButtonBindingDetected(InputControlSystem* ICS, Control* control + , int deviceId, unsigned int button, Control::ControlChangingDirection direction) + { + // if the joystick button is used by another control, remove it + ICS->removeJoystickButtonBinding(deviceId, button); + + // if the control has a joystick button assigned, remove it + unsigned int oldButton = ICS->getJoystickButtonBinding(control, deviceId, direction); + if(oldButton != ICS_MAX_DEVICE_BUTTONS) + { + ICS->removeJoystickButtonBinding(deviceId, oldButton); + } + + ICS->addJoystickButtonBinding(control, deviceId, button, direction); + ICS->cancelDetectingBindingState(); + } + + + void DetectingBindingListener::joystickPOVBindingDetected(InputControlSystem* ICS, Control* control + , int deviceId, int pov, InputControlSystem::POVAxis axis, Control::ControlChangingDirection direction) + { + // if the joystick slider is used by another control, remove it + ICS->removeJoystickPOVBinding(deviceId, pov, axis); + + // if the control has a joystick button assigned, remove it + ICS::InputControlSystem::POVBindingPair oldPOV = ICS->getJoystickPOVBinding(control, deviceId, direction); + if(oldPOV.index >= 0 && oldPOV.axis == axis) + { + ICS->removeJoystickPOVBinding(deviceId, oldPOV.index, oldPOV.axis); + } + + ICS->addJoystickPOVBinding(control, deviceId, pov, axis, direction); + ICS->cancelDetectingBindingState(); + } + + void DetectingBindingListener::joystickSliderBindingDetected(InputControlSystem* ICS, Control* control + , int deviceId, int slider, Control::ControlChangingDirection direction) + { + // if the joystick slider is used by another control, remove it + ICS->removeJoystickSliderBinding(deviceId, slider); + + // if the control has a joystick slider assigned, remove it + int oldSlider = ICS->getJoystickSliderBinding(control, deviceId, direction); + if(oldSlider != InputControlSystem::/*NamedAxis::*/UNASSIGNED) + { + ICS->removeJoystickSliderBinding(deviceId, oldSlider); + } + + ICS->addJoystickSliderBinding(control, deviceId, slider, direction); + ICS->cancelDetectingBindingState(); + } +} \ No newline at end of file diff --git a/extern/oics/ICSInputControlSystem_keyboard.cpp b/extern/oics/ICSInputControlSystem_keyboard.cpp new file mode 100644 index 000000000..8ef81d979 --- /dev/null +++ b/extern/oics/ICSInputControlSystem_keyboard.cpp @@ -0,0 +1,156 @@ +/* ------------------------------------------------------- +Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es) + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of +the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------- */ + +#include "ICSInputControlSystem.h" + +namespace ICS +{ + void InputControlSystem::loadKeyBinders(TiXmlElement* xmlControlNode) + { + TiXmlElement* xmlKeyBinder = xmlControlNode->FirstChildElement("KeyBinder"); + while(xmlKeyBinder) + { + Control::ControlChangingDirection dir = Control::STOP; + if(std::string(xmlKeyBinder->Attribute("direction")) == "INCREASE") + { + dir = Control::INCREASE; + } + else if(std::string(xmlKeyBinder->Attribute("direction")) == "DECREASE") + { + dir = Control::DECREASE; + } + + addKeyBinding(mControls.back(), mKeys[xmlKeyBinder->Attribute("key")], dir); + + xmlKeyBinder = xmlKeyBinder->NextSiblingElement("KeyBinder"); + } + } + + void InputControlSystem::addKeyBinding(Control* control, OIS::KeyCode key, Control::ControlChangingDirection direction) + { + ICS_LOG("\tAdding KeyBinder [key=" + + keyCodeToString(key) + ", direction=" + + ToString(direction) + "]"); + + ControlKeyBinderItem controlKeyBinderItem; + controlKeyBinderItem.control = control; + controlKeyBinderItem.direction = direction; + mControlsKeyBinderMap[ key ] = controlKeyBinderItem; + } + + void InputControlSystem::removeKeyBinding(OIS::KeyCode key) + { + ControlsKeyBinderMapType::iterator it = mControlsKeyBinderMap.find(key); + if(it != mControlsKeyBinderMap.end()) + { + mControlsKeyBinderMap.erase(it); + } + } + + OIS::KeyCode InputControlSystem::getKeyBinding(Control* control + , ICS::Control::ControlChangingDirection direction) + { + ControlsKeyBinderMapType::iterator it = mControlsKeyBinderMap.begin(); + while(it != mControlsKeyBinderMap.end()) + { + if(it->second.control == control && it->second.direction == direction) + { + return it->first; + } + it++; + } + + return OIS::KC_UNASSIGNED; + } + bool InputControlSystem::keyPressed(const OIS::KeyEvent &evt) + { + if(mActive) + { + if(!mDetectingBindingControl) + { + ControlsKeyBinderMapType::const_iterator it = mControlsKeyBinderMap.find(evt.key); + if(it != mControlsKeyBinderMap.end()) + { + it->second.control->setIgnoreAutoReverse(false); + if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) + { + it->second.control->setChangingDirection(it->second.direction); + } + else + { + if(it->second.control->getValue() == 1) + { + it->second.control->setChangingDirection(Control::DECREASE); + } + else if(it->second.control->getValue() == 0) + { + it->second.control->setChangingDirection(Control::INCREASE); + } + } + } + } + else if(mDetectingBindingListener) + { + mDetectingBindingListener->keyBindingDetected(this, + mDetectingBindingControl, evt.key, mDetectingBindingDirection); + } + } + + return true; + } + + bool InputControlSystem::keyReleased(const OIS::KeyEvent &evt) + { + if(mActive) + { + ControlsKeyBinderMapType::const_iterator it = mControlsKeyBinderMap.find(evt.key); + if(it != mControlsKeyBinderMap.end()) + { + it->second.control->setChangingDirection(Control::STOP); + } + } + + return true; + } + + void DetectingBindingListener::keyBindingDetected(InputControlSystem* ICS, Control* control + , OIS::KeyCode key, Control::ControlChangingDirection direction) + { + // if the key is used by another control, remove it + ICS->removeKeyBinding(key); + + // if the control has a key assigned, remove it + OIS::KeyCode oldKey = ICS->getKeyBinding(control, direction); + if(oldKey != OIS::KC_UNASSIGNED) + { + ICS->removeKeyBinding(oldKey); + } + + ICS->addKeyBinding(control, key, direction); + ICS->cancelDetectingBindingState(); + } + +} \ No newline at end of file diff --git a/extern/oics/ICSInputControlSystem_mouse.cpp b/extern/oics/ICSInputControlSystem_mouse.cpp new file mode 100644 index 000000000..c62f1765e --- /dev/null +++ b/extern/oics/ICSInputControlSystem_mouse.cpp @@ -0,0 +1,397 @@ +/* ------------------------------------------------------- +Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es) + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of +the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------- */ + +#include "ICSInputControlSystem.h" + +namespace ICS +{ + // load xml + void InputControlSystem::loadMouseAxisBinders(TiXmlElement* xmlControlNode) + { + TiXmlElement* xmlMouseBinder = xmlControlNode->FirstChildElement("MouseBinder"); + while(xmlMouseBinder) + { + Control::ControlChangingDirection dir = Control::STOP; + if(std::string(xmlMouseBinder->Attribute("direction")) == "INCREASE") + { + dir = Control::INCREASE; + } + else if(std::string(xmlMouseBinder->Attribute("direction")) == "DECREASE") + { + dir = Control::DECREASE; + } + + NamedAxis axis = /*NamedAxis::*/ X; + if((*xmlMouseBinder->Attribute("axis")) == 'Y') + { + axis = /*NamedAxis::*/ Y; + } + else if((*xmlMouseBinder->Attribute("axis")) == 'Z') + { + axis = /*NamedAxis::*/ Z; + } + + addMouseAxisBinding(mControls.back(), axis, dir); + + xmlMouseBinder = xmlMouseBinder->NextSiblingElement("MouseBinder"); + } + } + + void InputControlSystem::loadMouseButtonBinders(TiXmlElement* xmlControlNode) + { + TiXmlElement* xmlMouseButtonBinder = xmlControlNode->FirstChildElement("MouseButtonBinder"); + while(xmlMouseButtonBinder) + { + Control::ControlChangingDirection dir = Control::STOP; + if(std::string(xmlMouseButtonBinder->Attribute("direction")) == "INCREASE") + { + dir = Control::INCREASE; + } + else if(std::string(xmlMouseButtonBinder->Attribute("direction")) == "DECREASE") + { + dir = Control::DECREASE; + } + + int button = 0; + if(std::string(xmlMouseButtonBinder->Attribute("button")) == "LEFT") + { + button = OIS::/*MouseButtonID::*/MB_Left; + } + else if(std::string(xmlMouseButtonBinder->Attribute("button")) == "RIGHT") + { + button = OIS::/*MouseButtonID::*/MB_Right; + } + else if(std::string(xmlMouseButtonBinder->Attribute("button")) == "MIDDLE") + { + button = OIS::/*MouseButtonID::*/MB_Middle; + } + else + { + button = FromString(xmlMouseButtonBinder->Attribute("button")); + } + + addMouseButtonBinding(mControls.back(), button, dir); + + xmlMouseButtonBinder = xmlMouseButtonBinder->NextSiblingElement("MouseButtonBinder"); + } + } + + + // add bindings + void InputControlSystem::addMouseAxisBinding(Control* control, NamedAxis axis, Control::ControlChangingDirection direction) + { + if(axis == /*NamedAxis::*/X) + { + mXmouseAxisBinded = true; + } + else if(axis == /*NamedAxis::*/Y) + { + mYmouseAxisBinded = true; + } + + addMouseAxisBinding_(control, axis, direction); + } + + /*protected*/ void InputControlSystem::addMouseAxisBinding_(Control* control, int axis, Control::ControlChangingDirection direction) + { + ICS_LOG("\tAdding AxisBinder [axis=" + + ToString(axis) + ", direction=" + + ToString(direction) + "]"); + + ControlAxisBinderItem controlAxisBinderItem; + controlAxisBinderItem.control = control; + controlAxisBinderItem.direction = direction; + mControlsMouseAxisBinderMap[ axis ] = controlAxisBinderItem; + } + + void InputControlSystem::addMouseButtonBinding(Control* control, unsigned int button, Control::ControlChangingDirection direction) + { + ICS_LOG("\tAdding MouseButtonBinder [button=" + + ToString(button) + ", direction=" + + ToString(direction) + "]"); + + ControlButtonBinderItem controlMouseButtonBinderItem; + controlMouseButtonBinderItem.direction = direction; + controlMouseButtonBinderItem.control = control; + mControlsMouseButtonBinderMap[ button ] = controlMouseButtonBinderItem; + } + + // get bindings + InputControlSystem::NamedAxis InputControlSystem::getMouseAxisBinding(Control* control, ICS::Control::ControlChangingDirection direction) + { + ControlsAxisBinderMapType::iterator it = mControlsMouseAxisBinderMap.begin(); + while(it != mControlsMouseAxisBinderMap.end()) + { + if(it->first < 0 && it->second.control == control && it->second.direction == direction) + { + return (InputControlSystem::NamedAxis)(it->first); + } + it++; + } + + return /*NamedAxis::*/UNASSIGNED; + } + + //int InputControlSystem::getMouseAxisBinding(Control* control, ICS::Control::ControlChangingDirection direction) + //{ + // ControlsAxisBinderMapType::iterator it = mControlsMouseAxisBinderMap.begin(); + // while(it != mControlsMouseAxisBinderMap.end()) + // { + // if(it->first >= 0 && it->second.control == control && it->second.direction == direction) + // { + // return it->first; + // } + // it++; + // } + + // return /*NamedAxis::*/UNASSIGNED; + //} + + unsigned int InputControlSystem::getMouseButtonBinding(Control* control, ICS::Control::ControlChangingDirection direction) + { + ControlsButtonBinderMapType::iterator it = mControlsMouseButtonBinderMap.begin(); + while(it != mControlsMouseButtonBinderMap.end()) + { + if(it->second.control == control && it->second.direction == direction) + { + return it->first; + } + it++; + } + + return ICS_MAX_DEVICE_BUTTONS; + } + + // remove bindings + void InputControlSystem::removeMouseAxisBinding(NamedAxis axis) + { + if(axis == /*NamedAxis::*/X) + { + mXmouseAxisBinded = false; + } + else if(axis == /*NamedAxis::*/Y) + { + mYmouseAxisBinded = false; + } + + removeMouseAxisBinding_(axis); + } + /*protected*/ void InputControlSystem::removeMouseAxisBinding_(int axis) + { + ControlsAxisBinderMapType::iterator it = mControlsMouseAxisBinderMap.find(axis); + if(it != mControlsMouseAxisBinderMap.end()) + { + mControlsMouseAxisBinderMap.erase(it); + } + } + + + void InputControlSystem::removeMouseButtonBinding(unsigned int button) + { + ControlsButtonBinderMapType::iterator it = mControlsMouseButtonBinderMap.find(button); + if(it != mControlsMouseButtonBinderMap.end()) + { + mControlsMouseButtonBinderMap.erase(it); + } + } + + // mouse Listeners + bool InputControlSystem::mouseMoved(const OIS::MouseEvent &evt) + { + if(mActive) + { + if(!mDetectingBindingControl) + { + if(mXmouseAxisBinded && evt.state.X.rel) + { + ControlAxisBinderItem mouseBinderItem = mControlsMouseAxisBinderMap[ /*NamedAxis::*/X ]; + Control* ctrl = mouseBinderItem.control; + ctrl->setIgnoreAutoReverse(true); + if(mouseBinderItem.direction == Control::INCREASE) + { + ctrl->setValue( float( (evt.state.X.abs) / float(evt.state.width) ) ); + } + else if(mouseBinderItem.direction == Control::DECREASE) + { + ctrl->setValue( 1 - float( evt.state.X.abs / float(evt.state.width) ) ); + } + } + + if(mYmouseAxisBinded && evt.state.Y.rel) + { + ControlAxisBinderItem mouseBinderItem = mControlsMouseAxisBinderMap[ /*NamedAxis::*/Y ]; + Control* ctrl = mouseBinderItem.control; + ctrl->setIgnoreAutoReverse(true); + if(mouseBinderItem.direction == Control::INCREASE) + { + ctrl->setValue( float( (evt.state.Y.abs) / float(evt.state.height) ) ); + } + else if(mouseBinderItem.direction == Control::DECREASE) + { + ctrl->setValue( 1 - float( evt.state.Y.abs / float(evt.state.height) ) ); + } + } + + //! @todo Whats the range of the Z axis? + /*if(evt.state.Z.rel) + { + ControlAxisBinderItem mouseBinderItem = mControlsAxisBinderMap[ NamedAxis::Z ]; + Control* ctrl = mouseBinderItem.control; + ctrl->setIgnoreAutoReverse(true); + if(mouseBinderItem.direction == Control::INCREASE) + { + ctrl->setValue( float( (evt.state.Z.abs) / float(evt.state.¿width?) ) ); + } + else if(mouseBinderItem.direction == Control::DECREASE) + { + ctrl->setValue( float( (1 - evt.state.Z.abs) / float(evt.state.¿width?) ) ); + } + }*/ + } + else if(mDetectingBindingListener) + { + if(mDetectingBindingControl->isAxisBindable()) + { + if(mMouseAxisBindingInitialValues[0] == ICS_MOUSE_AXIS_BINDING_NULL_VALUE) + { + mMouseAxisBindingInitialValues[0] = 0; + mMouseAxisBindingInitialValues[1] = 0; + mMouseAxisBindingInitialValues[2] = 0; + } + + mMouseAxisBindingInitialValues[0] += evt.state.X.rel; + mMouseAxisBindingInitialValues[1] += evt.state.Y.rel; + mMouseAxisBindingInitialValues[2] += evt.state.Z.rel; + + if( abs(mMouseAxisBindingInitialValues[0]) > ICS_MOUSE_BINDING_MARGIN ) + { + mDetectingBindingListener->mouseAxisBindingDetected(this, + mDetectingBindingControl, X, mDetectingBindingDirection); + } + else if( abs(mMouseAxisBindingInitialValues[1]) > ICS_MOUSE_BINDING_MARGIN ) + { + mDetectingBindingListener->mouseAxisBindingDetected(this, + mDetectingBindingControl, Y, mDetectingBindingDirection); + } + else if( abs(mMouseAxisBindingInitialValues[2]) > ICS_MOUSE_BINDING_MARGIN ) + { + mDetectingBindingListener->mouseAxisBindingDetected(this, + mDetectingBindingControl, Z, mDetectingBindingDirection); + } + } + } + } + + return true; + } + + bool InputControlSystem::mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID btn) + { + if(mActive) + { + if(!mDetectingBindingControl) + { + ControlsButtonBinderMapType::const_iterator it = mControlsMouseButtonBinderMap.find((int)btn); + if(it != mControlsMouseButtonBinderMap.end()) + { + it->second.control->setIgnoreAutoReverse(false); + if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) + { + it->second.control->setChangingDirection(it->second.direction); + } + else + { + if(it->second.control->getValue() == 1) + { + it->second.control->setChangingDirection(Control::DECREASE); + } + else if(it->second.control->getValue() == 0) + { + it->second.control->setChangingDirection(Control::INCREASE); + } + } + } + } + else if(mDetectingBindingListener) + { + mDetectingBindingListener->mouseButtonBindingDetected(this, + mDetectingBindingControl, btn, mDetectingBindingDirection); + } + } + + return true; + } + + bool InputControlSystem::mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID btn) + { + if(mActive) + { + ControlsButtonBinderMapType::const_iterator it = mControlsMouseButtonBinderMap.find((int)btn); + if(it != mControlsMouseButtonBinderMap.end()) + { + it->second.control->setChangingDirection(Control::STOP); + } + } + + return true; + } + + // mouse auto bindings + void DetectingBindingListener::mouseAxisBindingDetected(InputControlSystem* ICS, Control* control + , InputControlSystem::NamedAxis axis, Control::ControlChangingDirection direction) + { + // if the mouse axis is used by another control, remove it + ICS->removeMouseAxisBinding(axis); + + // if the control has an axis assigned, remove it + InputControlSystem::NamedAxis oldAxis = ICS->getMouseAxisBinding(control, direction); + if(oldAxis != InputControlSystem::UNASSIGNED) + { + ICS->removeMouseAxisBinding(oldAxis); + } + + ICS->addMouseAxisBinding(control, axis, direction); + ICS->cancelDetectingBindingState(); + } + + void DetectingBindingListener::mouseButtonBindingDetected(InputControlSystem* ICS, Control* control + , unsigned int button, Control::ControlChangingDirection direction) + { + // if the mouse button is used by another control, remove it + ICS->removeMouseButtonBinding(button); + + // if the control has a mouse button assigned, remove it + unsigned int oldButton = ICS->getMouseButtonBinding(control, direction); + if(oldButton != ICS_MAX_DEVICE_BUTTONS) + { + ICS->removeMouseButtonBinding(oldButton); + } + + ICS->addMouseButtonBinding(control, button, direction); + ICS->cancelDetectingBindingState(); + } + +} \ No newline at end of file diff --git a/extern/oics/ICSPrerequisites.cpp b/extern/oics/ICSPrerequisites.cpp new file mode 100644 index 000000000..2824950ed --- /dev/null +++ b/extern/oics/ICSPrerequisites.cpp @@ -0,0 +1,27 @@ +/* ------------------------------------------------------- +Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es) + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of +the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------- */ + +#include "ICSPrerequisites.h" diff --git a/extern/oics/ICSPrerequisites.h b/extern/oics/ICSPrerequisites.h new file mode 100644 index 000000000..864dad15f --- /dev/null +++ b/extern/oics/ICSPrerequisites.h @@ -0,0 +1,111 @@ +/* ------------------------------------------------------- +Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es) + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of +the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------- */ + +//! @todo add mouse wheel support + +#ifndef _InputControlSystem_Prerequisites_H_ +#define _InputControlSystem_Prerequisites_H_ + +/// Include external headers +#include +#include +#include +#include +#include +#include + +#include "tinyxml.h" + +#define OIS_DYNAMIC_LIB +#include +#include +#include +#include +#include + +/// Define the dll export qualifier if compiling for Windows + +/* +#ifdef ICS_PLATFORM_WIN32 + #ifdef ICS_LIB + #define DllExport __declspec (dllexport) + #else + #define DllExport __declspec (dllimport) + #endif +#else + #define DllExport +#endif +*/ +#define DllExport + +// Define some macros +#define ICS_DEPRECATED __declspec(deprecated("Deprecated. It will be removed in future versions.")) + +/// Version defines +#define ICS_VERSION_MAJOR 0 +#define ICS_VERSION_MINOR 3 +#define ICS_VERSION_PATCH 1 + +#define ICS_MAX_DEVICE_BUTTONS 30 + +namespace ICS +{ + template + bool StringIsNumber ( const std::string &Text ) + { + std::stringstream ss(Text); + T result; + return ss >> result ? true : false; + } + + // from http://www.cplusplus.com/forum/articles/9645/ + template + std::string ToString ( T value ) + { + std::stringstream ss; + ss << value; + return ss.str(); + } + + // from http://www.cplusplus.com/forum/articles/9645/ + template + T FromString ( const std::string &Text )//Text not by const reference so that the function can be used with a + { //character array as argument + std::stringstream ss(Text); + T result; + return ss >> result ? result : 0; + } + + class InputControlSystem; + class Channel; + class ChannelListener; + class Control; + class ControlListener; + class DetectingBindingListener; + class InputControlSystemLog; +} + +#endif diff --git a/extern/oics/tinystr.cpp b/extern/oics/tinystr.cpp new file mode 100644 index 000000000..681250714 --- /dev/null +++ b/extern/oics/tinystr.cpp @@ -0,0 +1,116 @@ +/* +www.sourceforge.net/projects/tinyxml +Original file by Yves Berquin. + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +/* + * THIS FILE WAS ALTERED BY Tyge Løvset, 7. April 2005. + */ + + +#ifndef TIXML_USE_STL + +#include "tinystr.h" + +// Error value for find primitive +const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1); + + +// Null rep. +TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } }; + + +void TiXmlString::reserve (size_type cap) +{ + if (cap > capacity()) + { + TiXmlString tmp; + tmp.init(length(), cap); + memcpy(tmp.start(), data(), length()); + swap(tmp); + } +} + + +TiXmlString& TiXmlString::assign(const char* str, size_type len) +{ + size_type cap = capacity(); + if (len > cap || cap > 3*(len + 8)) + { + TiXmlString tmp; + tmp.init(len); + memcpy(tmp.start(), str, len); + swap(tmp); + } + else + { + memmove(start(), str, len); + set_size(len); + } + return *this; +} + + +TiXmlString& TiXmlString::append(const char* str, size_type len) +{ + size_type newsize = length() + len; + if (newsize > capacity()) + { + reserve (newsize + capacity()); + } + memmove(finish(), str, len); + set_size(newsize); + return *this; +} + + +TiXmlString operator + (const TiXmlString & a, const TiXmlString & b) +{ + TiXmlString tmp; + tmp.reserve(a.length() + b.length()); + tmp += a; + tmp += b; + return tmp; +} + +TiXmlString operator + (const TiXmlString & a, const char* b) +{ + TiXmlString tmp; + TiXmlString::size_type b_len = static_cast( strlen(b) ); + tmp.reserve(a.length() + b_len); + tmp += a; + tmp.append(b, b_len); + return tmp; +} + +TiXmlString operator + (const char* a, const TiXmlString & b) +{ + TiXmlString tmp; + TiXmlString::size_type a_len = static_cast( strlen(a) ); + tmp.reserve(a_len + b.length()); + tmp.append(a, a_len); + tmp += b; + return tmp; +} + + +#endif // TIXML_USE_STL diff --git a/extern/oics/tinystr.h b/extern/oics/tinystr.h new file mode 100644 index 000000000..419e647e1 --- /dev/null +++ b/extern/oics/tinystr.h @@ -0,0 +1,319 @@ +/* +www.sourceforge.net/projects/tinyxml +Original file by Yves Berquin. + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +/* + * THIS FILE WAS ALTERED BY Tyge Lovset, 7. April 2005. + * + * - completely rewritten. compact, clean, and fast implementation. + * - sizeof(TiXmlString) = pointer size (4 bytes on 32-bit systems) + * - fixed reserve() to work as per specification. + * - fixed buggy compares operator==(), operator<(), and operator>() + * - fixed operator+=() to take a const ref argument, following spec. + * - added "copy" constructor with length, and most compare operators. + * - added swap(), clear(), size(), capacity(), operator+(). + */ + +#ifndef TIXML_USE_STL + +#ifndef TIXML_STRING_INCLUDED +#define TIXML_STRING_INCLUDED + +#include +#include + +/* The support for explicit isn't that universal, and it isn't really + required - it is used to check that the TiXmlString class isn't incorrectly + used. Be nice to old compilers and macro it here: +*/ +#if defined(_MSC_VER) && (_MSC_VER >= 1200 ) + // Microsoft visual studio, version 6 and higher. + #define TIXML_EXPLICIT explicit +#elif defined(__GNUC__) && (__GNUC__ >= 3 ) + // GCC version 3 and higher.s + #define TIXML_EXPLICIT explicit +#else + #define TIXML_EXPLICIT +#endif + + +/* + TiXmlString is an emulation of a subset of the std::string template. + Its purpose is to allow compiling TinyXML on compilers with no or poor STL support. + Only the member functions relevant to the TinyXML project have been implemented. + The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase + a string and there's no more room, we allocate a buffer twice as big as we need. +*/ +class TiXmlString +{ + public : + // The size type used + typedef size_t size_type; + + // Error value for find primitive + static const size_type npos; // = -1; + + + // TiXmlString empty constructor + TiXmlString () : rep_(&nullrep_) + { + } + + // TiXmlString copy constructor + TiXmlString ( const TiXmlString & copy) : rep_(0) + { + init(copy.length()); + memcpy(start(), copy.data(), length()); + } + + // TiXmlString constructor, based on a string + TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0) + { + init( static_cast( strlen(copy) )); + memcpy(start(), copy, length()); + } + + // TiXmlString constructor, based on a string + TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0) + { + init(len); + memcpy(start(), str, len); + } + + // TiXmlString destructor + ~TiXmlString () + { + quit(); + } + + // = operator + TiXmlString& operator = (const char * copy) + { + return assign( copy, (size_type)strlen(copy)); + } + + // = operator + TiXmlString& operator = (const TiXmlString & copy) + { + return assign(copy.start(), copy.length()); + } + + + // += operator. Maps to append + TiXmlString& operator += (const char * suffix) + { + return append(suffix, static_cast( strlen(suffix) )); + } + + // += operator. Maps to append + TiXmlString& operator += (char single) + { + return append(&single, 1); + } + + // += operator. Maps to append + TiXmlString& operator += (const TiXmlString & suffix) + { + return append(suffix.data(), suffix.length()); + } + + + // Convert a TiXmlString into a null-terminated char * + const char * c_str () const { return rep_->str; } + + // Convert a TiXmlString into a char * (need not be null terminated). + const char * data () const { return rep_->str; } + + // Return the length of a TiXmlString + size_type length () const { return rep_->size; } + + // Alias for length() + size_type size () const { return rep_->size; } + + // Checks if a TiXmlString is empty + bool empty () const { return rep_->size == 0; } + + // Return capacity of string + size_type capacity () const { return rep_->capacity; } + + + // single char extraction + const char& at (size_type index) const + { + assert( index < length() ); + return rep_->str[ index ]; + } + + // [] operator + char& operator [] (size_type index) const + { + assert( index < length() ); + return rep_->str[ index ]; + } + + // find a char in a string. Return TiXmlString::npos if not found + size_type find (char lookup) const + { + return find(lookup, 0); + } + + // find a char in a string from an offset. Return TiXmlString::npos if not found + size_type find (char tofind, size_type offset) const + { + if (offset >= length()) return npos; + + for (const char* p = c_str() + offset; *p != '\0'; ++p) + { + if (*p == tofind) return static_cast< size_type >( p - c_str() ); + } + return npos; + } + + void clear () + { + //Lee: + //The original was just too strange, though correct: + // TiXmlString().swap(*this); + //Instead use the quit & re-init: + quit(); + init(0,0); + } + + /* Function to reserve a big amount of data when we know we'll need it. Be aware that this + function DOES NOT clear the content of the TiXmlString if any exists. + */ + void reserve (size_type cap); + + TiXmlString& assign (const char* str, size_type len); + + TiXmlString& append (const char* str, size_type len); + + void swap (TiXmlString& other) + { + Rep* r = rep_; + rep_ = other.rep_; + other.rep_ = r; + } + + private: + + void init(size_type sz) { init(sz, sz); } + void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; } + char* start() const { return rep_->str; } + char* finish() const { return rep_->str + rep_->size; } + + struct Rep + { + size_type size, capacity; + char str[1]; + }; + + void init(size_type sz, size_type cap) + { + if (cap) + { + // Lee: the original form: + // rep_ = static_cast(operator new(sizeof(Rep) + cap)); + // doesn't work in some cases of new being overloaded. Switching + // to the normal allocation, although use an 'int' for systems + // that are overly picky about structure alignment. + const size_type bytesNeeded = sizeof(Rep) + cap; + const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int ); + rep_ = reinterpret_cast( new int[ intsNeeded ] ); + + rep_->str[ rep_->size = sz ] = '\0'; + rep_->capacity = cap; + } + else + { + rep_ = &nullrep_; + } + } + + void quit() + { + if (rep_ != &nullrep_) + { + // The rep_ is really an array of ints. (see the allocator, above). + // Cast it back before delete, so the compiler won't incorrectly call destructors. + delete [] ( reinterpret_cast( rep_ ) ); + } + } + + Rep * rep_; + static Rep nullrep_; + +} ; + + +inline bool operator == (const TiXmlString & a, const TiXmlString & b) +{ + return ( a.length() == b.length() ) // optimization on some platforms + && ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare +} +inline bool operator < (const TiXmlString & a, const TiXmlString & b) +{ + return strcmp(a.c_str(), b.c_str()) < 0; +} + +inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); } +inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; } +inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); } +inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); } + +inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; } +inline bool operator == (const char* a, const TiXmlString & b) { return b == a; } +inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); } +inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); } + +TiXmlString operator + (const TiXmlString & a, const TiXmlString & b); +TiXmlString operator + (const TiXmlString & a, const char* b); +TiXmlString operator + (const char* a, const TiXmlString & b); + + +/* + TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. + Only the operators that we need for TinyXML have been developped. +*/ +class TiXmlOutStream : public TiXmlString +{ +public : + + // TiXmlOutStream << operator. + TiXmlOutStream & operator << (const TiXmlString & in) + { + *this += in; + return *this; + } + + // TiXmlOutStream << operator. + TiXmlOutStream & operator << (const char * in) + { + *this += in; + return *this; + } + +} ; + +#endif // TIXML_STRING_INCLUDED +#endif // TIXML_USE_STL diff --git a/extern/oics/tinyxml.cpp b/extern/oics/tinyxml.cpp new file mode 100644 index 000000000..841a41cd3 --- /dev/null +++ b/extern/oics/tinyxml.cpp @@ -0,0 +1,1888 @@ +/* +www.sourceforge.net/projects/tinyxml +Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include + +#ifdef TIXML_USE_STL +#include +#include +#endif + +#include "tinyxml.h" + + +bool TiXmlBase::condenseWhiteSpace = true; + +// Microsoft compiler security +FILE* TiXmlFOpen( const char* filename, const char* mode ) +{ + #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) + FILE* fp = 0; + errno_t err = fopen_s( &fp, filename, mode ); + if ( !err && fp ) + return fp; + return 0; + #else + return fopen( filename, mode ); + #endif +} + +void TiXmlBase::EncodeString( const TIXML_STRING& str, TIXML_STRING* outString ) +{ + int i=0; + + while( i<(int)str.length() ) + { + unsigned char c = (unsigned char) str[i]; + + if ( c == '&' + && i < ( (int)str.length() - 2 ) + && str[i+1] == '#' + && str[i+2] == 'x' ) + { + // Hexadecimal character reference. + // Pass through unchanged. + // © -- copyright symbol, for example. + // + // The -1 is a bug fix from Rob Laveaux. It keeps + // an overflow from happening if there is no ';'. + // There are actually 2 ways to exit this loop - + // while fails (error case) and break (semicolon found). + // However, there is no mechanism (currently) for + // this function to return an error. + while ( i<(int)str.length()-1 ) + { + outString->append( str.c_str() + i, 1 ); + ++i; + if ( str[i] == ';' ) + break; + } + } + else if ( c == '&' ) + { + outString->append( entity[0].str, entity[0].strLength ); + ++i; + } + else if ( c == '<' ) + { + outString->append( entity[1].str, entity[1].strLength ); + ++i; + } + else if ( c == '>' ) + { + outString->append( entity[2].str, entity[2].strLength ); + ++i; + } + else if ( c == '\"' ) + { + outString->append( entity[3].str, entity[3].strLength ); + ++i; + } + else if ( c == '\'' ) + { + outString->append( entity[4].str, entity[4].strLength ); + ++i; + } + else if ( c < 32 ) + { + // Easy pass at non-alpha/numeric/symbol + // Below 32 is symbolic. + char buf[ 32 ]; + + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) ); + #else + sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) ); + #endif + + //*ME: warning C4267: convert 'size_t' to 'int' + //*ME: Int-Cast to make compiler happy ... + outString->append( buf, (int)strlen( buf ) ); + ++i; + } + else + { + //char realc = (char) c; + //outString->append( &realc, 1 ); + *outString += (char) c; // somewhat more efficient function call. + ++i; + } + } +} + + +TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase() +{ + parent = 0; + type = _type; + firstChild = 0; + lastChild = 0; + prev = 0; + next = 0; +} + + +TiXmlNode::~TiXmlNode() +{ + TiXmlNode* node = firstChild; + TiXmlNode* temp = 0; + + while ( node ) + { + temp = node; + node = node->next; + delete temp; + } +} + + +void TiXmlNode::CopyTo( TiXmlNode* target ) const +{ + target->SetValue (value.c_str() ); + target->userData = userData; +} + + +void TiXmlNode::Clear() +{ + TiXmlNode* node = firstChild; + TiXmlNode* temp = 0; + + while ( node ) + { + temp = node; + node = node->next; + delete temp; + } + + firstChild = 0; + lastChild = 0; +} + + +TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) +{ + assert( node->parent == 0 || node->parent == this ); + assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() ); + + if ( node->Type() == TiXmlNode::DOCUMENT ) + { + delete node; + if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + node->parent = this; + + node->prev = lastChild; + node->next = 0; + + if ( lastChild ) + lastChild->next = node; + else + firstChild = node; // it was an empty list. + + lastChild = node; + return node; +} + + +TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis ) +{ + if ( addThis.Type() == TiXmlNode::DOCUMENT ) + { + if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + TiXmlNode* node = addThis.Clone(); + if ( !node ) + return 0; + + return LinkEndChild( node ); +} + + +TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ) +{ + if ( !beforeThis || beforeThis->parent != this ) { + return 0; + } + if ( addThis.Type() == TiXmlNode::DOCUMENT ) + { + if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + TiXmlNode* node = addThis.Clone(); + if ( !node ) + return 0; + node->parent = this; + + node->next = beforeThis; + node->prev = beforeThis->prev; + if ( beforeThis->prev ) + { + beforeThis->prev->next = node; + } + else + { + assert( firstChild == beforeThis ); + firstChild = node; + } + beforeThis->prev = node; + return node; +} + + +TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ) +{ + if ( !afterThis || afterThis->parent != this ) { + return 0; + } + if ( addThis.Type() == TiXmlNode::DOCUMENT ) + { + if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + TiXmlNode* node = addThis.Clone(); + if ( !node ) + return 0; + node->parent = this; + + node->prev = afterThis; + node->next = afterThis->next; + if ( afterThis->next ) + { + afterThis->next->prev = node; + } + else + { + assert( lastChild == afterThis ); + lastChild = node; + } + afterThis->next = node; + return node; +} + + +TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ) +{ + if ( replaceThis->parent != this ) + return 0; + + TiXmlNode* node = withThis.Clone(); + if ( !node ) + return 0; + + node->next = replaceThis->next; + node->prev = replaceThis->prev; + + if ( replaceThis->next ) + replaceThis->next->prev = node; + else + lastChild = node; + + if ( replaceThis->prev ) + replaceThis->prev->next = node; + else + firstChild = node; + + delete replaceThis; + node->parent = this; + return node; +} + + +bool TiXmlNode::RemoveChild( TiXmlNode* removeThis ) +{ + if ( removeThis->parent != this ) + { + assert( 0 ); + return false; + } + + if ( removeThis->next ) + removeThis->next->prev = removeThis->prev; + else + lastChild = removeThis->prev; + + if ( removeThis->prev ) + removeThis->prev->next = removeThis->next; + else + firstChild = removeThis->next; + + delete removeThis; + return true; +} + +const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const +{ + const TiXmlNode* node; + for ( node = firstChild; node; node = node->next ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; +} + + +const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const +{ + const TiXmlNode* node; + for ( node = lastChild; node; node = node->prev ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; +} + + +const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const +{ + if ( !previous ) + { + return FirstChild(); + } + else + { + assert( previous->parent == this ); + return previous->NextSibling(); + } +} + + +const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const +{ + if ( !previous ) + { + return FirstChild( val ); + } + else + { + assert( previous->parent == this ); + return previous->NextSibling( val ); + } +} + + +const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const +{ + const TiXmlNode* node; + for ( node = next; node; node = node->next ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; +} + + +const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const +{ + const TiXmlNode* node; + for ( node = prev; node; node = node->prev ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; +} + + +void TiXmlElement::RemoveAttribute( const char * name ) +{ + #ifdef TIXML_USE_STL + TIXML_STRING str( name ); + TiXmlAttribute* node = attributeSet.Find( str ); + #else + TiXmlAttribute* node = attributeSet.Find( name ); + #endif + if ( node ) + { + attributeSet.Remove( node ); + delete node; + } +} + +const TiXmlElement* TiXmlNode::FirstChildElement() const +{ + const TiXmlNode* node; + + for ( node = FirstChild(); + node; + node = node->NextSibling() ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const +{ + const TiXmlNode* node; + + for ( node = FirstChild( _value ); + node; + node = node->NextSibling( _value ) ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +const TiXmlElement* TiXmlNode::NextSiblingElement() const +{ + const TiXmlNode* node; + + for ( node = NextSibling(); + node; + node = node->NextSibling() ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const +{ + const TiXmlNode* node; + + for ( node = NextSibling( _value ); + node; + node = node->NextSibling( _value ) ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +const TiXmlDocument* TiXmlNode::GetDocument() const +{ + const TiXmlNode* node; + + for( node = this; node; node = node->parent ) + { + if ( node->ToDocument() ) + return node->ToDocument(); + } + return 0; +} + + +TiXmlElement::TiXmlElement (const char * _value) + : TiXmlNode( TiXmlNode::ELEMENT ) +{ + firstChild = lastChild = 0; + value = _value; +} + + +#ifdef TIXML_USE_STL +TiXmlElement::TiXmlElement( const std::string& _value ) + : TiXmlNode( TiXmlNode::ELEMENT ) +{ + firstChild = lastChild = 0; + value = _value; +} +#endif + + +TiXmlElement::TiXmlElement( const TiXmlElement& copy) + : TiXmlNode( TiXmlNode::ELEMENT ) +{ + firstChild = lastChild = 0; + copy.CopyTo( this ); +} + + +void TiXmlElement::operator=( const TiXmlElement& base ) +{ + ClearThis(); + base.CopyTo( this ); +} + + +TiXmlElement::~TiXmlElement() +{ + ClearThis(); +} + + +void TiXmlElement::ClearThis() +{ + Clear(); + while( attributeSet.First() ) + { + TiXmlAttribute* node = attributeSet.First(); + attributeSet.Remove( node ); + delete node; + } +} + + +const char* TiXmlElement::Attribute( const char* name ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( node ) + return node->Value(); + return 0; +} + + +#ifdef TIXML_USE_STL +const std::string* TiXmlElement::Attribute( const std::string& name ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( node ) + return &node->ValueStr(); + return 0; +} +#endif + + +const char* TiXmlElement::Attribute( const char* name, int* i ) const +{ + const char* s = Attribute( name ); + if ( i ) + { + if ( s ) { + *i = atoi( s ); + } + else { + *i = 0; + } + } + return s; +} + + +#ifdef TIXML_USE_STL +const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const +{ + const std::string* s = Attribute( name ); + if ( i ) + { + if ( s ) { + *i = atoi( s->c_str() ); + } + else { + *i = 0; + } + } + return s; +} +#endif + + +const char* TiXmlElement::Attribute( const char* name, double* d ) const +{ + const char* s = Attribute( name ); + if ( d ) + { + if ( s ) { + *d = atof( s ); + } + else { + *d = 0; + } + } + return s; +} + + +#ifdef TIXML_USE_STL +const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const +{ + const std::string* s = Attribute( name ); + if ( d ) + { + if ( s ) { + *d = atof( s->c_str() ); + } + else { + *d = 0; + } + } + return s; +} +#endif + + +int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + return node->QueryIntValue( ival ); +} + + +#ifdef TIXML_USE_STL +int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + return node->QueryIntValue( ival ); +} +#endif + + +int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + return node->QueryDoubleValue( dval ); +} + + +#ifdef TIXML_USE_STL +int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + return node->QueryDoubleValue( dval ); +} +#endif + + +void TiXmlElement::SetAttribute( const char * name, int val ) +{ + char buf[64]; + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF( buf, sizeof(buf), "%d", val ); + #else + sprintf( buf, "%d", val ); + #endif + SetAttribute( name, buf ); +} + + +#ifdef TIXML_USE_STL +void TiXmlElement::SetAttribute( const std::string& name, int val ) +{ + std::ostringstream oss; + oss << val; + SetAttribute( name, oss.str() ); +} +#endif + + +void TiXmlElement::SetDoubleAttribute( const char * name, double val ) +{ + char buf[256]; + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF( buf, sizeof(buf), "%f", val ); + #else + sprintf( buf, "%f", val ); + #endif + SetAttribute( name, buf ); +} + + +void TiXmlElement::SetAttribute( const char * cname, const char * cvalue ) +{ + #ifdef TIXML_USE_STL + TIXML_STRING _name( cname ); + TIXML_STRING _value( cvalue ); + #else + const char* _name = cname; + const char* _value = cvalue; + #endif + + TiXmlAttribute* node = attributeSet.Find( _name ); + if ( node ) + { + node->SetValue( _value ); + return; + } + + TiXmlAttribute* attrib = new TiXmlAttribute( cname, cvalue ); + if ( attrib ) + { + attributeSet.Add( attrib ); + } + else + { + TiXmlDocument* document = GetDocument(); + if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); + } +} + + +#ifdef TIXML_USE_STL +void TiXmlElement::SetAttribute( const std::string& name, const std::string& _value ) +{ + TiXmlAttribute* node = attributeSet.Find( name ); + if ( node ) + { + node->SetValue( _value ); + return; + } + + TiXmlAttribute* attrib = new TiXmlAttribute( name, _value ); + if ( attrib ) + { + attributeSet.Add( attrib ); + } + else + { + TiXmlDocument* document = GetDocument(); + if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); + } +} +#endif + + +void TiXmlElement::Print( FILE* cfile, int depth ) const +{ + int i; + assert( cfile ); + for ( i=0; iNext() ) + { + fprintf( cfile, " " ); + attrib->Print( cfile, depth ); + } + + // There are 3 different formatting approaches: + // 1) An element without children is printed as a node + // 2) An element with only a text child is printed as text + // 3) An element with children is printed on multiple lines. + TiXmlNode* node; + if ( !firstChild ) + { + fprintf( cfile, " />" ); + } + else if ( firstChild == lastChild && firstChild->ToText() ) + { + fprintf( cfile, ">" ); + firstChild->Print( cfile, depth + 1 ); + fprintf( cfile, "", value.c_str() ); + } + else + { + fprintf( cfile, ">" ); + + for ( node = firstChild; node; node=node->NextSibling() ) + { + if ( !node->ToText() ) + { + fprintf( cfile, "\n" ); + } + node->Print( cfile, depth+1 ); + } + fprintf( cfile, "\n" ); + for( i=0; i", value.c_str() ); + } +} + + +void TiXmlElement::CopyTo( TiXmlElement* target ) const +{ + // superclass: + TiXmlNode::CopyTo( target ); + + // Element class: + // Clone the attributes, then clone the children. + const TiXmlAttribute* attribute = 0; + for( attribute = attributeSet.First(); + attribute; + attribute = attribute->Next() ) + { + target->SetAttribute( attribute->Name(), attribute->Value() ); + } + + TiXmlNode* node = 0; + for ( node = firstChild; node; node = node->NextSibling() ) + { + target->LinkEndChild( node->Clone() ); + } +} + +bool TiXmlElement::Accept( TiXmlVisitor* visitor ) const +{ + if ( visitor->VisitEnter( *this, attributeSet.First() ) ) + { + for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) + { + if ( !node->Accept( visitor ) ) + break; + } + } + return visitor->VisitExit( *this ); +} + + +TiXmlNode* TiXmlElement::Clone() const +{ + TiXmlElement* clone = new TiXmlElement( Value() ); + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +const char* TiXmlElement::GetText() const +{ + const TiXmlNode* child = this->FirstChild(); + if ( child ) { + const TiXmlText* childText = child->ToText(); + if ( childText ) { + return childText->Value(); + } + } + return 0; +} + + +TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT ) +{ + tabsize = 4; + useMicrosoftBOM = false; + ClearError(); +} + +TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) +{ + tabsize = 4; + useMicrosoftBOM = false; + value = documentName; + ClearError(); +} + + +#ifdef TIXML_USE_STL +TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) +{ + tabsize = 4; + useMicrosoftBOM = false; + value = documentName; + ClearError(); +} +#endif + + +TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::DOCUMENT ) +{ + copy.CopyTo( this ); +} + + +void TiXmlDocument::operator=( const TiXmlDocument& copy ) +{ + Clear(); + copy.CopyTo( this ); +} + + +bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) +{ + // See STL_STRING_BUG below. + //StringToBuffer buf( value ); + + return LoadFile( Value(), encoding ); +} + + +bool TiXmlDocument::SaveFile() const +{ + // See STL_STRING_BUG below. +// StringToBuffer buf( value ); +// +// if ( buf.buffer && SaveFile( buf.buffer ) ) +// return true; +// +// return false; + return SaveFile( Value() ); +} + +bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding ) +{ + // There was a really terrifying little bug here. The code: + // value = filename + // in the STL case, cause the assignment method of the std::string to + // be called. What is strange, is that the std::string had the same + // address as it's c_str() method, and so bad things happen. Looks + // like a bug in the Microsoft STL implementation. + // Add an extra string to avoid the crash. + TIXML_STRING filename( _filename ); + value = filename; + + // reading in binary mode so that tinyxml can normalize the EOL + FILE* file = TiXmlFOpen( value.c_str (), "rb" ); + + if ( file ) + { + bool result = LoadFile( file, encoding ); + fclose( file ); + return result; + } + else + { + SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } +} + +bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding ) +{ + if ( !file ) + { + SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } + + // Delete the existing data: + Clear(); + location.Clear(); + + // Get the file size, so we can pre-allocate the string. HUGE speed impact. + long length = 0; + fseek( file, 0, SEEK_END ); + length = ftell( file ); + fseek( file, 0, SEEK_SET ); + + // Strange case, but good to handle up front. + if ( length <= 0 ) + { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } + + // If we have a file, assume it is all one big XML file, and read it in. + // The document parser may decide the document ends sooner than the entire file, however. + TIXML_STRING data; + data.reserve( length ); + + // Subtle bug here. TinyXml did use fgets. But from the XML spec: + // 2.11 End-of-Line Handling + // + // + // ...the XML processor MUST behave as if it normalized all line breaks in external + // parsed entities (including the document entity) on input, before parsing, by translating + // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to + // a single #xA character. + // + // + // It is not clear fgets does that, and certainly isn't clear it works cross platform. + // Generally, you expect fgets to translate from the convention of the OS to the c/unix + // convention, and not work generally. + + /* + while( fgets( buf, sizeof(buf), file ) ) + { + data += buf; + } + */ + + char* buf = new char[ length+1 ]; + buf[0] = 0; + + if ( fread( buf, length, 1, file ) != 1 ) { + delete [] buf; + SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } + + const char* lastPos = buf; + const char* p = buf; + + buf[length] = 0; + while( *p ) { + assert( p < (buf+length) ); + if ( *p == 0xa ) { + // Newline character. No special rules for this. Append all the characters + // since the last string, and include the newline. + data.append( lastPos, (p-lastPos+1) ); // append, include the newline + ++p; // move past the newline + lastPos = p; // and point to the new buffer (may be 0) + assert( p <= (buf+length) ); + } + else if ( *p == 0xd ) { + // Carriage return. Append what we have so far, then + // handle moving forward in the buffer. + if ( (p-lastPos) > 0 ) { + data.append( lastPos, p-lastPos ); // do not add the CR + } + data += (char)0xa; // a proper newline + + if ( *(p+1) == 0xa ) { + // Carriage return - new line sequence + p += 2; + lastPos = p; + assert( p <= (buf+length) ); + } + else { + // it was followed by something else...that is presumably characters again. + ++p; + lastPos = p; + assert( p <= (buf+length) ); + } + } + else { + ++p; + } + } + // Handle any left over characters. + if ( p-lastPos ) { + data.append( lastPos, p-lastPos ); + } + delete [] buf; + buf = 0; + + Parse( data.c_str(), 0, encoding ); + + if ( Error() ) + return false; + else + return true; +} + + +bool TiXmlDocument::SaveFile( const char * filename ) const +{ + // The old c stuff lives on... + FILE* fp = TiXmlFOpen( filename, "w" ); + if ( fp ) + { + bool result = SaveFile( fp ); + fclose( fp ); + return result; + } + return false; +} + + +bool TiXmlDocument::SaveFile( FILE* fp ) const +{ + if ( useMicrosoftBOM ) + { + const unsigned char TIXML_UTF_LEAD_0 = 0xefU; + const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; + const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; + + fputc( TIXML_UTF_LEAD_0, fp ); + fputc( TIXML_UTF_LEAD_1, fp ); + fputc( TIXML_UTF_LEAD_2, fp ); + } + Print( fp, 0 ); + return (ferror(fp) == 0); +} + + +void TiXmlDocument::CopyTo( TiXmlDocument* target ) const +{ + TiXmlNode::CopyTo( target ); + + target->error = error; + target->errorId = errorId; + target->errorDesc = errorDesc; + target->tabsize = tabsize; + target->errorLocation = errorLocation; + target->useMicrosoftBOM = useMicrosoftBOM; + + TiXmlNode* node = 0; + for ( node = firstChild; node; node = node->NextSibling() ) + { + target->LinkEndChild( node->Clone() ); + } +} + + +TiXmlNode* TiXmlDocument::Clone() const +{ + TiXmlDocument* clone = new TiXmlDocument(); + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +void TiXmlDocument::Print( FILE* cfile, int depth ) const +{ + assert( cfile ); + for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) + { + node->Print( cfile, depth ); + fprintf( cfile, "\n" ); + } +} + + +bool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const +{ + if ( visitor->VisitEnter( *this ) ) + { + for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) + { + if ( !node->Accept( visitor ) ) + break; + } + } + return visitor->VisitExit( *this ); +} + + +const TiXmlAttribute* TiXmlAttribute::Next() const +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( next->value.empty() && next->name.empty() ) + return 0; + return next; +} + +/* +TiXmlAttribute* TiXmlAttribute::Next() +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( next->value.empty() && next->name.empty() ) + return 0; + return next; +} +*/ + +const TiXmlAttribute* TiXmlAttribute::Previous() const +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( prev->value.empty() && prev->name.empty() ) + return 0; + return prev; +} + +/* +TiXmlAttribute* TiXmlAttribute::Previous() +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( prev->value.empty() && prev->name.empty() ) + return 0; + return prev; +} +*/ + +void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const +{ + TIXML_STRING n, v; + + EncodeString( name, &n ); + EncodeString( value, &v ); + + if (value.find ('\"') == TIXML_STRING::npos) { + if ( cfile ) { + fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); + } + if ( str ) { + (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\""; + } + } + else { + if ( cfile ) { + fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); + } + if ( str ) { + (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'"; + } + } +} + + +int TiXmlAttribute::QueryIntValue( int* ival ) const +{ + if ( TIXML_SSCANF( value.c_str(), "%d", ival ) == 1 ) + return TIXML_SUCCESS; + return TIXML_WRONG_TYPE; +} + +int TiXmlAttribute::QueryDoubleValue( double* dval ) const +{ + if ( TIXML_SSCANF( value.c_str(), "%lf", dval ) == 1 ) + return TIXML_SUCCESS; + return TIXML_WRONG_TYPE; +} + +void TiXmlAttribute::SetIntValue( int _value ) +{ + char buf [64]; + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value); + #else + sprintf (buf, "%d", _value); + #endif + SetValue (buf); +} + +void TiXmlAttribute::SetDoubleValue( double _value ) +{ + char buf [256]; + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF( buf, sizeof(buf), "%lf", _value); + #else + sprintf (buf, "%lf", _value); + #endif + SetValue (buf); +} + +int TiXmlAttribute::IntValue() const +{ + return atoi (value.c_str ()); +} + +double TiXmlAttribute::DoubleValue() const +{ + return atof (value.c_str ()); +} + + +TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::COMMENT ) +{ + copy.CopyTo( this ); +} + + +void TiXmlComment::operator=( const TiXmlComment& base ) +{ + Clear(); + base.CopyTo( this ); +} + + +void TiXmlComment::Print( FILE* cfile, int depth ) const +{ + assert( cfile ); + for ( int i=0; i", value.c_str() ); +} + + +void TiXmlComment::CopyTo( TiXmlComment* target ) const +{ + TiXmlNode::CopyTo( target ); +} + + +bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +TiXmlNode* TiXmlComment::Clone() const +{ + TiXmlComment* clone = new TiXmlComment(); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +void TiXmlText::Print( FILE* cfile, int depth ) const +{ + assert( cfile ); + if ( cdata ) + { + int i; + fprintf( cfile, "\n" ); + for ( i=0; i\n", value.c_str() ); // unformatted output + } + else + { + TIXML_STRING buffer; + EncodeString( value, &buffer ); + fprintf( cfile, "%s", buffer.c_str() ); + } +} + + +void TiXmlText::CopyTo( TiXmlText* target ) const +{ + TiXmlNode::CopyTo( target ); + target->cdata = cdata; +} + + +bool TiXmlText::Accept( TiXmlVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +TiXmlNode* TiXmlText::Clone() const +{ + TiXmlText* clone = 0; + clone = new TiXmlText( "" ); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +TiXmlDeclaration::TiXmlDeclaration( const char * _version, + const char * _encoding, + const char * _standalone ) + : TiXmlNode( TiXmlNode::DECLARATION ) +{ + version = _version; + encoding = _encoding; + standalone = _standalone; +} + + +#ifdef TIXML_USE_STL +TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, + const std::string& _encoding, + const std::string& _standalone ) + : TiXmlNode( TiXmlNode::DECLARATION ) +{ + version = _version; + encoding = _encoding; + standalone = _standalone; +} +#endif + + +TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) + : TiXmlNode( TiXmlNode::DECLARATION ) +{ + copy.CopyTo( this ); +} + + +void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) +{ + Clear(); + copy.CopyTo( this ); +} + + +void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const +{ + if ( cfile ) fprintf( cfile, "" ); + if ( str ) (*str) += "?>"; +} + + +void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const +{ + TiXmlNode::CopyTo( target ); + + target->version = version; + target->encoding = encoding; + target->standalone = standalone; +} + + +bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +TiXmlNode* TiXmlDeclaration::Clone() const +{ + TiXmlDeclaration* clone = new TiXmlDeclaration(); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +void TiXmlUnknown::Print( FILE* cfile, int depth ) const +{ + for ( int i=0; i", value.c_str() ); +} + + +void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const +{ + TiXmlNode::CopyTo( target ); +} + + +bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +TiXmlNode* TiXmlUnknown::Clone() const +{ + TiXmlUnknown* clone = new TiXmlUnknown(); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +TiXmlAttributeSet::TiXmlAttributeSet() +{ + sentinel.next = &sentinel; + sentinel.prev = &sentinel; +} + + +TiXmlAttributeSet::~TiXmlAttributeSet() +{ + assert( sentinel.next == &sentinel ); + assert( sentinel.prev == &sentinel ); +} + + +void TiXmlAttributeSet::Add( TiXmlAttribute* addMe ) +{ + #ifdef TIXML_USE_STL + assert( !Find( TIXML_STRING( addMe->Name() ) ) ); // Shouldn't be multiply adding to the set. + #else + assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set. + #endif + + addMe->next = &sentinel; + addMe->prev = sentinel.prev; + + sentinel.prev->next = addMe; + sentinel.prev = addMe; +} + +void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe ) +{ + TiXmlAttribute* node; + + for( node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( node == removeMe ) + { + node->prev->next = node->next; + node->next->prev = node->prev; + node->next = 0; + node->prev = 0; + return; + } + } + assert( 0 ); // we tried to remove a non-linked attribute. +} + + +#ifdef TIXML_USE_STL +const TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const +{ + for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( node->name == name ) + return node; + } + return 0; +} + +/* +TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) +{ + for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( node->name == name ) + return node; + } + return 0; +} +*/ +#endif + + +const TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const +{ + for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( strcmp( node->name.c_str(), name ) == 0 ) + return node; + } + return 0; +} + +/* +TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) +{ + for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( strcmp( node->name.c_str(), name ) == 0 ) + return node; + } + return 0; +} +*/ + +#ifdef TIXML_USE_STL +std::istream& operator>> (std::istream & in, TiXmlNode & base) +{ + TIXML_STRING tag; + tag.reserve( 8 * 1000 ); + base.StreamIn( &in, &tag ); + + base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING ); + return in; +} +#endif + + +#ifdef TIXML_USE_STL +std::ostream& operator<< (std::ostream & out, const TiXmlNode & base) +{ + TiXmlPrinter printer; + printer.SetStreamPrinting(); + base.Accept( &printer ); + out << printer.Str(); + + return out; +} + + +std::string& operator<< (std::string& out, const TiXmlNode& base ) +{ + TiXmlPrinter printer; + printer.SetStreamPrinting(); + base.Accept( &printer ); + out.append( printer.Str() ); + + return out; +} +#endif + + +TiXmlHandle TiXmlHandle::FirstChild() const +{ + if ( node ) + { + TiXmlNode* child = node->FirstChild(); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const +{ + if ( node ) + { + TiXmlNode* child = node->FirstChild( value ); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::FirstChildElement() const +{ + if ( node ) + { + TiXmlElement* child = node->FirstChildElement(); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const +{ + if ( node ) + { + TiXmlElement* child = node->FirstChildElement( value ); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::Child( int count ) const +{ + if ( node ) + { + int i; + TiXmlNode* child = node->FirstChild(); + for ( i=0; + child && iNextSibling(), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const +{ + if ( node ) + { + int i; + TiXmlNode* child = node->FirstChild( value ); + for ( i=0; + child && iNextSibling( value ), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::ChildElement( int count ) const +{ + if ( node ) + { + int i; + TiXmlElement* child = node->FirstChildElement(); + for ( i=0; + child && iNextSiblingElement(), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const +{ + if ( node ) + { + int i; + TiXmlElement* child = node->FirstChildElement( value ); + for ( i=0; + child && iNextSiblingElement( value ), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +bool TiXmlPrinter::VisitEnter( const TiXmlDocument& ) +{ + return true; +} + +bool TiXmlPrinter::VisitExit( const TiXmlDocument& ) +{ + return true; +} + +bool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ) +{ + DoIndent(); + buffer += "<"; + buffer += element.Value(); + + for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() ) + { + buffer += " "; + attrib->Print( 0, 0, &buffer ); + } + + if ( !element.FirstChild() ) + { + buffer += " />"; + DoLineBreak(); + } + else + { + buffer += ">"; + if ( element.FirstChild()->ToText() + && element.LastChild() == element.FirstChild() + && element.FirstChild()->ToText()->CDATA() == false ) + { + simpleTextPrint = true; + // no DoLineBreak()! + } + else + { + DoLineBreak(); + } + } + ++depth; + return true; +} + + +bool TiXmlPrinter::VisitExit( const TiXmlElement& element ) +{ + --depth; + if ( !element.FirstChild() ) + { + // nothing. + } + else + { + if ( simpleTextPrint ) + { + simpleTextPrint = false; + } + else + { + DoIndent(); + } + buffer += ""; + DoLineBreak(); + } + return true; +} + + +bool TiXmlPrinter::Visit( const TiXmlText& text ) +{ + if ( text.CDATA() ) + { + DoIndent(); + buffer += ""; + DoLineBreak(); + } + else if ( simpleTextPrint ) + { + TIXML_STRING str; + TiXmlBase::EncodeString( text.ValueTStr(), &str ); + buffer += str; + } + else + { + DoIndent(); + TIXML_STRING str; + TiXmlBase::EncodeString( text.ValueTStr(), &str ); + buffer += str; + DoLineBreak(); + } + return true; +} + + +bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration ) +{ + DoIndent(); + declaration.Print( 0, 0, &buffer ); + DoLineBreak(); + return true; +} + + +bool TiXmlPrinter::Visit( const TiXmlComment& comment ) +{ + DoIndent(); + buffer += ""; + DoLineBreak(); + return true; +} + + +bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown ) +{ + DoIndent(); + buffer += "<"; + buffer += unknown.Value(); + buffer += ">"; + DoLineBreak(); + return true; +} + diff --git a/extern/oics/tinyxml.h b/extern/oics/tinyxml.h new file mode 100644 index 000000000..e69913b59 --- /dev/null +++ b/extern/oics/tinyxml.h @@ -0,0 +1,1802 @@ +/* +www.sourceforge.net/projects/tinyxml +Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +//#define TIXML_USE_STL + +#ifndef TINYXML_INCLUDED +#define TINYXML_INCLUDED + +#ifdef _MSC_VER +#pragma warning( push ) +#pragma warning( disable : 4530 ) +#pragma warning( disable : 4786 ) +#endif + +#include +#include +#include +#include +#include + +// Help out windows: +#if defined( _DEBUG ) && !defined( DEBUG ) +#define DEBUG +#endif + +#ifdef TIXML_USE_STL + #include + #include + #include + #define TIXML_STRING std::string +#else + #include "tinystr.h" + #define TIXML_STRING TiXmlString +#endif + +// Deprecated library function hell. Compilers want to use the +// new safe versions. This probably doesn't fully address the problem, +// but it gets closer. There are too many compilers for me to fully +// test. If you get compilation troubles, undefine TIXML_SAFE +#define TIXML_SAFE + +#ifdef TIXML_SAFE + #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) + // Microsoft visual studio, version 2005 and higher. + #define TIXML_SNPRINTF _snprintf_s + #define TIXML_SNSCANF _snscanf_s + #define TIXML_SSCANF sscanf_s + #elif defined(_MSC_VER) && (_MSC_VER >= 1200 ) + // Microsoft visual studio, version 6 and higher. + //#pragma message( "Using _sn* functions." ) + #define TIXML_SNPRINTF _snprintf + #define TIXML_SNSCANF _snscanf + #define TIXML_SSCANF sscanf + #elif defined(__GNUC__) && (__GNUC__ >= 3 ) + // GCC version 3 and higher.s + //#warning( "Using sn* functions." ) + #define TIXML_SNPRINTF snprintf + #define TIXML_SNSCANF snscanf + #define TIXML_SSCANF sscanf + #else + #define TIXML_SSCANF sscanf + #endif +#endif + +class TiXmlDocument; +class TiXmlElement; +class TiXmlComment; +class TiXmlUnknown; +class TiXmlAttribute; +class TiXmlText; +class TiXmlDeclaration; +class TiXmlParsingData; + +const int TIXML_MAJOR_VERSION = 2; +const int TIXML_MINOR_VERSION = 5; +const int TIXML_PATCH_VERSION = 3; + +/* Internal structure for tracking location of items + in the XML file. +*/ +struct TiXmlCursor +{ + TiXmlCursor() { Clear(); } + void Clear() { row = col = -1; } + + int row; // 0 based. + int col; // 0 based. +}; + + +/** + If you call the Accept() method, it requires being passed a TiXmlVisitor + class to handle callbacks. For nodes that contain other nodes (Document, Element) + you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves + are simple called with Visit(). + + If you return 'true' from a Visit method, recursive parsing will continue. If you return + false, no children of this node or its sibilings will be Visited. + + All flavors of Visit methods have a default implementation that returns 'true' (continue + visiting). You need to only override methods that are interesting to you. + + Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting. + + You should never change the document from a callback. + + @sa TiXmlNode::Accept() +*/ +class TiXmlVisitor +{ +public: + virtual ~TiXmlVisitor() {} + + /// Visit a document. + virtual bool VisitEnter( const TiXmlDocument& /*doc*/ ) { return true; } + /// Visit a document. + virtual bool VisitExit( const TiXmlDocument& /*doc*/ ) { return true; } + + /// Visit an element. + virtual bool VisitEnter( const TiXmlElement& /*element*/, const TiXmlAttribute* /*firstAttribute*/ ) { return true; } + /// Visit an element. + virtual bool VisitExit( const TiXmlElement& /*element*/ ) { return true; } + + /// Visit a declaration + virtual bool Visit( const TiXmlDeclaration& /*declaration*/ ) { return true; } + /// Visit a text node + virtual bool Visit( const TiXmlText& /*text*/ ) { return true; } + /// Visit a comment node + virtual bool Visit( const TiXmlComment& /*comment*/ ) { return true; } + /// Visit an unknow node + virtual bool Visit( const TiXmlUnknown& /*unknown*/ ) { return true; } +}; + +// Only used by Attribute::Query functions +enum +{ + TIXML_SUCCESS, + TIXML_NO_ATTRIBUTE, + TIXML_WRONG_TYPE +}; + + +// Used by the parsing routines. +enum TiXmlEncoding +{ + TIXML_ENCODING_UNKNOWN, + TIXML_ENCODING_UTF8, + TIXML_ENCODING_LEGACY +}; + +const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN; + +/** TiXmlBase is a base class for every class in TinyXml. + It does little except to establish that TinyXml classes + can be printed and provide some utility functions. + + In XML, the document and elements can contain + other elements and other types of nodes. + + @verbatim + A Document can contain: Element (container or leaf) + Comment (leaf) + Unknown (leaf) + Declaration( leaf ) + + An Element can contain: Element (container or leaf) + Text (leaf) + Attributes (not on tree) + Comment (leaf) + Unknown (leaf) + + A Decleration contains: Attributes (not on tree) + @endverbatim +*/ +class TiXmlBase +{ + friend class TiXmlNode; + friend class TiXmlElement; + friend class TiXmlDocument; + +public: + TiXmlBase() : userData(0) {} + virtual ~TiXmlBase() {} + + /** All TinyXml classes can print themselves to a filestream + or the string class (TiXmlString in non-STL mode, std::string + in STL mode.) Either or both cfile and str can be null. + + This is a formatted print, and will insert + tabs and newlines. + + (For an unformatted stream, use the << operator.) + */ + virtual void Print( FILE* cfile, int depth ) const = 0; + + /** The world does not agree on whether white space should be kept or + not. In order to make everyone happy, these global, static functions + are provided to set whether or not TinyXml will condense all white space + into a single space or not. The default is to condense. Note changing this + value is not thread safe. + */ + static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; } + + /// Return the current white space setting. + static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; } + + /** Return the position, in the original source file, of this node or attribute. + The row and column are 1-based. (That is the first row and first column is + 1,1). If the returns values are 0 or less, then the parser does not have + a row and column value. + + Generally, the row and column value will be set when the TiXmlDocument::Load(), + TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set + when the DOM was created from operator>>. + + The values reflect the initial load. Once the DOM is modified programmatically + (by adding or changing nodes and attributes) the new values will NOT update to + reflect changes in the document. + + There is a minor performance cost to computing the row and column. Computation + can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value. + + @sa TiXmlDocument::SetTabSize() + */ + int Row() const { return location.row + 1; } + int Column() const { return location.col + 1; } ///< See Row() + + void SetUserData( void* user ) { userData = user; } ///< Set a pointer to arbitrary user data. + void* GetUserData() { return userData; } ///< Get a pointer to arbitrary user data. + const void* GetUserData() const { return userData; } ///< Get a pointer to arbitrary user data. + + // Table that returs, for a given lead byte, the total number of bytes + // in the UTF-8 sequence. + static const int utf8ByteTable[256]; + + virtual const char* Parse( const char* p, + TiXmlParsingData* data, + TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0; + + /** Expands entities in a string. Note this should not contian the tag's '<', '>', etc, + or they will be transformed into entities! + */ + static void EncodeString( const TIXML_STRING& str, TIXML_STRING* out ); + + enum + { + TIXML_NO_ERROR = 0, + TIXML_ERROR, + TIXML_ERROR_OPENING_FILE, + TIXML_ERROR_OUT_OF_MEMORY, + TIXML_ERROR_PARSING_ELEMENT, + TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, + TIXML_ERROR_READING_ELEMENT_VALUE, + TIXML_ERROR_READING_ATTRIBUTES, + TIXML_ERROR_PARSING_EMPTY, + TIXML_ERROR_READING_END_TAG, + TIXML_ERROR_PARSING_UNKNOWN, + TIXML_ERROR_PARSING_COMMENT, + TIXML_ERROR_PARSING_DECLARATION, + TIXML_ERROR_DOCUMENT_EMPTY, + TIXML_ERROR_EMBEDDED_NULL, + TIXML_ERROR_PARSING_CDATA, + TIXML_ERROR_DOCUMENT_TOP_ONLY, + + TIXML_ERROR_STRING_COUNT + }; + +protected: + + static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding ); + inline static bool IsWhiteSpace( char c ) + { + return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); + } + inline static bool IsWhiteSpace( int c ) + { + if ( c < 256 ) + return IsWhiteSpace( (char) c ); + return false; // Again, only truly correct for English/Latin...but usually works. + } + + #ifdef TIXML_USE_STL + static bool StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ); + static bool StreamTo( std::istream * in, int character, TIXML_STRING * tag ); + #endif + + /* Reads an XML name into the string provided. Returns + a pointer just past the last character of the name, + or 0 if the function has an error. + */ + static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding ); + + /* Reads text. Returns a pointer past the given end tag. + Wickedly complex options, but it keeps the (sensitive) code in one place. + */ + static const char* ReadText( const char* in, // where to start + TIXML_STRING* text, // the string read + bool ignoreWhiteSpace, // whether to keep the white space + const char* endTag, // what ends this text + bool ignoreCase, // whether to ignore case in the end tag + TiXmlEncoding encoding ); // the current encoding + + // If an entity has been found, transform it into a character. + static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding ); + + // Get a character, while interpreting entities. + // The length can be from 0 to 4 bytes. + inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding ) + { + assert( p ); + if ( encoding == TIXML_ENCODING_UTF8 ) + { + *length = utf8ByteTable[ *((const unsigned char*)p) ]; + assert( *length >= 0 && *length < 5 ); + } + else + { + *length = 1; + } + + if ( *length == 1 ) + { + if ( *p == '&' ) + return GetEntity( p, _value, length, encoding ); + *_value = *p; + return p+1; + } + else if ( *length ) + { + //strncpy( _value, p, *length ); // lots of compilers don't like this function (unsafe), + // and the null terminator isn't needed + for( int i=0; p[i] && i<*length; ++i ) { + _value[i] = p[i]; + } + return p + (*length); + } + else + { + // Not valid text. + return 0; + } + } + + // Return true if the next characters in the stream are any of the endTag sequences. + // Ignore case only works for english, and should only be relied on when comparing + // to English words: StringEqual( p, "version", true ) is fine. + static bool StringEqual( const char* p, + const char* endTag, + bool ignoreCase, + TiXmlEncoding encoding ); + + static const char* errorString[ TIXML_ERROR_STRING_COUNT ]; + + TiXmlCursor location; + + /// Field containing a generic user pointer + void* userData; + + // None of these methods are reliable for any language except English. + // Good for approximation, not great for accuracy. + static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ); + static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ); + inline static int ToLower( int v, TiXmlEncoding encoding ) + { + if ( encoding == TIXML_ENCODING_UTF8 ) + { + if ( v < 128 ) return tolower( v ); + return v; + } + else + { + return tolower( v ); + } + } + static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); + +private: + TiXmlBase( const TiXmlBase& ); // not implemented. + void operator=( const TiXmlBase& base ); // not allowed. + + struct Entity + { + const char* str; + unsigned int strLength; + char chr; + }; + enum + { + NUM_ENTITY = 5, + MAX_ENTITY_LENGTH = 6 + + }; + static Entity entity[ NUM_ENTITY ]; + static bool condenseWhiteSpace; +}; + + +/** The parent class for everything in the Document Object Model. + (Except for attributes). + Nodes have siblings, a parent, and children. A node can be + in a document, or stand on its own. The type of a TiXmlNode + can be queried, and it can be cast to its more defined type. +*/ +class TiXmlNode : public TiXmlBase +{ + friend class TiXmlDocument; + friend class TiXmlElement; + +public: + #ifdef TIXML_USE_STL + + /** An input stream operator, for every class. Tolerant of newlines and + formatting, but doesn't expect them. + */ + friend std::istream& operator >> (std::istream& in, TiXmlNode& base); + + /** An output stream operator, for every class. Note that this outputs + without any newlines or formatting, as opposed to Print(), which + includes tabs and new lines. + + The operator<< and operator>> are not completely symmetric. Writing + a node to a stream is very well defined. You'll get a nice stream + of output, without any extra whitespace or newlines. + + But reading is not as well defined. (As it always is.) If you create + a TiXmlElement (for example) and read that from an input stream, + the text needs to define an element or junk will result. This is + true of all input streams, but it's worth keeping in mind. + + A TiXmlDocument will read nodes until it reads a root element, and + all the children of that root element. + */ + friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base); + + /// Appends the XML node or attribute to a std::string. + friend std::string& operator<< (std::string& out, const TiXmlNode& base ); + + #endif + + /** The types of XML nodes supported by TinyXml. (All the + unsupported types are picked up by UNKNOWN.) + */ + enum NodeType + { + DOCUMENT, + ELEMENT, + COMMENT, + UNKNOWN, + TEXT, + DECLARATION, + TYPECOUNT + }; + + virtual ~TiXmlNode(); + + /** The meaning of 'value' changes for the specific type of + TiXmlNode. + @verbatim + Document: filename of the xml file + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + + The subclasses will wrap this function. + */ + const char *Value() const { return value.c_str (); } + + #ifdef TIXML_USE_STL + /** Return Value() as a std::string. If you only use STL, + this is more efficient than calling Value(). + Only available in STL mode. + */ + const std::string& ValueStr() const { return value; } + #endif + + const TIXML_STRING& ValueTStr() const { return value; } + + /** Changes the value of the node. Defined as: + @verbatim + Document: filename of the xml file + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + */ + void SetValue(const char * _value) { value = _value;} + + #ifdef TIXML_USE_STL + /// STL std::string form. + void SetValue( const std::string& _value ) { value = _value; } + #endif + + /// Delete all the children of this node. Does not affect 'this'. + void Clear(); + + /// One step up the DOM. + TiXmlNode* Parent() { return parent; } + const TiXmlNode* Parent() const { return parent; } + + const TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children. + TiXmlNode* FirstChild() { return firstChild; } + const TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found. + /// The first child of this node with the matching 'value'. Will be null if none found. + TiXmlNode* FirstChild( const char * _value ) { + // Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe) + // call the method, cast the return back to non-const. + return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->FirstChild( _value )); + } + const TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children. + TiXmlNode* LastChild() { return lastChild; } + + const TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children. + TiXmlNode* LastChild( const char * _value ) { + return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->LastChild( _value )); + } + + #ifdef TIXML_USE_STL + const TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* FirstChild( const std::string& _value ) { return FirstChild (_value.c_str ()); } ///< STL std::string form. + const TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* LastChild( const std::string& _value ) { return LastChild (_value.c_str ()); } ///< STL std::string form. + #endif + + /** An alternate way to walk the children of a node. + One way to iterate over nodes is: + @verbatim + for( child = parent->FirstChild(); child; child = child->NextSibling() ) + @endverbatim + + IterateChildren does the same thing with the syntax: + @verbatim + child = 0; + while( child = parent->IterateChildren( child ) ) + @endverbatim + + IterateChildren takes the previous child as input and finds + the next one. If the previous child is null, it returns the + first. IterateChildren will return null when done. + */ + const TiXmlNode* IterateChildren( const TiXmlNode* previous ) const; + TiXmlNode* IterateChildren( const TiXmlNode* previous ) { + return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( previous ) ); + } + + /// This flavor of IterateChildren searches for children with a particular 'value' + const TiXmlNode* IterateChildren( const char * value, const TiXmlNode* previous ) const; + TiXmlNode* IterateChildren( const char * _value, const TiXmlNode* previous ) { + return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( _value, previous ) ); + } + + #ifdef TIXML_USE_STL + const TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. + TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. + #endif + + /** Add a new node related to this. Adds a child past the LastChild. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* InsertEndChild( const TiXmlNode& addThis ); + + + /** Add a new node related to this. Adds a child past the LastChild. + + NOTE: the node to be added is passed by pointer, and will be + henceforth owned (and deleted) by tinyXml. This method is efficient + and avoids an extra copy, but should be used with care as it + uses a different memory model than the other insert functions. + + @sa InsertEndChild + */ + TiXmlNode* LinkEndChild( TiXmlNode* addThis ); + + /** Add a new node related to this. Adds a child before the specified child. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ); + + /** Add a new node related to this. Adds a child after the specified child. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ); + + /** Replace a child of this node. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ); + + /// Delete a child of this node. + bool RemoveChild( TiXmlNode* removeThis ); + + /// Navigate to a sibling node. + const TiXmlNode* PreviousSibling() const { return prev; } + TiXmlNode* PreviousSibling() { return prev; } + + /// Navigate to a sibling node. + const TiXmlNode* PreviousSibling( const char * ) const; + TiXmlNode* PreviousSibling( const char *_prev ) { + return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->PreviousSibling( _prev ) ); + } + + #ifdef TIXML_USE_STL + const TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* PreviousSibling( const std::string& _value ) { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. + const TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* NextSibling( const std::string& _value) { return NextSibling (_value.c_str ()); } ///< STL std::string form. + #endif + + /// Navigate to a sibling node. + const TiXmlNode* NextSibling() const { return next; } + TiXmlNode* NextSibling() { return next; } + + /// Navigate to a sibling node with the given 'value'. + const TiXmlNode* NextSibling( const char * ) const; + TiXmlNode* NextSibling( const char* _next ) { + return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->NextSibling( _next ) ); + } + + /** Convenience function to get through elements. + Calls NextSibling and ToElement. Will skip all non-Element + nodes. Returns 0 if there is not another element. + */ + const TiXmlElement* NextSiblingElement() const; + TiXmlElement* NextSiblingElement() { + return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement() ); + } + + /** Convenience function to get through elements. + Calls NextSibling and ToElement. Will skip all non-Element + nodes. Returns 0 if there is not another element. + */ + const TiXmlElement* NextSiblingElement( const char * ) const; + TiXmlElement* NextSiblingElement( const char *_next ) { + return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement( _next ) ); + } + + #ifdef TIXML_USE_STL + const TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. + TiXmlElement* NextSiblingElement( const std::string& _value) { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. + #endif + + /// Convenience function to get through elements. + const TiXmlElement* FirstChildElement() const; + TiXmlElement* FirstChildElement() { + return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement() ); + } + + /// Convenience function to get through elements. + const TiXmlElement* FirstChildElement( const char * _value ) const; + TiXmlElement* FirstChildElement( const char * _value ) { + return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement( _value ) ); + } + + #ifdef TIXML_USE_STL + const TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. + TiXmlElement* FirstChildElement( const std::string& _value ) { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. + #endif + + /** Query the type (as an enumerated value, above) of this node. + The possible types are: DOCUMENT, ELEMENT, COMMENT, + UNKNOWN, TEXT, and DECLARATION. + */ + int Type() const { return type; } + + /** Return a pointer to the Document this node lives in. + Returns null if not in a document. + */ + const TiXmlDocument* GetDocument() const; + TiXmlDocument* GetDocument() { + return const_cast< TiXmlDocument* >( (const_cast< const TiXmlNode* >(this))->GetDocument() ); + } + + /// Returns true if this node has no children. + bool NoChildren() const { return !firstChild; } + + virtual const TiXmlDocument* ToDocument() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlElement* ToElement() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlComment* ToComment() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlUnknown* ToUnknown() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlText* ToText() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlDeclaration* ToDeclaration() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + + virtual TiXmlDocument* ToDocument() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlElement* ToElement() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlComment* ToComment() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlUnknown* ToUnknown() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlText* ToText() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlDeclaration* ToDeclaration() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + + /** Create an exact duplicate of this node and return it. The memory must be deleted + by the caller. + */ + virtual TiXmlNode* Clone() const = 0; + + /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the + XML tree will be conditionally visited and the host will be called back + via the TiXmlVisitor interface. + + This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse + the XML for the callbacks, so the performance of TinyXML is unchanged by using this + interface versus any other.) + + The interface has been based on ideas from: + + - http://www.saxproject.org/ + - http://c2.com/cgi/wiki?HierarchicalVisitorPattern + + Which are both good references for "visiting". + + An example of using Accept(): + @verbatim + TiXmlPrinter printer; + tinyxmlDoc.Accept( &printer ); + const char* xmlcstr = printer.CStr(); + @endverbatim + */ + virtual bool Accept( TiXmlVisitor* visitor ) const = 0; + +protected: + TiXmlNode( NodeType _type ); + + // Copy to the allocated object. Shared functionality between Clone, Copy constructor, + // and the assignment operator. + void CopyTo( TiXmlNode* target ) const; + + #ifdef TIXML_USE_STL + // The real work of the input operator. + virtual void StreamIn( std::istream* in, TIXML_STRING* tag ) = 0; + #endif + + // Figure out what is at *p, and parse it. Returns null if it is not an xml node. + TiXmlNode* Identify( const char* start, TiXmlEncoding encoding ); + + TiXmlNode* parent; + NodeType type; + + TiXmlNode* firstChild; + TiXmlNode* lastChild; + + TIXML_STRING value; + + TiXmlNode* prev; + TiXmlNode* next; + +private: + TiXmlNode( const TiXmlNode& ); // not implemented. + void operator=( const TiXmlNode& base ); // not allowed. +}; + + +/** An attribute is a name-value pair. Elements have an arbitrary + number of attributes, each with a unique name. + + @note The attributes are not TiXmlNodes, since they are not + part of the tinyXML document object model. There are other + suggested ways to look at this problem. +*/ +class TiXmlAttribute : public TiXmlBase +{ + friend class TiXmlAttributeSet; + +public: + /// Construct an empty attribute. + TiXmlAttribute() : TiXmlBase() + { + document = 0; + prev = next = 0; + } + + #ifdef TIXML_USE_STL + /// std::string constructor. + TiXmlAttribute( const std::string& _name, const std::string& _value ) + { + name = _name; + value = _value; + document = 0; + prev = next = 0; + } + #endif + + /// Construct an attribute with a name and value. + TiXmlAttribute( const char * _name, const char * _value ) + { + name = _name; + value = _value; + document = 0; + prev = next = 0; + } + + const char* Name() const { return name.c_str(); } ///< Return the name of this attribute. + const char* Value() const { return value.c_str(); } ///< Return the value of this attribute. + #ifdef TIXML_USE_STL + const std::string& ValueStr() const { return value; } ///< Return the value of this attribute. + #endif + int IntValue() const; ///< Return the value of this attribute, converted to an integer. + double DoubleValue() const; ///< Return the value of this attribute, converted to a double. + + // Get the tinyxml string representation + const TIXML_STRING& NameTStr() const { return name; } + + /** QueryIntValue examines the value string. It is an alternative to the + IntValue() method with richer error checking. + If the value is an integer, it is stored in 'value' and + the call returns TIXML_SUCCESS. If it is not + an integer, it returns TIXML_WRONG_TYPE. + + A specialized but useful call. Note that for success it returns 0, + which is the opposite of almost all other TinyXml calls. + */ + int QueryIntValue( int* _value ) const; + /// QueryDoubleValue examines the value string. See QueryIntValue(). + int QueryDoubleValue( double* _value ) const; + + void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute. + void SetValue( const char* _value ) { value = _value; } ///< Set the value. + + void SetIntValue( int _value ); ///< Set the value from an integer. + void SetDoubleValue( double _value ); ///< Set the value from a double. + + #ifdef TIXML_USE_STL + /// STL std::string form. + void SetName( const std::string& _name ) { name = _name; } + /// STL std::string form. + void SetValue( const std::string& _value ) { value = _value; } + #endif + + /// Get the next sibling attribute in the DOM. Returns null at end. + const TiXmlAttribute* Next() const; + TiXmlAttribute* Next() { + return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Next() ); + } + + /// Get the previous sibling attribute in the DOM. Returns null at beginning. + const TiXmlAttribute* Previous() const; + TiXmlAttribute* Previous() { + return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Previous() ); + } + + bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; } + bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; } + bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; } + + /* Attribute parsing starts: first letter of the name + returns: the next char after the value end quote + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + // Prints this Attribute to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const { + Print( cfile, depth, 0 ); + } + void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; + + // [internal use] + // Set the document pointer so the attribute can report errors. + void SetDocument( TiXmlDocument* doc ) { document = doc; } + +private: + TiXmlAttribute( const TiXmlAttribute& ); // not implemented. + void operator=( const TiXmlAttribute& base ); // not allowed. + + TiXmlDocument* document; // A pointer back to a document, for error reporting. + TIXML_STRING name; + TIXML_STRING value; + TiXmlAttribute* prev; + TiXmlAttribute* next; +}; + + +/* A class used to manage a group of attributes. + It is only used internally, both by the ELEMENT and the DECLARATION. + + The set can be changed transparent to the Element and Declaration + classes that use it, but NOT transparent to the Attribute + which has to implement a next() and previous() method. Which makes + it a bit problematic and prevents the use of STL. + + This version is implemented with circular lists because: + - I like circular lists + - it demonstrates some independence from the (typical) doubly linked list. +*/ +class TiXmlAttributeSet +{ +public: + TiXmlAttributeSet(); + ~TiXmlAttributeSet(); + + void Add( TiXmlAttribute* attribute ); + void Remove( TiXmlAttribute* attribute ); + + const TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } + TiXmlAttribute* First() { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } + const TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } + TiXmlAttribute* Last() { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } + + const TiXmlAttribute* Find( const char* _name ) const; + TiXmlAttribute* Find( const char* _name ) { + return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) ); + } + #ifdef TIXML_USE_STL + const TiXmlAttribute* Find( const std::string& _name ) const; + TiXmlAttribute* Find( const std::string& _name ) { + return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) ); + } + + #endif + +private: + //*ME: Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element), + //*ME: this class must be also use a hidden/disabled copy-constructor !!! + TiXmlAttributeSet( const TiXmlAttributeSet& ); // not allowed + void operator=( const TiXmlAttributeSet& ); // not allowed (as TiXmlAttribute) + + TiXmlAttribute sentinel; +}; + + +/** The element is a container class. It has a value, the element name, + and can contain other elements, text, comments, and unknowns. + Elements also contain an arbitrary number of attributes. +*/ +class TiXmlElement : public TiXmlNode +{ +public: + /// Construct an element. + TiXmlElement (const char * in_value); + + #ifdef TIXML_USE_STL + /// std::string constructor. + TiXmlElement( const std::string& _value ); + #endif + + TiXmlElement( const TiXmlElement& ); + + void operator=( const TiXmlElement& base ); + + virtual ~TiXmlElement(); + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none exists. + */ + const char* Attribute( const char* name ) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none exists. + If the attribute exists and can be converted to an integer, + the integer value will be put in the return 'i', if 'i' + is non-null. + */ + const char* Attribute( const char* name, int* i ) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none exists. + If the attribute exists and can be converted to an double, + the double value will be put in the return 'd', if 'd' + is non-null. + */ + const char* Attribute( const char* name, double* d ) const; + + /** QueryIntAttribute examines the attribute - it is an alternative to the + Attribute() method with richer error checking. + If the attribute is an integer, it is stored in 'value' and + the call returns TIXML_SUCCESS. If it is not + an integer, it returns TIXML_WRONG_TYPE. If the attribute + does not exist, then TIXML_NO_ATTRIBUTE is returned. + */ + int QueryIntAttribute( const char* name, int* _value ) const; + /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). + int QueryDoubleAttribute( const char* name, double* _value ) const; + /// QueryFloatAttribute examines the attribute - see QueryIntAttribute(). + int QueryFloatAttribute( const char* name, float* _value ) const { + double d; + int result = QueryDoubleAttribute( name, &d ); + if ( result == TIXML_SUCCESS ) { + *_value = (float)d; + } + return result; + } + + #ifdef TIXML_USE_STL + /** Template form of the attribute query which will try to read the + attribute into the specified type. Very easy, very powerful, but + be careful to make sure to call this with the correct type. + + NOTE: This method doesn't work correctly for 'string' types. + + @return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE + */ + template< typename T > int QueryValueAttribute( const std::string& name, T* outValue ) const + { + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + + std::stringstream sstream( node->ValueStr() ); + sstream >> *outValue; + if ( !sstream.fail() ) + return TIXML_SUCCESS; + return TIXML_WRONG_TYPE; + } + /* + This is - in theory - a bug fix for "QueryValueAtribute returns truncated std::string" + but template specialization is hard to get working cross-compiler. Leaving the bug for now. + + // The above will fail for std::string because the space character is used as a seperator. + // Specialize for strings. Bug [ 1695429 ] QueryValueAtribute returns truncated std::string + template<> int QueryValueAttribute( const std::string& name, std::string* outValue ) const + { + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + *outValue = node->ValueStr(); + return TIXML_SUCCESS; + } + */ + #endif + + /** Sets an attribute of name to a given value. The attribute + will be created if it does not exist, or changed if it does. + */ + void SetAttribute( const char* name, const char * _value ); + + #ifdef TIXML_USE_STL + const std::string* Attribute( const std::string& name ) const; + const std::string* Attribute( const std::string& name, int* i ) const; + const std::string* Attribute( const std::string& name, double* d ) const; + int QueryIntAttribute( const std::string& name, int* _value ) const; + int QueryDoubleAttribute( const std::string& name, double* _value ) const; + + /// STL std::string form. + void SetAttribute( const std::string& name, const std::string& _value ); + ///< STL std::string form. + void SetAttribute( const std::string& name, int _value ); + #endif + + /** Sets an attribute of name to a given value. The attribute + will be created if it does not exist, or changed if it does. + */ + void SetAttribute( const char * name, int value ); + + /** Sets an attribute of name to a given value. The attribute + will be created if it does not exist, or changed if it does. + */ + void SetDoubleAttribute( const char * name, double value ); + + /** Deletes an attribute with the given name. + */ + void RemoveAttribute( const char * name ); + #ifdef TIXML_USE_STL + void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form. + #endif + + const TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element. + TiXmlAttribute* FirstAttribute() { return attributeSet.First(); } + const TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element. + TiXmlAttribute* LastAttribute() { return attributeSet.Last(); } + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, GetText() is limited compared to getting the TiXmlText child + and accessing it directly. + + If the first child of 'this' is a TiXmlText, the GetText() + returns the character string of the Text node, else null is returned. + + This is a convenient method for getting the text of simple contained text: + @verbatim + This is text + const char* str = fooElement->GetText(); + @endverbatim + + 'str' will be a pointer to "This is text". + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + This is text + @endverbatim + + then the value of str would be null. The first child node isn't a text node, it is + another element. From this XML: + @verbatim + This is text + @endverbatim + GetText() will return "This is ". + + WARNING: GetText() accesses a child node - don't become confused with the + similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are + safe type casts on the referenced node. + */ + const char* GetText() const; + + /// Creates a new Element and returns it - the returned element is a copy. + virtual TiXmlNode* Clone() const; + // Print the Element to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + /* Attribtue parsing starts: next char past '<' + returns: next char past '>' + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlElement* ToElement() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlElement* ToElement() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* visitor ) const; + +protected: + + void CopyTo( TiXmlElement* target ) const; + void ClearThis(); // like clear, but initializes 'this' object as well + + // Used to be public [internal use] + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + /* [internal use] + Reads the "value" of the element -- another element, or text. + This should terminate with the current end tag. + */ + const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding ); + +private: + + TiXmlAttributeSet attributeSet; +}; + + +/** An XML comment. +*/ +class TiXmlComment : public TiXmlNode +{ +public: + /// Constructs an empty comment. + TiXmlComment() : TiXmlNode( TiXmlNode::COMMENT ) {} + /// Construct a comment from text. + TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::COMMENT ) { + SetValue( _value ); + } + TiXmlComment( const TiXmlComment& ); + void operator=( const TiXmlComment& base ); + + virtual ~TiXmlComment() {} + + /// Returns a copy of this Comment. + virtual TiXmlNode* Clone() const; + // Write this Comment to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + /* Attribtue parsing starts: at the ! of the !-- + returns: next char past '>' + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlComment* ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlComment* ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* visitor ) const; + +protected: + void CopyTo( TiXmlComment* target ) const; + + // used to be public + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif +// virtual void StreamOut( TIXML_OSTREAM * out ) const; + +private: + +}; + + +/** XML text. A text node can have 2 ways to output the next. "normal" output + and CDATA. It will default to the mode it was parsed from the XML file and + you generally want to leave it alone, but you can change the output mode with + SetCDATA() and query it with CDATA(). +*/ +class TiXmlText : public TiXmlNode +{ + friend class TiXmlElement; +public: + /** Constructor for text element. By default, it is treated as + normal, encoded text. If you want it be output as a CDATA text + element, set the parameter _cdata to 'true' + */ + TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TEXT) + { + SetValue( initValue ); + cdata = false; + } + virtual ~TiXmlText() {} + + #ifdef TIXML_USE_STL + /// Constructor. + TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TEXT) + { + SetValue( initValue ); + cdata = false; + } + #endif + + TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TEXT ) { copy.CopyTo( this ); } + void operator=( const TiXmlText& base ) { base.CopyTo( this ); } + + // Write this text object to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + /// Queries whether this represents text using a CDATA section. + bool CDATA() const { return cdata; } + /// Turns on or off a CDATA representation of text. + void SetCDATA( bool _cdata ) { cdata = _cdata; } + + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlText* ToText() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlText* ToText() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* content ) const; + +protected : + /// [internal use] Creates a new Element and returns it. + virtual TiXmlNode* Clone() const; + void CopyTo( TiXmlText* target ) const; + + bool Blank() const; // returns true if all white space and new lines + // [internal use] + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + +private: + bool cdata; // true if this should be input and output as a CDATA style text element +}; + + +/** In correct XML the declaration is the first entry in the file. + @verbatim + + @endverbatim + + TinyXml will happily read or write files without a declaration, + however. There are 3 possible attributes to the declaration: + version, encoding, and standalone. + + Note: In this version of the code, the attributes are + handled as special cases, not generic attributes, simply + because there can only be at most 3 and they are always the same. +*/ +class TiXmlDeclaration : public TiXmlNode +{ +public: + /// Construct an empty declaration. + TiXmlDeclaration() : TiXmlNode( TiXmlNode::DECLARATION ) {} + +#ifdef TIXML_USE_STL + /// Constructor. + TiXmlDeclaration( const std::string& _version, + const std::string& _encoding, + const std::string& _standalone ); +#endif + + /// Construct. + TiXmlDeclaration( const char* _version, + const char* _encoding, + const char* _standalone ); + + TiXmlDeclaration( const TiXmlDeclaration& copy ); + void operator=( const TiXmlDeclaration& copy ); + + virtual ~TiXmlDeclaration() {} + + /// Version. Will return an empty string if none was found. + const char *Version() const { return version.c_str (); } + /// Encoding. Will return an empty string if none was found. + const char *Encoding() const { return encoding.c_str (); } + /// Is this a standalone document? + const char *Standalone() const { return standalone.c_str (); } + + /// Creates a copy of this Declaration and returns it. + virtual TiXmlNode* Clone() const; + // Print this declaration to a FILE stream. + virtual void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; + virtual void Print( FILE* cfile, int depth ) const { + Print( cfile, depth, 0 ); + } + + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlDeclaration* ToDeclaration() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlDeclaration* ToDeclaration() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* visitor ) const; + +protected: + void CopyTo( TiXmlDeclaration* target ) const; + // used to be public + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + +private: + + TIXML_STRING version; + TIXML_STRING encoding; + TIXML_STRING standalone; +}; + + +/** Any tag that tinyXml doesn't recognize is saved as an + unknown. It is a tag of text, but should not be modified. + It will be written back to the XML, unchanged, when the file + is saved. + + DTD tags get thrown into TiXmlUnknowns. +*/ +class TiXmlUnknown : public TiXmlNode +{ +public: + TiXmlUnknown() : TiXmlNode( TiXmlNode::UNKNOWN ) {} + virtual ~TiXmlUnknown() {} + + TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::UNKNOWN ) { copy.CopyTo( this ); } + void operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); } + + /// Creates a copy of this Unknown and returns it. + virtual TiXmlNode* Clone() const; + // Print this Unknown to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlUnknown* ToUnknown() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlUnknown* ToUnknown() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* content ) const; + +protected: + void CopyTo( TiXmlUnknown* target ) const; + + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + +private: + +}; + + +/** Always the top level node. A document binds together all the + XML pieces. It can be saved, loaded, and printed to the screen. + The 'value' of a document node is the xml file name. +*/ +class TiXmlDocument : public TiXmlNode +{ +public: + /// Create an empty document, that has no name. + TiXmlDocument(); + /// Create a document with a name. The name of the document is also the filename of the xml. + TiXmlDocument( const char * documentName ); + + #ifdef TIXML_USE_STL + /// Constructor. + TiXmlDocument( const std::string& documentName ); + #endif + + TiXmlDocument( const TiXmlDocument& copy ); + void operator=( const TiXmlDocument& copy ); + + virtual ~TiXmlDocument() {} + + /** Load a file using the current document value. + Returns true if successful. Will delete any existing + document data before loading. + */ + bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + /// Save a file using the current document value. Returns true if successful. + bool SaveFile() const; + /// Load a file using the given filename. Returns true if successful. + bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + /// Save a file using the given filename. Returns true if successful. + bool SaveFile( const char * filename ) const; + /** Load a file using the given FILE*. Returns true if successful. Note that this method + doesn't stream - the entire object pointed at by the FILE* + will be interpreted as an XML file. TinyXML doesn't stream in XML from the current + file location. Streaming may be added in the future. + */ + bool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + /// Save a file using the given FILE*. Returns true if successful. + bool SaveFile( FILE* ) const; + + #ifdef TIXML_USE_STL + bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version. + { +// StringToBuffer f( filename ); +// return ( f.buffer && LoadFile( f.buffer, encoding )); + return LoadFile( filename.c_str(), encoding ); + } + bool SaveFile( const std::string& filename ) const ///< STL std::string version. + { +// StringToBuffer f( filename ); +// return ( f.buffer && SaveFile( f.buffer )); + return SaveFile( filename.c_str() ); + } + #endif + + /** Parse the given null terminated block of xml data. Passing in an encoding to this + method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml + to use that encoding, regardless of what TinyXml might otherwise try to detect. + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + + /** Get the root element -- the only top level element -- of the document. + In well formed XML, there should only be one. TinyXml is tolerant of + multiple elements at the document level. + */ + const TiXmlElement* RootElement() const { return FirstChildElement(); } + TiXmlElement* RootElement() { return FirstChildElement(); } + + /** If an error occurs, Error will be set to true. Also, + - The ErrorId() will contain the integer identifier of the error (not generally useful) + - The ErrorDesc() method will return the name of the error. (very useful) + - The ErrorRow() and ErrorCol() will return the location of the error (if known) + */ + bool Error() const { return error; } + + /// Contains a textual (english) description of the error if one occurs. + const char * ErrorDesc() const { return errorDesc.c_str (); } + + /** Generally, you probably want the error string ( ErrorDesc() ). But if you + prefer the ErrorId, this function will fetch it. + */ + int ErrorId() const { return errorId; } + + /** Returns the location (if known) of the error. The first column is column 1, + and the first row is row 1. A value of 0 means the row and column wasn't applicable + (memory errors, for example, have no row/column) or the parser lost the error. (An + error in the error reporting, in that case.) + + @sa SetTabSize, Row, Column + */ + int ErrorRow() const { return errorLocation.row+1; } + int ErrorCol() const { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow() + + /** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol()) + to report the correct values for row and column. It does not change the output + or input in any way. + + By calling this method, with a tab size + greater than 0, the row and column of each node and attribute is stored + when the file is loaded. Very useful for tracking the DOM back in to + the source file. + + The tab size is required for calculating the location of nodes. If not + set, the default of 4 is used. The tabsize is set per document. Setting + the tabsize to 0 disables row/column tracking. + + Note that row and column tracking is not supported when using operator>>. + + The tab size needs to be enabled before the parse or load. Correct usage: + @verbatim + TiXmlDocument doc; + doc.SetTabSize( 8 ); + doc.Load( "myfile.xml" ); + @endverbatim + + @sa Row, Column + */ + void SetTabSize( int _tabsize ) { tabsize = _tabsize; } + + int TabSize() const { return tabsize; } + + /** If you have handled the error, it can be reset with this call. The error + state is automatically cleared if you Parse a new XML block. + */ + void ClearError() { error = false; + errorId = 0; + errorDesc = ""; + errorLocation.row = errorLocation.col = 0; + //errorLocation.last = 0; + } + + /** Write the document to standard out using formatted printing ("pretty print"). */ + void Print() const { Print( stdout, 0 ); } + + /* Write the document to a string using formatted printing ("pretty print"). This + will allocate a character array (new char[]) and return it as a pointer. The + calling code pust call delete[] on the return char* to avoid a memory leak. + */ + //char* PrintToMemory() const; + + /// Print this Document to a FILE stream. + virtual void Print( FILE* cfile, int depth = 0 ) const; + // [internal use] + void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding ); + + virtual const TiXmlDocument* ToDocument() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlDocument* ToDocument() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* content ) const; + +protected : + // [internal use] + virtual TiXmlNode* Clone() const; + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + +private: + void CopyTo( TiXmlDocument* target ) const; + + bool error; + int errorId; + TIXML_STRING errorDesc; + int tabsize; + TiXmlCursor errorLocation; + bool useMicrosoftBOM; // the UTF-8 BOM were found when read. Note this, and try to write. +}; + + +/** + A TiXmlHandle is a class that wraps a node pointer with null checks; this is + an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml + DOM structure. It is a separate utility class. + + Take an example: + @verbatim + + + + + + + @endverbatim + + Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very + easy to write a *lot* of code that looks like: + + @verbatim + TiXmlElement* root = document.FirstChildElement( "Document" ); + if ( root ) + { + TiXmlElement* element = root->FirstChildElement( "Element" ); + if ( element ) + { + TiXmlElement* child = element->FirstChildElement( "Child" ); + if ( child ) + { + TiXmlElement* child2 = child->NextSiblingElement( "Child" ); + if ( child2 ) + { + // Finally do something useful. + @endverbatim + + And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity + of such code. A TiXmlHandle checks for null pointers so it is perfectly safe + and correct to use: + + @verbatim + TiXmlHandle docHandle( &document ); + TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement(); + if ( child2 ) + { + // do something useful + @endverbatim + + Which is MUCH more concise and useful. + + It is also safe to copy handles - internally they are nothing more than node pointers. + @verbatim + TiXmlHandle handleCopy = handle; + @endverbatim + + What they should not be used for is iteration: + + @verbatim + int i=0; + while ( true ) + { + TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).ToElement(); + if ( !child ) + break; + // do something + ++i; + } + @endverbatim + + It seems reasonable, but it is in fact two embedded while loops. The Child method is + a linear walk to find the element, so this code would iterate much more than it needs + to. Instead, prefer: + + @verbatim + TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).ToElement(); + + for( child; child; child=child->NextSiblingElement() ) + { + // do something + } + @endverbatim +*/ +class TiXmlHandle +{ +public: + /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. + TiXmlHandle( TiXmlNode* _node ) { this->node = _node; } + /// Copy constructor + TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; } + TiXmlHandle operator=( const TiXmlHandle& ref ) { this->node = ref.node; return *this; } + + /// Return a handle to the first child node. + TiXmlHandle FirstChild() const; + /// Return a handle to the first child node with the given name. + TiXmlHandle FirstChild( const char * value ) const; + /// Return a handle to the first child element. + TiXmlHandle FirstChildElement() const; + /// Return a handle to the first child element with the given name. + TiXmlHandle FirstChildElement( const char * value ) const; + + /** Return a handle to the "index" child with the given name. + The first child is 0, the second 1, etc. + */ + TiXmlHandle Child( const char* value, int index ) const; + /** Return a handle to the "index" child. + The first child is 0, the second 1, etc. + */ + TiXmlHandle Child( int index ) const; + /** Return a handle to the "index" child element with the given name. + The first child element is 0, the second 1, etc. Note that only TiXmlElements + are indexed: other types are not counted. + */ + TiXmlHandle ChildElement( const char* value, int index ) const; + /** Return a handle to the "index" child element. + The first child element is 0, the second 1, etc. Note that only TiXmlElements + are indexed: other types are not counted. + */ + TiXmlHandle ChildElement( int index ) const; + + #ifdef TIXML_USE_STL + TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); } + TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); } + + TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); } + TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); } + #endif + + /** Return the handle as a TiXmlNode. This may return null. + */ + TiXmlNode* ToNode() const { return node; } + /** Return the handle as a TiXmlElement. This may return null. + */ + TiXmlElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); } + /** Return the handle as a TiXmlText. This may return null. + */ + TiXmlText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); } + /** Return the handle as a TiXmlUnknown. This may return null. + */ + TiXmlUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); } + + /** @deprecated use ToNode. + Return the handle as a TiXmlNode. This may return null. + */ + TiXmlNode* Node() const { return ToNode(); } + /** @deprecated use ToElement. + Return the handle as a TiXmlElement. This may return null. + */ + TiXmlElement* Element() const { return ToElement(); } + /** @deprecated use ToText() + Return the handle as a TiXmlText. This may return null. + */ + TiXmlText* Text() const { return ToText(); } + /** @deprecated use ToUnknown() + Return the handle as a TiXmlUnknown. This may return null. + */ + TiXmlUnknown* Unknown() const { return ToUnknown(); } + +private: + TiXmlNode* node; +}; + + +/** Print to memory functionality. The TiXmlPrinter is useful when you need to: + + -# Print to memory (especially in non-STL mode) + -# Control formatting (line endings, etc.) + + When constructed, the TiXmlPrinter is in its default "pretty printing" mode. + Before calling Accept() you can call methods to control the printing + of the XML document. After TiXmlNode::Accept() is called, the printed document can + be accessed via the CStr(), Str(), and Size() methods. + + TiXmlPrinter uses the Visitor API. + @verbatim + TiXmlPrinter printer; + printer.SetIndent( "\t" ); + + doc.Accept( &printer ); + fprintf( stdout, "%s", printer.CStr() ); + @endverbatim +*/ +class TiXmlPrinter : public TiXmlVisitor +{ +public: + TiXmlPrinter() : depth( 0 ), simpleTextPrint( false ), + buffer(), indent( " " ), lineBreak( "\n" ) {} + + virtual bool VisitEnter( const TiXmlDocument& doc ); + virtual bool VisitExit( const TiXmlDocument& doc ); + + virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ); + virtual bool VisitExit( const TiXmlElement& element ); + + virtual bool Visit( const TiXmlDeclaration& declaration ); + virtual bool Visit( const TiXmlText& text ); + virtual bool Visit( const TiXmlComment& comment ); + virtual bool Visit( const TiXmlUnknown& unknown ); + + /** Set the indent characters for printing. By default 4 spaces + but tab (\t) is also useful, or null/empty string for no indentation. + */ + void SetIndent( const char* _indent ) { indent = _indent ? _indent : "" ; } + /// Query the indention string. + const char* Indent() { return indent.c_str(); } + /** Set the line breaking string. By default set to newline (\n). + Some operating systems prefer other characters, or can be + set to the null/empty string for no indenation. + */ + void SetLineBreak( const char* _lineBreak ) { lineBreak = _lineBreak ? _lineBreak : ""; } + /// Query the current line breaking string. + const char* LineBreak() { return lineBreak.c_str(); } + + /** Switch over to "stream printing" which is the most dense formatting without + linebreaks. Common when the XML is needed for network transmission. + */ + void SetStreamPrinting() { indent = ""; + lineBreak = ""; + } + /// Return the result. + const char* CStr() { return buffer.c_str(); } + /// Return the length of the result string. + size_t Size() { return buffer.size(); } + + #ifdef TIXML_USE_STL + /// Return the result. + const std::string& Str() { return buffer; } + #endif + +private: + void DoIndent() { + for( int i=0; i +#include + +#include "tinyxml.h" + +//#define DEBUG_PARSER +#if defined( DEBUG_PARSER ) +# if defined( DEBUG ) && defined( _MSC_VER ) +# include +# define TIXML_LOG OutputDebugString +# else +# define TIXML_LOG printf +# endif +#endif + +// Note tha "PutString" hardcodes the same list. This +// is less flexible than it appears. Changing the entries +// or order will break putstring. +TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] = +{ + { "&", 5, '&' }, + { "<", 4, '<' }, + { ">", 4, '>' }, + { """, 6, '\"' }, + { "'", 6, '\'' } +}; + +// Bunch of unicode info at: +// http://www.unicode.org/faq/utf_bom.html +// Including the basic of this table, which determines the #bytes in the +// sequence from the lead byte. 1 placed for invalid sequences -- +// although the result will be junk, pass it through as much as possible. +// Beware of the non-characters in UTF-8: +// ef bb bf (Microsoft "lead bytes") +// ef bf be +// ef bf bf + +const unsigned char TIXML_UTF_LEAD_0 = 0xefU; +const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; +const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; + +const int TiXmlBase::utf8ByteTable[256] = +{ + // 0 1 2 3 4 5 6 7 8 9 a b c d e f + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 + 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte + 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid +}; + + +void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) +{ + const unsigned long BYTE_MASK = 0xBF; + const unsigned long BYTE_MARK = 0x80; + const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + + if (input < 0x80) + *length = 1; + else if ( input < 0x800 ) + *length = 2; + else if ( input < 0x10000 ) + *length = 3; + else if ( input < 0x200000 ) + *length = 4; + else + { *length = 0; return; } // This code won't covert this correctly anyway. + + output += *length; + + // Scary scary fall throughs. + switch (*length) + { + case 4: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 3: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 2: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 1: + --output; + *output = (char)(input | FIRST_BYTE_MARK[*length]); + } +} + + +/*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) +{ + // This will only work for low-ascii, everything else is assumed to be a valid + // letter. I'm not sure this is the best approach, but it is quite tricky trying + // to figure out alhabetical vs. not across encoding. So take a very + // conservative approach. + +// if ( encoding == TIXML_ENCODING_UTF8 ) +// { + if ( anyByte < 127 ) + return isalpha( anyByte ); + else + return 1; // What else to do? The unicode set is huge...get the english ones right. +// } +// else +// { +// return isalpha( anyByte ); +// } +} + + +/*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) +{ + // This will only work for low-ascii, everything else is assumed to be a valid + // letter. I'm not sure this is the best approach, but it is quite tricky trying + // to figure out alhabetical vs. not across encoding. So take a very + // conservative approach. + +// if ( encoding == TIXML_ENCODING_UTF8 ) +// { + if ( anyByte < 127 ) + return isalnum( anyByte ); + else + return 1; // What else to do? The unicode set is huge...get the english ones right. +// } +// else +// { +// return isalnum( anyByte ); +// } +} + + +class TiXmlParsingData +{ + friend class TiXmlDocument; + public: + void Stamp( const char* now, TiXmlEncoding encoding ); + + const TiXmlCursor& Cursor() { return cursor; } + + private: + // Only used by the document! + TiXmlParsingData( const char* start, int _tabsize, int row, int col ) + { + assert( start ); + stamp = start; + tabsize = _tabsize; + cursor.row = row; + cursor.col = col; + } + + TiXmlCursor cursor; + const char* stamp; + int tabsize; +}; + + +void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) +{ + assert( now ); + + // Do nothing if the tabsize is 0. + if ( tabsize < 1 ) + { + return; + } + + // Get the current row, column. + int row = cursor.row; + int col = cursor.col; + const char* p = stamp; + assert( p ); + + while ( p < now ) + { + // Treat p as unsigned, so we have a happy compiler. + const unsigned char* pU = (const unsigned char*)p; + + // Code contributed by Fletcher Dunn: (modified by lee) + switch (*pU) { + case 0: + // We *should* never get here, but in case we do, don't + // advance past the terminating null character, ever + return; + + case '\r': + // bump down to the next line + ++row; + col = 0; + // Eat the character + ++p; + + // Check for \r\n sequence, and treat this as a single character + if (*p == '\n') { + ++p; + } + break; + + case '\n': + // bump down to the next line + ++row; + col = 0; + + // Eat the character + ++p; + + // Check for \n\r sequence, and treat this as a single + // character. (Yes, this bizarre thing does occur still + // on some arcane platforms...) + if (*p == '\r') { + ++p; + } + break; + + case '\t': + // Eat the character + ++p; + + // Skip to next tab stop + col = (col / tabsize + 1) * tabsize; + break; + + case TIXML_UTF_LEAD_0: + if ( encoding == TIXML_ENCODING_UTF8 ) + { + if ( *(p+1) && *(p+2) ) + { + // In these cases, don't advance the column. These are + // 0-width spaces. + if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) + p += 3; + else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU ) + p += 3; + else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU ) + p += 3; + else + { p +=3; ++col; } // A normal character. + } + } + else + { + ++p; + ++col; + } + break; + + default: + if ( encoding == TIXML_ENCODING_UTF8 ) + { + // Eat the 1 to 4 byte utf8 character. + int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)]; + if ( step == 0 ) + step = 1; // Error case from bad encoding, but handle gracefully. + p += step; + + // Just advance one column, of course. + ++col; + } + else + { + ++p; + ++col; + } + break; + } + } + cursor.row = row; + cursor.col = col; + assert( cursor.row >= -1 ); + assert( cursor.col >= -1 ); + stamp = p; + assert( stamp ); +} + + +const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) +{ + if ( !p || !*p ) + { + return 0; + } + if ( encoding == TIXML_ENCODING_UTF8 ) + { + while ( *p ) + { + const unsigned char* pU = (const unsigned char*)p; + + // Skip the stupid Microsoft UTF-8 Byte order marks + if ( *(pU+0)==TIXML_UTF_LEAD_0 + && *(pU+1)==TIXML_UTF_LEAD_1 + && *(pU+2)==TIXML_UTF_LEAD_2 ) + { + p += 3; + continue; + } + else if(*(pU+0)==TIXML_UTF_LEAD_0 + && *(pU+1)==0xbfU + && *(pU+2)==0xbeU ) + { + p += 3; + continue; + } + else if(*(pU+0)==TIXML_UTF_LEAD_0 + && *(pU+1)==0xbfU + && *(pU+2)==0xbfU ) + { + p += 3; + continue; + } + + if ( IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) // Still using old rules for white space. + ++p; + else + break; + } + } + else + { + while ( *p && IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) + ++p; + } + + return p; +} + +#ifdef TIXML_USE_STL +/*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ) +{ + for( ;; ) + { + if ( !in->good() ) return false; + + int c = in->peek(); + // At this scope, we can't get to a document. So fail silently. + if ( !IsWhiteSpace( c ) || c <= 0 ) + return true; + + *tag += (char) in->get(); + } +} + +/*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag ) +{ + //assert( character > 0 && character < 128 ); // else it won't work in utf-8 + while ( in->good() ) + { + int c = in->peek(); + if ( c == character ) + return true; + if ( c <= 0 ) // Silent failure: can't get document at this scope + return false; + + in->get(); + *tag += (char) c; + } + return false; +} +#endif + +// One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The +// "assign" optimization removes over 10% of the execution time. +// +const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding ) +{ + // Oddly, not supported on some comilers, + //name->clear(); + // So use this: + *name = ""; + assert( p ); + + // Names start with letters or underscores. + // Of course, in unicode, tinyxml has no idea what a letter *is*. The + // algorithm is generous. + // + // After that, they can be letters, underscores, numbers, + // hyphens, or colons. (Colons are valid ony for namespaces, + // but tinyxml can't tell namespaces from names.) + if ( p && *p + && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) + { + const char* start = p; + while( p && *p + && ( IsAlphaNum( (unsigned char ) *p, encoding ) + || *p == '_' + || *p == '-' + || *p == '.' + || *p == ':' ) ) + { + //(*name) += *p; // expensive + ++p; + } + if ( p-start > 0 ) { + name->assign( start, p-start ); + } + return p; + } + return 0; +} + +const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding ) +{ + // Presume an entity, and pull it out. + TIXML_STRING ent; + int i; + *length = 0; + + if ( *(p+1) && *(p+1) == '#' && *(p+2) ) + { + unsigned long ucs = 0; + ptrdiff_t delta = 0; + unsigned mult = 1; + + if ( *(p+2) == 'x' ) + { + // Hexadecimal. + if ( !*(p+3) ) return 0; + + const char* q = p+3; + q = strchr( q, ';' ); + + if ( !q || !*q ) return 0; + + delta = q-p; + --q; + + while ( *q != 'x' ) + { + if ( *q >= '0' && *q <= '9' ) + ucs += mult * (*q - '0'); + else if ( *q >= 'a' && *q <= 'f' ) + ucs += mult * (*q - 'a' + 10); + else if ( *q >= 'A' && *q <= 'F' ) + ucs += mult * (*q - 'A' + 10 ); + else + return 0; + mult *= 16; + --q; + } + } + else + { + // Decimal. + if ( !*(p+2) ) return 0; + + const char* q = p+2; + q = strchr( q, ';' ); + + if ( !q || !*q ) return 0; + + delta = q-p; + --q; + + while ( *q != '#' ) + { + if ( *q >= '0' && *q <= '9' ) + ucs += mult * (*q - '0'); + else + return 0; + mult *= 10; + --q; + } + } + if ( encoding == TIXML_ENCODING_UTF8 ) + { + // convert the UCS to UTF-8 + ConvertUTF32ToUTF8( ucs, value, length ); + } + else + { + *value = (char)ucs; + *length = 1; + } + return p + delta + 1; + } + + // Now try to match it. + for( i=0; iappend( cArr, len ); + } + } + else + { + bool whitespace = false; + + // Remove leading white space: + p = SkipWhiteSpace( p, encoding ); + while ( p && *p + && !StringEqual( p, endTag, caseInsensitive, encoding ) ) + { + if ( *p == '\r' || *p == '\n' ) + { + whitespace = true; + ++p; + } + else if ( IsWhiteSpace( *p ) ) + { + whitespace = true; + ++p; + } + else + { + // If we've found whitespace, add it before the + // new character. Any whitespace just becomes a space. + if ( whitespace ) + { + (*text) += ' '; + whitespace = false; + } + int len; + char cArr[4] = { 0, 0, 0, 0 }; + p = GetChar( p, cArr, &len, encoding ); + if ( len == 1 ) + (*text) += cArr[0]; // more efficient + else + text->append( cArr, len ); + } + } + } + if ( p ) + p += strlen( endTag ); + return p; +} + +#ifdef TIXML_USE_STL + +void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag ) +{ + // The basic issue with a document is that we don't know what we're + // streaming. Read something presumed to be a tag (and hope), then + // identify it, and call the appropriate stream method on the tag. + // + // This "pre-streaming" will never read the closing ">" so the + // sub-tag can orient itself. + + if ( !StreamTo( in, '<', tag ) ) + { + SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + + while ( in->good() ) + { + int tagIndex = (int) tag->length(); + while ( in->good() && in->peek() != '>' ) + { + int c = in->get(); + if ( c <= 0 ) + { + SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + break; + } + (*tag) += (char) c; + } + + if ( in->good() ) + { + // We now have something we presume to be a node of + // some sort. Identify it, and call the node to + // continue streaming. + TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); + + if ( node ) + { + node->StreamIn( in, tag ); + bool isElement = node->ToElement() != 0; + delete node; + node = 0; + + // If this is the root element, we're done. Parsing will be + // done by the >> operator. + if ( isElement ) + { + return; + } + } + else + { + SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + } + } + // We should have returned sooner. + SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); +} + +#endif + +const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding ) +{ + ClearError(); + + // Parse away, at the document level. Since a document + // contains nothing but other tags, most of what happens + // here is skipping white space. + if ( !p || !*p ) + { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + // Note that, for a document, this needs to come + // before the while space skip, so that parsing + // starts from the pointer we are given. + location.Clear(); + if ( prevData ) + { + location.row = prevData->cursor.row; + location.col = prevData->cursor.col; + } + else + { + location.row = 0; + location.col = 0; + } + TiXmlParsingData data( p, TabSize(), location.row, location.col ); + location = data.Cursor(); + + if ( encoding == TIXML_ENCODING_UNKNOWN ) + { + // Check for the Microsoft UTF-8 lead bytes. + const unsigned char* pU = (const unsigned char*)p; + if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0 + && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1 + && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 ) + { + encoding = TIXML_ENCODING_UTF8; + useMicrosoftBOM = true; + } + } + + p = SkipWhiteSpace( p, encoding ); + if ( !p ) + { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + while ( p && *p ) + { + TiXmlNode* node = Identify( p, encoding ); + if ( node ) + { + p = node->Parse( p, &data, encoding ); + LinkEndChild( node ); + } + else + { + break; + } + + // Did we get encoding info? + if ( encoding == TIXML_ENCODING_UNKNOWN + && node->ToDeclaration() ) + { + TiXmlDeclaration* dec = node->ToDeclaration(); + const char* enc = dec->Encoding(); + assert( enc ); + + if ( *enc == 0 ) + encoding = TIXML_ENCODING_UTF8; + else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) ) + encoding = TIXML_ENCODING_UTF8; + else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) + encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice + else + encoding = TIXML_ENCODING_LEGACY; + } + + p = SkipWhiteSpace( p, encoding ); + } + + // Was this empty? + if ( !firstChild ) { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding ); + return 0; + } + + // All is well. + return p; +} + +void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + // The first error in a chain is more accurate - don't set again! + if ( error ) + return; + + assert( err > 0 && err < TIXML_ERROR_STRING_COUNT ); + error = true; + errorId = err; + errorDesc = errorString[ errorId ]; + + errorLocation.Clear(); + if ( pError && data ) + { + data->Stamp( pError, encoding ); + errorLocation = data->Cursor(); + } +} + + +TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) +{ + TiXmlNode* returnNode = 0; + + p = SkipWhiteSpace( p, encoding ); + if( !p || !*p || *p != '<' ) + { + return 0; + } + + TiXmlDocument* doc = GetDocument(); + p = SkipWhiteSpace( p, encoding ); + + if ( !p || !*p ) + { + return 0; + } + + // What is this thing? + // - Elements start with a letter or underscore, but xml is reserved. + // - Comments: "; + + if ( !StringEqual( p, startTag, false, encoding ) ) + { + document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); + return 0; + } + p += strlen( startTag ); + + // [ 1475201 ] TinyXML parses entities in comments + // Oops - ReadText doesn't work, because we don't want to parse the entities. + // p = ReadText( p, &value, false, endTag, false, encoding ); + // + // from the XML spec: + /* + [Definition: Comments may appear anywhere in a document outside other markup; in addition, + they may appear within the document type declaration at places allowed by the grammar. + They are not part of the document's character data; an XML processor MAY, but need not, + make it possible for an application to retrieve the text of comments. For compatibility, + the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity + references MUST NOT be recognized within comments. + + An example of a comment: + + + */ + + value = ""; + // Keep all the white space. + while ( p && *p && !StringEqual( p, endTag, false, encoding ) ) + { + value.append( p, 1 ); + ++p; + } + if ( p ) + p += strlen( endTag ); + + return p; +} + + +const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p ) return 0; + +// int tabsize = 4; +// if ( document ) +// tabsize = document->TabSize(); + + if ( data ) + { + data->Stamp( p, encoding ); + location = data->Cursor(); + } + // Read the name, the '=' and the value. + const char* pErr = p; + p = ReadName( p, &name, encoding ); + if ( !p || !*p ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); + return 0; + } + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p || *p != '=' ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); + return 0; + } + + ++p; // skip '=' + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); + return 0; + } + + const char* end; + const char SINGLE_QUOTE = '\''; + const char DOUBLE_QUOTE = '\"'; + + if ( *p == SINGLE_QUOTE ) + { + ++p; + end = "\'"; // single quote in string + p = ReadText( p, &value, false, end, false, encoding ); + } + else if ( *p == DOUBLE_QUOTE ) + { + ++p; + end = "\""; // double quote in string + p = ReadText( p, &value, false, end, false, encoding ); + } + else + { + // All attribute values should be in single or double quotes. + // But this is such a common error that the parser will try + // its best, even without them. + value = ""; + while ( p && *p // existence + && !IsWhiteSpace( *p ) && *p != '\n' && *p != '\r' // whitespace + && *p != '/' && *p != '>' ) // tag end + { + if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) { + // [ 1451649 ] Attribute values with trailing quotes not handled correctly + // We did not have an opening quote but seem to have a + // closing one. Give up and throw an error. + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); + return 0; + } + value += *p; + ++p; + } + } + return p; +} + +#ifdef TIXML_USE_STL +void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag ) +{ + while ( in->good() ) + { + int c = in->peek(); + if ( !cdata && (c == '<' ) ) + { + return; + } + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + + (*tag) += (char) c; + in->get(); // "commits" the peek made above + + if ( cdata && c == '>' && tag->size() >= 3 ) { + size_t len = tag->size(); + if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) { + // terminator of cdata. + return; + } + } + } +} +#endif + +const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + value = ""; + TiXmlDocument* document = GetDocument(); + + if ( data ) + { + data->Stamp( p, encoding ); + location = data->Cursor(); + } + + const char* const startTag = ""; + + if ( cdata || StringEqual( p, startTag, false, encoding ) ) + { + cdata = true; + + if ( !StringEqual( p, startTag, false, encoding ) ) + { + document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding ); + return 0; + } + p += strlen( startTag ); + + // Keep all the white space, ignore the encoding, etc. + while ( p && *p + && !StringEqual( p, endTag, false, encoding ) + ) + { + value += *p; + ++p; + } + + TIXML_STRING dummy; + p = ReadText( p, &dummy, false, endTag, false, encoding ); + return p; + } + else + { + bool ignoreWhite = true; + + const char* end = "<"; + p = ReadText( p, &value, ignoreWhite, end, false, encoding ); + if ( p ) + return p-1; // don't truncate the '<' + return 0; + } +} + +#ifdef TIXML_USE_STL +void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag ) +{ + while ( in->good() ) + { + int c = in->get(); + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + (*tag) += (char) c; + + if ( c == '>' ) + { + // All is well. + return; + } + } +} +#endif + +const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding ) +{ + p = SkipWhiteSpace( p, _encoding ); + // Find the beginning, find the end, and look for + // the stuff in-between. + TiXmlDocument* document = GetDocument(); + if ( !p || !*p || !StringEqual( p, "SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); + return 0; + } + if ( data ) + { + data->Stamp( p, _encoding ); + location = data->Cursor(); + } + p += 5; + + version = ""; + encoding = ""; + standalone = ""; + + while ( p && *p ) + { + if ( *p == '>' ) + { + ++p; + return p; + } + + p = SkipWhiteSpace( p, _encoding ); + if ( StringEqual( p, "version", true, _encoding ) ) + { + TiXmlAttribute attrib; + p = attrib.Parse( p, data, _encoding ); + version = attrib.Value(); + } + else if ( StringEqual( p, "encoding", true, _encoding ) ) + { + TiXmlAttribute attrib; + p = attrib.Parse( p, data, _encoding ); + encoding = attrib.Value(); + } + else if ( StringEqual( p, "standalone", true, _encoding ) ) + { + TiXmlAttribute attrib; + p = attrib.Parse( p, data, _encoding ); + standalone = attrib.Value(); + } + else + { + // Read over whatever it is. + while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) + ++p; + } + } + return 0; +} + +bool TiXmlText::Blank() const +{ + for ( unsigned i=0; i + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/mangle/.gitignore b/libs/mangle/.gitignore deleted file mode 100644 index cd24d7897..000000000 --- a/libs/mangle/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -upload_docs.sh -docs -*~ diff --git a/libs/mangle/Doxyfile b/libs/mangle/Doxyfile deleted file mode 100644 index f3e018002..000000000 --- a/libs/mangle/Doxyfile +++ /dev/null @@ -1,1510 +0,0 @@ -# Doxyfile 1.5.8 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. - -PROJECT_NAME = Mangle - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = 1 - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, -# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, -# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, -# Spanish, Swedish, and Ukrainian. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = YES - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) - -JAVADOC_AUTOBRIEF = NO - -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 8 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for -# Java. For instance, namespaces will be presented as packages, qualified -# scopes will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources only. Doxygen will then generate output that is more tailored for -# Fortran. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for -# VHDL. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Doxygen selects the parser to use depending on the extension of the files it parses. -# With this tag you can assign which parser to use for a given extension. -# Doxygen has a built-in mapping, but you can override or extend it using this tag. -# The format is ext=language, where ext is a file extension, and language is one of -# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, -# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat -# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), -# use: inc=Fortran f=C - -EXTENSION_MAPPING = - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = YES - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public -# instead of private inheritance when no explicit protection keyword is present. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate getter -# and setter methods for a property. Setting this option to YES (the default) -# will make doxygen to replace the get and set methods by a property in the -# documentation. This will only work if the methods are indeed getting or -# setting a simple type. If this is not the case, or you want to show the -# methods anyway, you should set this option to NO. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -# is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. - -TYPEDEF_HIDES_STRUCT = NO - -# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to -# determine which symbols to keep in memory and which to flush to disk. -# When the cache is full, less often used symbols will be written to disk. -# For small to medium size projects (<1000 input files) the default value is -# probably good enough. For larger projects a too small cache size can cause -# doxygen to be busy swapping symbols to and from disk most of the time -# causing a significant performance penality. -# If the system has enough physical memory increasing the cache will improve the -# performance by keeping more symbols in memory. Note that the value works on -# a logarithmic scale so increasing the size by one will rougly double the -# memory usage. The cache size is given by this formula: -# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols - -SYMBOL_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = NO - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = NO - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base -# name of the file that contains the anonymous namespace. By default -# anonymous namespace are hidden. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = YES - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -# hierarchy of group names into alphabetical order. If set to NO (the default) -# the group names will appear in their defined order. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is NO. - -SHOW_DIRECTORIES = NO - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. -# This will remove the Files entry from the Quick Index and from the -# Folder Tree View (if specified). The default is YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the -# Namespaces page. -# This will remove the Namespaces entry from the Quick Index -# and from the Folder Tree View (if specified). The default is YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by -# doxygen. The layout file controls the global structure of the generated output files -# in an output format independent way. The create the layout file that represents -# doxygen's defaults, run doxygen with the -l option. You can optionally specify a -# file name after the option, if omitted DoxygenLayout.xml will be used as the name -# of the layout file. - -LAYOUT_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = sound stream vfs input - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -# also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for -# the list of possible encodings. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 - -FILE_PATTERNS = *.h - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = YES - -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = */tests/* - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. -# If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. -# Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. -# The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. - -SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = NO - -# If the REFERENCES_RELATION tag is set to YES -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = NO - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. -# Otherwise they will link to the documentation. - -REFERENCES_LINK_SOURCE = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = NO - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = docs - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! - -HTML_STYLESHEET = - -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - -HTML_ALIGN_MEMBERS = YES - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). - -HTML_DYNAMIC_SECTIONS = NO - -# If the GENERATE_DOCSET tag is set to YES, additional index files -# will be generated that can be used as input for Apple's Xcode 3 -# integrated development environment, introduced with OSX 10.5 (Leopard). -# To create a documentation set, doxygen will generate a Makefile in the -# HTML output directory. Running make will produce the docset in that -# directory and running "make install" will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. - -GENERATE_DOCSET = NO - -# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -# feed. A documentation feed provides an umbrella under which multiple -# documentation sets from a single provider (such as a company or product suite) -# can be grouped. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -# should uniquely identify the documentation set bundle. This should be a -# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen -# will append .docset to the name. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING -# is used to encode HtmlHelp index (hhk), content (hhc) and project file -# content. - -CHM_INDEX_ENCODING = - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER -# are set, an additional index file will be generated that can be used as input for -# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated -# HTML documentation. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can -# be used to specify the file name of the resulting .qch file. -# The path specified is relative to the HTML output folder. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#namespace - -QHP_NAMESPACE = - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#virtual-folders - -QHP_VIRTUAL_FOLDER = doc - -# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. -# For more information please see -# http://doc.trolltech.com/qthelpproject.html#custom-filters - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see -# Qt Help Project / Custom Filters. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's -# filter section matches. -# Qt Help Project / Filter Attributes. - -QHP_SECT_FILTER_ATTRS = - -# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can -# be used to specify the location of Qt's qhelpgenerator. -# If non-empty doxygen will try to run qhelpgenerator on the generated -# .qhp file. - -QHG_LOCATION = - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. - -DISABLE_INDEX = NO - -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. - -ENUM_VALUES_PER_LINE = 4 - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. -# If the tag value is set to FRAME, a side panel will be generated -# containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, -# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are -# probably better off using the HTML help feature. Other possible values -# for this tag are: HIERARCHIES, which will generate the Groups, Directories, -# and Class Hierarchy pages using a tree view instead of an ordered list; -# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which -# disables this behavior completely. For backwards compatibility with previous -# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE -# respectively. - -GENERATE_TREEVIEW = NONE - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -# Use this tag to change the font size of Latex formulas included -# as images in the HTML documentation. The default is 10. Note that -# when you change the font size after a successful doxygen run you need -# to manually remove any form_*.png images from the HTML output directory -# to force them to be regenerated. - -FORMULA_FONTSIZE = 10 - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = NO - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4wide - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = YES - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = YES - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. -# This is useful -# if you want to understand what is going on. -# On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = NO - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse -# the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more -# powerful graphs. - -CLASS_DIAGRAMS = YES - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see -# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = YES - -# By default doxygen will write a font called FreeSans.ttf to the output -# directory and reference it in all dot files that doxygen generates. This -# font does not include all possible unicode characters however, so when you need -# these (or just want a differently looking font) you can specify the font name -# using DOT_FONTNAME. You need need to make sure dot is able to find the font, -# which can be done by putting it in a standard location or by setting the -# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory -# containing the font. - -DOT_FONTNAME = FreeSans - -# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. -# The default size is 10pt. - -DOT_FONTSIZE = 10 - -# By default doxygen will tell dot to use the output directory to look for the -# FreeSans.ttf font (which doxygen will put there itself). If you specify a -# different font using DOT_FONTNAME you can set the path where dot -# can find it using this tag. - -DOT_FONTPATH = - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = NO - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = NO - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH and HAVE_DOT options are set to YES then -# doxygen will generate a call dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable call graphs -# for selected functions only using the \callgraph command. - -CALL_GRAPH = NO - -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then -# doxygen will generate a caller dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable caller -# graphs for selected functions only using the \callergraph command. - -CALLER_GRAPH = NO - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, jpg, or gif -# If left blank png will be used. - -DOT_IMAGE_FORMAT = png - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the -# number of direct children of the root node in a graph is already larger than -# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note -# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. - -DOT_GRAPH_MAX_NODES = 50 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by -# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. - -MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not -# seem to support this out of the box. Warning: Depending on the platform used, -# enabling this option may lead to badly anti-aliased labels on the edges of -# a graph (i.e. they become hard to read). - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = NO - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES - -#--------------------------------------------------------------------------- -# Options related to the search engine -#--------------------------------------------------------------------------- - -# The SEARCHENGINE tag specifies whether or not a search engine should be -# used. If set to NO the values of all tags below this one will be ignored. - -SEARCHENGINE = NO diff --git a/libs/mangle/LICENSE.txt b/libs/mangle/LICENSE.txt deleted file mode 100644 index ccfcc9f22..000000000 --- a/libs/mangle/LICENSE.txt +++ /dev/null @@ -1,26 +0,0 @@ -Minimal Abstraction Game Layer (Mangle) is licensed under the -'zlib/libpng' license: - ----- - -Copyright (c) 2009 Nicolay Korslund - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - diff --git a/libs/mangle/README.txt b/libs/mangle/README.txt deleted file mode 100644 index f4849bebd..000000000 --- a/libs/mangle/README.txt +++ /dev/null @@ -1,129 +0,0 @@ -Welcome to Mangle v0.1 ----------------------- - -Written by: Nicolay Korslund (korslund@gmail.com) -License: zlib/png (see LICENSE.txt) -WWW: http://asm-soft.com/mangle/ -Documentation: http://asm-soft.com/mangle/docs - - - -Mangle is the project name for a small set of generic interfaces for -various game middleware libraries, such as sound, input, graphics, and -so on. You can imagine that it stands for "Minimal Abstraction Game -Layer", if you like. It will consist of several more or less -independent modules, one for each of these areas. These may be used -together to build an entire game engine, or they can be used -individually as separate libraries. - -However, Mangle does NOT actually implement a game engine, or any new -fundamental functionality. More on that below. - -Currently there's modules for sound and streams / archives (virtual -file systems.) More will come in the future (including input, 2D/3D -graphics, GUI, physics, and more.) - - -Main idea ---------- - -The idea behind Mangle is to provide a uniform, consistent interface -to other game libraries. The library does not provide ANY -functionality on its own. Instead it connects to a backend -implementation of your choice (or of your making.) - -The Sound module, for example, currently has backends for OpenAL -(output only), FFmpeg (input only) and for Audiere. Hopefully we'll -add IrrKlang, FMod, DirectSound, Miles and more in the future. It can -combine libraries to get more complete functionality (like using -OpenAL for output and FFmpeg to decode sound files), and it's also -easy to write your own backend if you're using a different (or -home-brewed) sound system. - -Regardless of what backend you use, the front-end interfaces (found -eg. in sound/output.h) is identical, and as a library user you -shouldn't notice much difference at all if you swap one backend for -another at a later point. It should Just Work. - -The interfaces themselves are also quite simple. Setting up a sound -stream from FFmpeg or other decoder into OpenAL can be quite hairy - -but with Mangle the hairy parts have already been written for you. You -just plug the parts together. - -The goal in the long run is to support a wide variety of game-related -libraries, and as many backend libraries (free and commercial) as -possible, so that you the user will have to write as little code as -possible. - - - -What is it good for -------------------- - -The main point of Mangle, as we said above, is that it connects to any -library of your choice "behind the scenes" but provides the same, -super-simple interface front-end for all of them. There can benefit -you in many ways: - -- If you want to use a new library that Mangle support. You don't have - to scour the net for tutorials and usage examples, since much of the - common usage code is already included in the implementation classes. - -- If you don't want to pollute your code with library-specific code. - The Mangle interfaces can help you keep your code clean, and its - user interface is often simpler than the exteral library one. - -- If you want to quickly connect different libraries together, it - really helps if they speak a common language. The Mangle interfaces - are exactly that - a common language between libraries. Do you need - Audiere to load sounds from a weird archive format only implemented - for PhysFS, all channeled through the OGRE resource system? No - problem! - -- If you are creating a library that depends on a specific feature - (such as sound), but you don't want to lock your users into any - specific sound library. Mangle works as an abstraction that lets - your users select their own implementation. - -- If you want to support multiple backends for your game/app, or want - to make it possible to easily switch backends later. You can select - backends at compile time or even at runtime. For example you might - want to switch to to a commercial sound library at a later stage in - development, or you may want to use a different input library on - console platforms than on PC. - -The Mangle implementations are extremely light-weight - often just one -or two cpp/h pairs per module. You can plug them directly into your -program, there's no separate library building step required. - -Since the library aims to be very modularly put together, you can -also, in many cases, just copy-and-paste the parts you need and ignore -the rest. Or modify stuff without fearing that the whole 'system' will -come crashing down, because there is no big 'system' to speak of. - - -Past and future ---------------- - -Mangle started out as (and still is) a spin-off from OpenMW, another -project I am personally working on ( http://openmw.com/ ). OpenMW is -an attempt to recreate the engine behind the commercial game -Morrowind, using only open source software. - -The projects are still tightly interlinked, and they will continue to -be until OpenMW is finished. Most near-future work on Mangle will be -focused chiefly on OpenMW at the moment. However I will gladly include -external contributions and suggestions that are not OpenMW-related if -someone sends them to me. - - -Conclusion ----------- - -As you might have guessed, Mangle is more a concept in development -than a finished library right now. - -All feedback, ideas, concepts, questions and code are very -welcome. Send them to: korslund@gmail.com - -I will put up a forum later as well if there's enough interest. diff --git a/libs/mangle/input/clients/ogre_input_capture.hpp b/libs/mangle/input/clients/ogre_input_capture.hpp deleted file mode 100644 index 2e77dc10b..000000000 --- a/libs/mangle/input/clients/ogre_input_capture.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef MANGLE_INPUT_OGREINPUTFRAME_H -#define MANGLE_INPUT_OGREINPUTFRAME_H - -/* - This Ogre FrameListener calls capture() on an input driver every frame. - */ - -#include -#include "../driver.hpp" - -namespace Mangle { -namespace Input { - - struct OgreInputCapture : Ogre::FrameListener - { - Mangle::Input::Driver &driver; - - OgreInputCapture(Mangle::Input::Driver &drv) - : driver(drv) {} - - bool frameStarted(const Ogre::FrameEvent &evt) - { - driver.capture(); - return true; - } - }; -}} - -#endif diff --git a/libs/mangle/input/driver.hpp b/libs/mangle/input/driver.hpp deleted file mode 100644 index f4ba159c5..000000000 --- a/libs/mangle/input/driver.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef MANGLE_INPUT_DRIVER_H -#define MANGLE_INPUT_DRIVER_H - -#include "event.hpp" - -namespace Mangle -{ - namespace Input - { - /** Input::Driver is the main interface to any input system that - handles keyboard and/or mouse input, along with any other - input source like joysticks. - - It is really a generalized event system, and could also be - used for non-input related events. The definition of the event - codes and structures are entirely dependent on the - implementation. - - A system-independent key code list will be found in keys.hpp, - and input drivers should privide optional translations to/from - this list for full compatibility. - */ - struct Driver - { - Driver() {} - virtual ~Driver() {} - - /** Captures input and produces the relevant events from it. An - event callback must be set with setEvent(), or all events - will be ignored. - */ - virtual void capture() = 0; - - /** Check the state of a given key or button. The key/button - definitions depends on the driver. - */ - virtual bool isDown(int index) = 0; - - /** Show or hide system mouse cursor - */ - virtual void showMouse(bool show) = 0; - - /** Set the event handler for input events. The evt->event() - function is called for each event. The meaning of the index - and *p parameters will be specific to each driver and to - each input system. - */ - void setEvent(EventPtr evt) - { event = evt; } - - /** Instigate an event. Is used internally for all events, but - can also be called from the outside to "fake" events from - this driver. - */ - void makeEvent(Event::Type type, int index, const void *p=NULL) - { - if(event) - event->event(type,index,p); - } - - private: - /// Holds the event callback set byt setEvent() - EventPtr event; - }; - - typedef boost::shared_ptr DriverPtr; - } -} -#endif diff --git a/libs/mangle/input/event.hpp b/libs/mangle/input/event.hpp deleted file mode 100644 index dc7b47088..000000000 --- a/libs/mangle/input/event.hpp +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef MANGLE_INPUT_EVENT_H -#define MANGLE_INPUT_EVENT_H - -#include "../tools/shared_ptr.hpp" - -namespace Mangle -{ - namespace Input - { - /** Generic callback for input events. The meaning of the - parameters depend on the system producing the events. - */ - struct Event - { - /// Event types - enum Type - { - EV_Unknown = 1, // Unknown event type - EV_KeyDown = 2, // Keyboard button was pressed - EV_KeyUp = 4, // Keyboard button was released - EV_Keyboard = 6, // All keyboard events - - EV_MouseMove = 8, // Mouse movement - EV_MouseDown = 16, // Mouse button pressed - EV_MouseUp = 32, // Mouse button released - EV_Mouse = 56, // All mouse events - - EV_ALL = 63 // All events - }; - - /** - Called upon all events. The first parameter give the event - type, the second gives additional data (usually the local - keysym or button index as defined by the driver), and the - pointer points to the full custom event structure provided by - the driver (the type may vary depending on the EventType, - this is defined in the Driver documentation.) - */ - virtual void event(Type type, int index, const void *p) = 0; - virtual ~Event() {} - }; - - typedef boost::shared_ptr EventPtr; - } -} -#endif diff --git a/libs/mangle/input/filters/eventlist.hpp b/libs/mangle/input/filters/eventlist.hpp deleted file mode 100644 index b3e2ff8f2..000000000 --- a/libs/mangle/input/filters/eventlist.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef MANGLE_INPUT_EVENTLIST_H -#define MANGLE_INPUT_EVENTLIST_H - -#include "../event.hpp" -#include - -namespace Mangle -{ - namespace Input - { - /** And Event handler that distributes each event to a list of - other handlers. Supports filtering events by their Type - parameter. - */ - struct EventList : Event - { - struct Filter - { - EventPtr evt; - int flags; - }; - std::vector list; - - void add(EventPtr e, int flags = EV_ALL) - { - Filter f; - f.evt = e; - f.flags = flags; - list.push_back(f); - } - - virtual void event(Type type, int index, const void *p) - { - std::vector::iterator it; - - for(it=list.begin(); it!=list.end(); it++) - { - if(type & it->flags) - it->evt->event(type,index,p); - } - } - }; - - typedef boost::shared_ptr EventListPtr; - } -} -#endif diff --git a/libs/mangle/input/servers/ois_driver.cpp b/libs/mangle/input/servers/ois_driver.cpp deleted file mode 100644 index 07ba3e83a..000000000 --- a/libs/mangle/input/servers/ois_driver.cpp +++ /dev/null @@ -1,154 +0,0 @@ -#include "ois_driver.hpp" - -#include -#include -#include -#include - -#ifdef __APPLE_CC__ -#include -#endif - -using namespace Mangle::Input; -using namespace OIS; - -struct Mangle::Input::OISListener : OIS::KeyListener, OIS::MouseListener -{ - OISDriver &drv; - - OISListener(OISDriver &driver) - : drv(driver) {} - - bool keyPressed( const OIS::KeyEvent &arg ) - { - drv.makeEvent(Event::EV_KeyDown, arg.key, &arg); - return true; - } - - bool keyReleased( const OIS::KeyEvent &arg ) - { - drv.makeEvent(Event::EV_KeyUp, arg.key, &arg); - return true; - } - - bool mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id ) - { - // Mouse button events are handled as key events - // TODO: Translate mouse buttons into pseudo-keysyms - drv.makeEvent(Event::EV_MouseDown, id, &arg); - return true; - } - - bool mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id ) - { - // TODO: ditto - drv.makeEvent(Event::EV_MouseUp, id, &arg); - return true; - } - - bool mouseMoved( const OIS::MouseEvent &arg ) - { - drv.makeEvent(Event::EV_MouseMove, -1, &arg); - return true; - } -}; - -OISDriver::OISDriver(Ogre::RenderWindow *window, bool exclusive) -{ - assert(window); - - size_t windowHnd; - - window->getCustomAttribute("WINDOW", &windowHnd); - - std::ostringstream windowHndStr; - ParamList pl; - - windowHndStr << windowHnd; - pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str())); - - // Set non-exclusive mouse and keyboard input if the user requested - // it. - if(!exclusive) - { -#if defined OIS_WIN32_PLATFORM - pl.insert(std::make_pair(std::string("w32_mouse"), - std::string("DISCL_FOREGROUND" ))); - pl.insert(std::make_pair(std::string("w32_mouse"), - std::string("DISCL_NONEXCLUSIVE"))); - pl.insert(std::make_pair(std::string("w32_keyboard"), - std::string("DISCL_FOREGROUND"))); - pl.insert(std::make_pair(std::string("w32_keyboard"), - std::string("DISCL_NONEXCLUSIVE"))); -#elif defined OIS_LINUX_PLATFORM - pl.insert(std::make_pair(std::string("x11_mouse_grab"), - std::string("false"))); - pl.insert(std::make_pair(std::string("x11_mouse_hide"), - std::string("false"))); - pl.insert(std::make_pair(std::string("x11_keyboard_grab"), - std::string("false"))); - pl.insert(std::make_pair(std::string("XAutoRepeatOn"), - std::string("true"))); -#endif - } - -#ifdef __APPLE_CC__ - // Give the application window focus to receive input events - ProcessSerialNumber psn = { 0, kCurrentProcess }; - TransformProcessType(&psn, kProcessTransformToForegroundApplication); - SetFrontProcess(&psn); -#endif - - inputMgr = InputManager::createInputSystem( pl ); - - // Create all devices - keyboard = static_cast(inputMgr->createInputObject - ( OISKeyboard, true )); - mouse = static_cast(inputMgr->createInputObject - ( OISMouse, true )); - - // Set mouse region - const MouseState &ms = mouse->getMouseState(); - ms.width = window->getWidth(); - ms.height = window->getHeight(); - - // Set up the input listener - listener = new OISListener(*this); - keyboard-> setEventCallback(listener); - mouse-> setEventCallback(listener); -} - -OISDriver::~OISDriver() -{ - // Delete the listener object - delete listener; - - if(inputMgr == NULL) return; - - // Kill the input systems. This will reset input options such as key - // repeat rate. - inputMgr->destroyInputObject(keyboard); - inputMgr->destroyInputObject(mouse); - InputManager::destroyInputSystem(inputMgr); - inputMgr = NULL; -} - -void OISDriver::capture() -{ - // Capture keyboard and mouse events - keyboard->capture(); - mouse->capture(); -} - -bool OISDriver::isDown(int index) -{ - // TODO: Extend to mouse buttons as well - return keyboard->isKeyDown((OIS::KeyCode)index); -} - -void OISDriver::adjustMouseClippingSize(int width, int height) -{ - const OIS::MouseState &ms = mouse->getMouseState(); - ms.width = width; - ms.height = height; -} diff --git a/libs/mangle/input/servers/ois_driver.hpp b/libs/mangle/input/servers/ois_driver.hpp deleted file mode 100644 index 81633542f..000000000 --- a/libs/mangle/input/servers/ois_driver.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef MANGLE_INPUT_OIS_DRIVER_H -#define MANGLE_INPUT_OIS_DRIVER_H - -#include "../driver.hpp" - -namespace OIS -{ - class InputManager; - class Mouse; - class Keyboard; -} - -namespace Ogre -{ - class RenderWindow; -} - -namespace Mangle -{ - namespace Input - { - struct OISListener; - - /** Input driver for OIS, the input manager typically used with - Ogre. - */ - struct OISDriver : Driver - { - /// If exclusive=true, then we capture mouse and keyboard from - /// the OS. - OISDriver(Ogre::RenderWindow *window, bool exclusive=true); - ~OISDriver(); - - void adjustMouseClippingSize(int width, int height); - - void capture(); - bool isDown(int index); - /// Not currently supported. - void showMouse(bool) {} - - private: - OIS::InputManager *inputMgr; - OIS::Mouse *mouse; - OIS::Keyboard *keyboard; - - OISListener *listener; - }; - } -} -#endif diff --git a/libs/mangle/input/servers/sdl_driver.cpp b/libs/mangle/input/servers/sdl_driver.cpp deleted file mode 100644 index 93884a6e6..000000000 --- a/libs/mangle/input/servers/sdl_driver.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "sdl_driver.hpp" - -#include - -using namespace Mangle::Input; - -void SDLDriver::capture() -{ - // Poll for events - SDL_Event evt; - while(SDL_PollEvent(&evt)) - { - Event::Type type = Event::EV_Unknown; - int index = -1; - - switch(evt.type) - { - // For key events, send the keysym as the index. - case SDL_KEYDOWN: - type = Event::EV_KeyDown; - index = evt.key.keysym.sym; - break; - case SDL_KEYUP: - type = Event::EV_KeyUp; - index = evt.key.keysym.sym; - break; - case SDL_MOUSEMOTION: - type = Event::EV_MouseMove; - break; - // Add more event types later - } - - // Pass the event along, using -1 as index for unidentified - // event types. - makeEvent(type, index, &evt); - } -} - -bool SDLDriver::isDown(int index) -{ - int num; - Uint8 *keys = SDL_GetKeyState(&num); - assert(index >= 0 && index < num); - - // The returned array from GetKeyState is indexed by the - // SDLK_KEYNAME enums and is just a list of bools. If the indexed - // value is true, the button is down. - return keys[index]; -} - -void SDLDriver::showMouse(bool show) -{ - SDL_ShowCursor(show?SDL_ENABLE:SDL_DISABLE); -} diff --git a/libs/mangle/input/servers/sdl_driver.hpp b/libs/mangle/input/servers/sdl_driver.hpp deleted file mode 100644 index b71346cba..000000000 --- a/libs/mangle/input/servers/sdl_driver.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef MANGLE_INPUT_SDL_DRIVER_H -#define MANGLE_INPUT_SDL_DRIVER_H - -#include "../driver.hpp" - -namespace Mangle -{ - namespace Input - { - /** Input driver for SDL. As the input system of SDL is seldomly - used alone (most often along with the video system), it is - assumed that you do your own initialization and cleanup of SDL - before and after using this driver. - - The Event.event() calls will be given the proper EV_ type, the - key index (for key up/down events), and a pointer to the full - SDL_Event structure. - */ - struct SDLDriver : Driver - { - void capture(); - bool isDown(int index); - void showMouse(bool); - }; - } -} -#endif diff --git a/libs/mangle/input/tests/.gitignore b/libs/mangle/input/tests/.gitignore deleted file mode 100644 index 460c76f00..000000000 --- a/libs/mangle/input/tests/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*_test -ogre.cfg diff --git a/libs/mangle/input/tests/Makefile b/libs/mangle/input/tests/Makefile deleted file mode 100644 index 8760adfe7..000000000 --- a/libs/mangle/input/tests/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -GCC=g++ -Wall - -all: sdl_driver_test ois_driver_test evtlist_test - -sdl_driver_test: sdl_driver_test.cpp - $(GCC) $< ../servers/sdl_driver.cpp -o $@ -I/usr/include/SDL/ -lSDL - -ois_driver_test: ois_driver_test.cpp - $(GCC) $< ../servers/ois_driver.cpp -o $@ -I/usr/local/include/OGRE/ -lOgreMain -lOIS -lboost_filesystem - -evtlist_test: evtlist_test.cpp ../filters/eventlist.hpp ../event.hpp - $(GCC) $< -o $@ - -clean: - rm *_test diff --git a/libs/mangle/input/tests/common.cpp b/libs/mangle/input/tests/common.cpp deleted file mode 100644 index 0c7c76466..000000000 --- a/libs/mangle/input/tests/common.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include "../driver.hpp" -#include -using namespace std; -using namespace Mangle::Input; - -Driver *input; - -struct MyCB : Event -{ - void event(Event::Type type, int i, const void *p) - { - cout << "got event: type=" << type << " index=" << i << endl; - } -}; - -void mainLoop(int argc, int quitKey) -{ - cout << "Hold the Q key to quit:\n"; - input->setEvent(EventPtr(new MyCB)); - while(!input->isDown(quitKey)) - { - input->capture(); - usleep(20000); - - if(argc == 1) - { - cout << "You are running in script mode, aborting. Run this test with a parameter (any at all) to test the input loop properly\n"; - break; - } - } - - delete input; - cout << "\nBye bye!\n"; -} diff --git a/libs/mangle/input/tests/evtlist_test.cpp b/libs/mangle/input/tests/evtlist_test.cpp deleted file mode 100644 index fbd980cbd..000000000 --- a/libs/mangle/input/tests/evtlist_test.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include "../filters/eventlist.hpp" - -using namespace std; -using namespace Mangle::Input; - -struct MyEvent : Event -{ - int ii; - MyEvent(int i) : ii(i) {} - - void event(Event::Type type, int i, const void *p) - { - cout << " #" << ii << " got event: type=" << type << " index=" << i << endl; - } -}; - -EventList lst; - -int iii=1; -void make(int flags) -{ - lst.add(EventPtr(new MyEvent(iii++)), flags); -} - -void send(Event::Type type) -{ - cout << "Sending type " << type << endl; - lst.event(type,0,NULL); -} - -int main() -{ - make(Event::EV_ALL); - make(Event::EV_KeyDown); - make(Event::EV_KeyUp | Event::EV_MouseDown); - - send(Event::EV_Unknown); - send(Event::EV_KeyDown); - send(Event::EV_KeyUp); - send(Event::EV_MouseDown); - - cout << "Enough of that\n"; - return 0; -} diff --git a/libs/mangle/input/tests/ois_driver_test.cpp b/libs/mangle/input/tests/ois_driver_test.cpp deleted file mode 100644 index 386f24055..000000000 --- a/libs/mangle/input/tests/ois_driver_test.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "common.cpp" - -#include "../servers/ois_driver.hpp" -#include -#include -#include - -bool isFile(const char *name) -{ - boost::filesystem::path cfg_file_path(name); - return boost::filesystem::exists(cfg_file_path); -} - -using namespace Ogre; -using namespace OIS; - -Root *root; -RenderWindow *window; - -void setupOgre() -{ - // Disable logging - new LogManager; - Log *log = LogManager::getSingleton().createLog(""); - log->setDebugOutputEnabled(false); - - bool useConfig = isFile("ogre.cfg"); - - // Set up Root - root = new Root("plugins.cfg", "ogre.cfg", ""); - - // Configure - if(!useConfig) - root->showConfigDialog(); - else - root->restoreConfig(); - - // Initialize OGRE window - window = root->initialise(true, "test", ""); -} - -int main(int argc, char** argv) -{ - setupOgre(); - input = new OISDriver(window); - - mainLoop(argc, KC_Q); - - delete root; - return 0; -} diff --git a/libs/mangle/input/tests/output/evtlist_test.out b/libs/mangle/input/tests/output/evtlist_test.out deleted file mode 100644 index 180dcc58a..000000000 --- a/libs/mangle/input/tests/output/evtlist_test.out +++ /dev/null @@ -1,12 +0,0 @@ -Sending type 1 - #1 got event: type=1 index=0 -Sending type 2 - #1 got event: type=2 index=0 - #2 got event: type=2 index=0 -Sending type 4 - #1 got event: type=4 index=0 - #3 got event: type=4 index=0 -Sending type 16 - #1 got event: type=16 index=0 - #3 got event: type=16 index=0 -Enough of that diff --git a/libs/mangle/input/tests/output/ois_driver_test.out b/libs/mangle/input/tests/output/ois_driver_test.out deleted file mode 100644 index 7d273fd46..000000000 --- a/libs/mangle/input/tests/output/ois_driver_test.out +++ /dev/null @@ -1,5 +0,0 @@ -Hold the Q key to quit: -got event: type=8 index=-1 -You are running in script mode, aborting. Run this test with a parameter (any at all) to test the input loop properly - -Bye bye! diff --git a/libs/mangle/input/tests/output/sdl_driver_test.out b/libs/mangle/input/tests/output/sdl_driver_test.out deleted file mode 100644 index 2df2e4014..000000000 --- a/libs/mangle/input/tests/output/sdl_driver_test.out +++ /dev/null @@ -1,5 +0,0 @@ -Hold the Q key to quit: -got event: type=1 index=-1 -You are running in script mode, aborting. Run this test with a parameter (any at all) to test the input loop properly - -Bye bye! diff --git a/libs/mangle/input/tests/plugins.cfg b/libs/mangle/input/tests/plugins.cfg deleted file mode 100644 index 57ec54e1a..000000000 --- a/libs/mangle/input/tests/plugins.cfg +++ /dev/null @@ -1,12 +0,0 @@ -# Defines plugins to load - -# Define plugin folder -PluginFolder=/usr/local/lib/OGRE/ - -# Define plugins -Plugin=RenderSystem_GL -Plugin=Plugin_ParticleFX -Plugin=Plugin_OctreeSceneManager -# Plugin=Plugin_CgProgramManager - - diff --git a/libs/mangle/input/tests/sdl_driver_test.cpp b/libs/mangle/input/tests/sdl_driver_test.cpp deleted file mode 100644 index 5db6dbba8..000000000 --- a/libs/mangle/input/tests/sdl_driver_test.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "common.cpp" - -#include "../servers/sdl_driver.hpp" -#include - -int main(int argc, char** argv) -{ - SDL_Init(SDL_INIT_VIDEO); - SDL_SetVideoMode(640, 480, 0, SDL_SWSURFACE); - input = new SDLDriver(); - - mainLoop(argc, SDLK_q); - - SDL_Quit(); - return 0; -} diff --git a/libs/mangle/input/tests/test.sh b/libs/mangle/input/tests/test.sh deleted file mode 100755 index 2d07708ad..000000000 --- a/libs/mangle/input/tests/test.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -make || exit - -mkdir -p output - -PROGS=*_test - -for a in $PROGS; do - if [ -f "output/$a.out" ]; then - echo "Running $a:" - ./$a | diff output/$a.out - - else - echo "Creating $a.out" - ./$a > "output/$a.out" - git add "output/$a.out" - fi -done diff --git a/libs/mangle/rend2d/driver.hpp b/libs/mangle/rend2d/driver.hpp deleted file mode 100644 index 08a15b0ae..000000000 --- a/libs/mangle/rend2d/driver.hpp +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef MANGLE_REND2D_DRIVER_H -#define MANGLE_REND2D_DRIVER_H - -#include -#include "sprite.hpp" - -namespace Mangle -{ - namespace Rend2D - { - /** - The driver is the connection to the backend system that powers - 2D sprite rendering. For example the backend could be SDL or - any other 2D-capable graphics library. - */ - struct Driver - { - /// Get the screen sprite - virtual Sprite *getScreen() = 0; - - /// Sets the video mode. - virtual void setVideoMode(int width, int height, int bpp=32, bool fullscreen=false) = 0; - - /** Update the screen. Until this function is called, none of - the changes written to the screen sprite will be visible. - */ - virtual void update() = 0; - - /// Set the window title, as well as the title of the window - /// when "iconified" - virtual void setWindowTitle(const std::string &title, - const std::string &icon) = 0; - - /// Set the window title - void setWindowTitle(const std::string &title) { setWindowTitle(title,title); } - - /// Load sprite from an image file. Thows an exception on - /// failure. - virtual Sprite* loadImage(const std::string &file) = 0; - - /// Load a sprite from an image file stored in memory. Throws - /// exception on failure. - virtual Sprite* loadImage(const void* data, size_t size) = 0; - - /** @brief Set gamma value for all colors. - - Note: Setting this in windowed mode will affect the ENTIRE - SCREEN! - */ - virtual void setGamma(float gamma) = 0; - - /// Set gamma individually for red, green, blue - virtual void setGamma(float red, float green, float blue) = 0; - - /// Get screen width - virtual int width() = 0; - - /// Get screen height - virtual int height() = 0; - }; - } -} -#endif diff --git a/libs/mangle/rend2d/servers/sdl_driver.cpp b/libs/mangle/rend2d/servers/sdl_driver.cpp deleted file mode 100644 index 84a17933f..000000000 --- a/libs/mangle/rend2d/servers/sdl_driver.cpp +++ /dev/null @@ -1,259 +0,0 @@ -#include "sdl_driver.hpp" - -#include -#include -#include -#include - -using namespace Mangle::Rend2D; - -const SpriteData *SDL_Sprite::lock() -{ - // Make sure we aren't already locked - assert(!data.pixels); - - // Lock the surface and set up the data structure - SDL_LockSurface(surface); - - data.pixels = surface->pixels; - data.w = surface->w; - data.h = surface->h; - data.pitch = surface->pitch; - data.bypp = surface->format->BytesPerPixel; - - return &data; -} - -void SDL_Sprite::unlock() -{ - if(data.pixels) - { - SDL_UnlockSurface(surface); - data.pixels = NULL; - } -} - -// This is a really crappy and slow implementation, only intended for -// testing purposes. Use lock/unlock for faster pixel drawing. -void SDL_Sprite::pixel(int x, int y, int color) -{ - SDL_LockSurface(surface); - - int bpp = surface->format->BytesPerPixel; - char *p = (char*)surface->pixels + y*surface->pitch + x*bpp; - - switch(bpp) - { - case 1: *p = color; break; - case 3: - if(SDL_BYTEORDER == SDL_BIG_ENDIAN) - { - p[0] = (color >> 16) & 0xff; - p[1] = (color >> 8) & 0xff; - p[2] = color & 0xff; - } - else - { - p[0] = color & 0xff; - p[1] = (color >> 8) & 0xff; - p[2] = (color >> 16) & 0xff; - } - break; - case 4: - *(int*)p = color; - break; - } - SDL_UnlockSurface(surface); -} - -void SDL_Sprite::draw(Sprite *s, // Must be SDL_Sprite - int x, int y, // Destination position - int sx, int sy, // Source position - int w, int h // Amount to draw. -1 means remainder. - ) -{ - // Get source surface - SDL_Sprite *other = dynamic_cast(s); - assert(other != NULL); - SDL_Surface *img = other->getSurface(); - - // Check coordinate validity - assert(sx <= img->w && sy <= img->h); - assert(x <= surface->w && y <= surface->h); - assert(sx >= 0 && sy >= 0); - - // Compute width and height if necessary - if(w == -1) w = img->w - sx; - if(h == -1) h = img->h - sy; - - // Check them if they're valid - assert(w >= 0 && w <= img->w); - assert(h >= 0 && h <= img->h); - - SDL_Rect dest; - dest.x = x; - dest.y = y; - dest.w = w; - dest.h = h; - - SDL_Rect src; - src.x = sx; - src.y = sy; - src.w = w; - src.h = h; - - // Do the Blitman - SDL_BlitSurface(img, &src, surface, &dest); -} - -SDL_Sprite::SDL_Sprite(SDL_Surface *s, bool autoDelete) - : surface(s), autoDel(autoDelete) -{ - assert(surface != NULL); - data.pixels = NULL; -} - -SDL_Sprite::~SDL_Sprite() -{ - if(autoDel) - SDL_FreeSurface(surface); -} - -void SDL_Sprite::fill(int value) -{ - SDL_FillRect(surface, NULL, value); -} - -int SDL_Sprite::width() { return surface->w; } -int SDL_Sprite::height() { return surface->h; } - -SDLDriver::SDLDriver() : display(NULL), realDisp(NULL), softDouble(false) -{ - if (SDL_InitSubSystem( SDL_INIT_VIDEO ) == -1) - throw std::runtime_error("Error initializing SDL video"); -} -SDLDriver::~SDLDriver() -{ - if(display) delete display; - SDL_Quit(); -} - -void SDLDriver::setVideoMode(int width, int height, int bpp, bool fullscreen) -{ - unsigned int flags; - - if(display) delete display; - - if (fullscreen) - // Assume fullscreen mode allows a double-bufferd hardware - // mode. We need more test code for this to be safe though. - flags = SDL_FULLSCREEN | SDL_HWSURFACE | SDL_DOUBLEBUF; - else - flags = SDL_SWSURFACE; - - // Create the surface and check it - realDisp = SDL_SetVideoMode(width, height, bpp, flags); - if(realDisp == NULL) - throw std::runtime_error("Failed setting SDL video mode"); - - // Code for software double buffering. I haven't found this to be - // any speed advantage at all in windowed mode (it's slower, as one - // would expect.) Not properly tested in fullscreen mode with - // hardware buffers, but it will probably only be an improvement if - // we do excessive writing (ie. write each pixel on average more - // than once) or try to read from the display buffer. - if(softDouble) - { - // Make a new surface with the same attributes as the real - // display surface. - SDL_Surface *back = SDL_DisplayFormat(realDisp); - assert(back != NULL); - - // Create a sprite representing the double buffer - display = new SDL_Sprite(back); - } - else - { - // Create a sprite directly representing the display surface. - // The 'false' parameter means do not autodelete the screen - // surface upon exit (since SDL manages it) - display = new SDL_Sprite(realDisp, false); - } -} - -/// Update the screen -void SDLDriver::update() -{ - // Blit the soft double buffer onto the real display buffer - if(softDouble) - SDL_BlitSurface(display->getSurface(), NULL, realDisp, NULL ); - - if(realDisp) - SDL_Flip(realDisp); -} - -/// Set the window title, as well as the title of the window when -/// "iconified" -void SDLDriver::setWindowTitle(const std::string &title, - const std::string &icon) -{ - SDL_WM_SetCaption( title.c_str(), icon.c_str() ); -} - -// Convert the given surface to display format. -static SDL_Surface* convertImage(SDL_Surface* surf) -{ - if(surf != NULL) - { - // Convert the image to the display buffer format, for faster - // blitting - SDL_Surface *surf2 = SDL_DisplayFormat(surf); - SDL_FreeSurface(surf); - surf = surf2; - } - return surf; -} - -/// Load sprite from an image file, using SDL_image. -Sprite* SDLDriver::loadImage(const std::string &file) -{ - SDL_Surface *surf = IMG_Load(file.c_str()); - surf = convertImage(surf); - if(surf == NULL) - throw std::runtime_error("SDL failed to load image file '" + file + "'"); - return spriteFromSDL(surf); -} - -/// Load sprite from an SDL_RWops structure. autoFree determines -/// whether the RWops struct should be closed/freed after use. -Sprite* SDLDriver::loadImage(SDL_RWops *src, bool autoFree) -{ - SDL_Surface *surf = IMG_Load_RW(src, autoFree); - surf = convertImage(surf); - if(surf == NULL) - throw std::runtime_error("SDL failed to load image"); - return spriteFromSDL(surf); -} - -/// Load a sprite from an image file stored in memory. Uses -/// SDL_image. -Sprite* SDLDriver::loadImage(const void* data, size_t size) -{ - SDL_RWops *rw = SDL_RWFromConstMem(data, size); - return loadImage(rw, true); -} - -void SDLDriver::setGamma(float red, float green, float blue) -{ - SDL_SetGamma(red,green,blue); -} - -/// Convert an existing SDL surface into a sprite -Sprite* SDLDriver::spriteFromSDL(SDL_Surface *surf, bool autoFree) -{ - assert(surf); - return new SDL_Sprite(surf, autoFree); -} - -void SDLDriver::sleep(int ms) { SDL_Delay(ms); } -unsigned int SDLDriver::ticks() { return SDL_GetTicks(); } diff --git a/libs/mangle/rend2d/servers/sdl_driver.hpp b/libs/mangle/rend2d/servers/sdl_driver.hpp deleted file mode 100644 index 0f205ba34..000000000 --- a/libs/mangle/rend2d/servers/sdl_driver.hpp +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef MANGLE_DRAW2D_SDL_H -#define MANGLE_DRAW2D_SDL_H - -#include "../driver.hpp" - -// Predeclarations keep the streets safe at night -struct SDL_Surface; -struct SDL_RWops; - -namespace Mangle -{ - namespace Rend2D - { - /// SDL-implementation of Sprite - struct SDL_Sprite : Sprite - { - /** Draw a sprite in the given position. Can only draw other SDL - sprites. - */ - void draw(Sprite *s, // Must be SDL_Sprite - int x, int y, // Destination position - int sx=0, int sy=0, // Source position - int w=-1, int h=-1 // Amount to draw. -1 means remainder. - ); - - SDL_Sprite(SDL_Surface *s, bool autoDelete=true); - ~SDL_Sprite(); - - // Information retrieval - int width(); - int height(); - SDL_Surface *getSurface() { return surface; } - - // Fill with a given pixel value - void fill(int value); - - // Set one pixel - void pixel(int x, int y, int value); - - const SpriteData *lock(); - void unlock(); - - private: - // The SDL surface - SDL_Surface* surface; - - // Used for locking - SpriteData data; - - // If true, delete this surface when the canvas is destructed - bool autoDel; - }; - - class SDLDriver : public Driver - { - // The main display surface - SDL_Sprite *display; - - // The actual display surface. May or may not be the same - // surface pointed to by 'display' above, depending on the - // softDouble flag. - SDL_Surface *realDisp; - - // If true, we do software double buffering. - bool softDouble; - - public: - SDLDriver(); - ~SDLDriver(); - - /// Sets the video mode. Will create the window if it is not - /// already set up. Note that for SDL, bpp=0 means use current - /// bpp. - void setVideoMode(int width, int height, int bpp=0, bool fullscreen=false); - - /// Update the screen - void update(); - - /// Set the window title, as well as the title of the window - /// when "iconified" - void setWindowTitle(const std::string &title, - const std::string &icon); - - // Include overloads from our Glorious parent - using Driver::setWindowTitle; - - /// Load sprite from an image file, using SDL_image. - Sprite* loadImage(const std::string &file); - - /// Load sprite from an SDL_RWops structure. autoFree determines - /// whether the RWops struct should be closed/freed after use. - Sprite* loadImage(SDL_RWops *src, bool autoFree=false); - - /// Load a sprite from an image file stored in memory. Uses - /// SDL_image. - Sprite* loadImage(const void* data, size_t size); - - /// Set gamma value - void setGamma(float gamma) { setGamma(gamma,gamma,gamma); } - - /// Set gamma individually for red, green, blue - void setGamma(float red, float green, float blue); - - /// Convert an existing SDL surface into a sprite - Sprite* spriteFromSDL(SDL_Surface *surf, bool autoFree = true); - - // Get width and height - int width() { return display ? display->width() : 0; } - int height() { return display ? display->height() : 0; } - - /// Get the screen sprite - Sprite *getScreen() { return display; } - - /// Not really a graphic-related function, but very - /// handly. Sleeps the given number of milliseconds using - /// SDL_Delay(). - void sleep(int ms); - - /// Get the number of ticks since SDL initialization, using - /// SDL_GetTicks(). - unsigned int ticks(); - }; - } -} -#endif diff --git a/libs/mangle/rend2d/servers/sdl_gl_driver.cpp b/libs/mangle/rend2d/servers/sdl_gl_driver.cpp deleted file mode 100644 index db519e091..000000000 --- a/libs/mangle/rend2d/servers/sdl_gl_driver.cpp +++ /dev/null @@ -1,311 +0,0 @@ -#include "sdl_gl_driver.hpp" - -#include -#include -#include -#include -#include - -using namespace Mangle::Rend2D; - -void SDLGL_Sprite::draw(Sprite *s, // Must be SDLGL_Sprite - int x, int y, // Destination position - int sx, int sy, // Source position - int w, int h // Amount to draw. -1 means remainder. - ) -{ - // Get source surface - SDLGL_Sprite *other = dynamic_cast(s); - assert(other != NULL); - SDL_Surface *img = other->getSurface(); - - // Check coordinate validity - assert(sx <= img->w && sy <= img->h); - assert(x <= surface->w && y <= surface->h); - assert(sx >= 0 && sy >= 0); - - // Compute width and height if necessary - if(w == -1) w = img->w - sx; - if(h == -1) h = img->h - sy; - - // Check them if they're valid - assert(w >= 0 && w <= img->w); - assert(h >= 0 && h <= img->h); - - SDL_Rect dest; - dest.x = x; - dest.y = y; - dest.w = w; - dest.h = h; - - SDL_Rect src; - src.x = sx; - src.y = sy; - src.w = w; - src.h = h; - - // Do the Blitman - SDL_BlitSurface(img, &src, surface, &dest); -} - -SDLGL_Sprite::SDLGL_Sprite(SDL_Surface *s, bool autoDelete) - : surface(s), autoDel(autoDelete) -{ - assert(surface != NULL); -} - -SDLGL_Sprite::~SDLGL_Sprite() -{ - if(autoDel) - SDL_FreeSurface(surface); -} - -void SDLGL_Sprite::fill(int value) -{ - SDL_FillRect(surface, NULL, value); -} - -int SDLGL_Sprite::width() { return surface->w; } -int SDLGL_Sprite::height() { return surface->h; } - -SDLGLDriver::SDLGLDriver() : display(NULL), realDisp(NULL) -{ - if (SDL_InitSubSystem( SDL_INIT_VIDEO ) == -1) - throw std::runtime_error("Error initializing SDL video"); -} -SDLGLDriver::~SDLGLDriver() -{ - if(display) delete display; - SDL_Quit(); -} - -// Surface used for the screen. Since OpenGL surfaces must have sizes -// that are powers of 2, we have to "fake" the returned display size -// to match the screen, not the surface itself. If we don't use this, -// the client program will get confused about the actual size of our -// screen, thinking it is bigger than it is. -struct FakeSizeSprite : SDLGL_Sprite -{ - int fakeW, fakeH; - - FakeSizeSprite(SDL_Surface *s, int fw, int fh) - : SDLGL_Sprite(s), fakeW(fw), fakeH(fh) - {} - - int width() { return fakeW; } - int height() { return fakeH; } -}; - -static int makePow2(int num) -{ - assert(num); - if((num & (num-1)) != 0) - { - int cnt = 0; - while(num) - { - num >>= 1; - cnt++; - } - num = 1 << cnt; - } - return num; -} - -void SDLGLDriver::setVideoMode(int width, int height, int bpp, bool fullscreen) -{ - unsigned int flags; - - if(display) delete display; - - flags = SDL_OPENGL; - - if (fullscreen) - flags |= SDL_FULLSCREEN; - - SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); - SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, 1 ); - - // Create the surface and check it - screen = SDL_SetVideoMode(width, height, bpp, flags); - if(screen == NULL) - throw std::runtime_error("Failed setting SDL video mode"); - - // Expand width and height to be powers of 2 - int width2 = makePow2(width); - int height2 = makePow2(height); - - // Create a new SDL surface of this size - const SDL_PixelFormat& fmt = *(screen->format); - realDisp = SDL_CreateRGBSurface(SDL_SWSURFACE,width2,height2, - fmt.BitsPerPixel, - fmt.Rmask,fmt.Gmask,fmt.Bmask,fmt.Amask); - - // Create a sprite directly representing the display surface. This - // allows the user to blit to it directly. - display = new FakeSizeSprite(realDisp, width, height); - - // Set up the OpenGL format - nOfColors = fmt.BytesPerPixel; - - if(nOfColors == 4) - { - if (fmt.Rmask == 0x000000ff) - texture_format = GL_RGBA; - else - texture_format = GL_BGRA; - } - else if(nOfColors == 3) - { - if (fmt.Rmask == 0x000000ff) - texture_format = GL_RGB; - else - texture_format = GL_BGR; - } - else - assert(0 && "unsupported screen format"); - - glEnable(GL_TEXTURE_2D); - - // Have OpenGL generate a texture object handle for us - glGenTextures( 1, &texture ); - - // Bind the texture object - glBindTexture( GL_TEXTURE_2D, texture ); - - // Set the texture's stretching properties - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); -} - -void SDLGLDriver::updateNoSwap() -{ - if(!realDisp) return; - - // Fist, set up the screen texture: - - // Bind the texture object - glBindTexture( GL_TEXTURE_2D, texture ); - - // Edit the texture object's image data - glTexImage2D( GL_TEXTURE_2D, 0, nOfColors, realDisp->w, realDisp->h, 0, - texture_format, GL_UNSIGNED_BYTE, realDisp->pixels ); - - glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT); - glLoadIdentity(); - - // OpenGL barf. Set up the projection to match our screen - int vPort[4]; - glGetIntegerv(GL_VIEWPORT, vPort); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(0, vPort[2], 0, vPort[3], -1, 1); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - glBegin( GL_QUADS ); - - // Needed to move the screen into the right place - int diff = screen->h - realDisp->h; - - // Bottom-left vertex (corner) - glTexCoord2i( 0, 1 ); - glVertex3f(0,diff,0); - - // Bottom-right vertex (corner) - glTexCoord2i( 1, 1 ); - glVertex3f( realDisp->w, diff, 0.f ); - - // Top-right vertex (corner) - glTexCoord2i( 1, 0 ); - glVertex3f( realDisp->w, screen->h, 0.f ); - - // Top-left vertex (corner) - glTexCoord2i( 0, 0 ); - glVertex3f( 0, screen->h, 0.f ); - glEnd(); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); -} - -void SDLGLDriver::swap() -{ - SDL_GL_SwapBuffers(); -} - -void SDLGLDriver::update() -{ - updateNoSwap(); - swap(); -} - -/// Set the window title, as well as the title of the window when -/// "iconified" -void SDLGLDriver::setWindowTitle(const std::string &title, - const std::string &icon) -{ - SDL_WM_SetCaption( title.c_str(), icon.c_str() ); -} - -// Convert the given surface to display format. -static SDL_Surface* convertImage(SDL_Surface* surf) -{ - if(surf != NULL) - { - // Convert the image to the display buffer format, for faster - // blitting - SDL_Surface *surf2 = SDL_DisplayFormat(surf); - SDL_FreeSurface(surf); - surf = surf2; - } - return surf; -} - -/// Load sprite from an image file, using SDL_image. -Sprite* SDLGLDriver::loadImage(const std::string &file) -{ - SDL_Surface *surf = IMG_Load(file.c_str()); - surf = convertImage(surf); - if(surf == NULL) - throw std::runtime_error("SDL failed to load image file '" + file + "'"); - return spriteFromSDL(surf); -} - -/// Load sprite from an SDL_RWops structure. autoFree determines -/// whether the RWops struct should be closed/freed after use. -Sprite* SDLGLDriver::loadImage(SDL_RWops *src, bool autoFree) -{ - SDL_Surface *surf = IMG_Load_RW(src, autoFree); - surf = convertImage(surf); - if(surf == NULL) - throw std::runtime_error("SDL failed to load image"); - return spriteFromSDL(surf); -} - -/// Load a sprite from an image file stored in memory. Uses -/// SDL_image. -Sprite* SDLGLDriver::loadImage(const void* data, size_t size) -{ - SDL_RWops *rw = SDL_RWFromConstMem(data, size); - return loadImage(rw, true); -} - -void SDLGLDriver::setGamma(float red, float green, float blue) -{ - SDL_SetGamma(red,green,blue); -} - -/// Convert an existing SDL surface into a sprite -Sprite* SDLGLDriver::spriteFromSDL(SDL_Surface *surf, bool autoFree) -{ - assert(surf); - return new SDLGL_Sprite(surf, autoFree); -} - -void SDLGLDriver::sleep(int ms) { SDL_Delay(ms); } -unsigned int SDLGLDriver::ticks() { return SDL_GetTicks(); } diff --git a/libs/mangle/rend2d/servers/sdl_gl_driver.hpp b/libs/mangle/rend2d/servers/sdl_gl_driver.hpp deleted file mode 100644 index d116e3659..000000000 --- a/libs/mangle/rend2d/servers/sdl_gl_driver.hpp +++ /dev/null @@ -1,132 +0,0 @@ -#ifndef MANGLE_DRAW2D_SDLGL_H -#define MANGLE_DRAW2D_SDLGL_H - -/** This driver is similar to SDLDriver, except that it uses SDL on - top of OpenGL. - - I've decided to make it a separate file instead of just adding - optional OpenGL support to the original, so that pure SDL users - don't have to add OpenGL as a dependency. - */ - -#include "../driver.hpp" - -// Predeclarations keep the streets safe at night -struct SDL_Surface; -struct SDL_RWops; - -namespace Mangle -{ - namespace Rend2D - { - /// SDL-implementation of Sprite - struct SDLGL_Sprite : Sprite - { - /** Draw a sprite in the given position. Can only draw other SDL - sprites. - */ - void draw(Sprite *s, // Must be SDLGL_Sprite - int x, int y, // Destination position - int sx=0, int sy=0, // Source position - int w=-1, int h=-1 // Amount to draw. -1 means remainder. - ); - - SDLGL_Sprite(SDL_Surface *s, bool autoDelete=true); - ~SDLGL_Sprite(); - - // Information retrieval - virtual int width(); - virtual int height(); - SDL_Surface *getSurface() { return surface; } - - // Fill with a given pixel value - void fill(int value); - - private: - // The SDL surface - SDL_Surface* surface; - - // If true, delete this surface when the canvas is destructed - bool autoDel; - }; - - class SDLGLDriver : public Driver - { - // The main display surface - SDLGL_Sprite *display; - - // The screen surface. This is completely unused. - SDL_Surface *screen; - - // The display surface and main GL texture. These are used when - // drawing the entire screen as one surface, as a drop-in - // replacement for SDLDriver. - SDL_Surface *realDisp; - unsigned int texture; - int nOfColors, texture_format; - - public: - SDLGLDriver(); - ~SDLGLDriver(); - - /// Sets the video mode. Will create the window if it is not - /// already set up. Note that for SDL, bpp=0 means use current - /// bpp. - void setVideoMode(int width, int height, int bpp=0, bool fullscreen=false); - - /// Update the screen - void update(); - - /// Calls SDL_GL_SwapBuffers - void swap(); - - /// Draw surface to screen but do not call SDL_GL_SwapBuffers() - void updateNoSwap(); - - /// Set the window title, as well as the title of the window - /// when "iconified" - void setWindowTitle(const std::string &title, - const std::string &icon); - - // Include overloads from our Glorious parent - using Driver::setWindowTitle; - - /// Load sprite from an image file, using SDL_image. - Sprite* loadImage(const std::string &file); - - /// Load sprite from an SDL_RWops structure. autoFree determines - /// whether the RWops struct should be closed/freed after use. - Sprite* loadImage(SDL_RWops *src, bool autoFree=false); - - /// Load a sprite from an image file stored in memory. Uses - /// SDL_image. - Sprite* loadImage(const void* data, size_t size); - - /// Set gamma value - void setGamma(float gamma) { setGamma(gamma,gamma,gamma); } - - /// Set gamma individually for red, green, blue - void setGamma(float red, float green, float blue); - - /// Convert an existing SDL surface into a sprite - Sprite* spriteFromSDL(SDL_Surface *surf, bool autoFree = true); - - // Get width and height - int width() { return display ? display->width() : 0; } - int height() { return display ? display->height() : 0; } - - /// Get the screen sprite - Sprite *getScreen() { return display; } - - /// Not really a graphic-related function, but very - /// handly. Sleeps the given number of milliseconds using - /// SDL_Delay(). - void sleep(int ms); - - /// Get the number of ticks since SDL initialization, using - /// SDL_GetTicks(). - unsigned int ticks(); - }; - } -} -#endif diff --git a/libs/mangle/rend2d/sprite.hpp b/libs/mangle/rend2d/sprite.hpp deleted file mode 100644 index f49da6cb6..000000000 --- a/libs/mangle/rend2d/sprite.hpp +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef MANGLE_REND2D_SPRITE_H -#define MANGLE_REND2D_SPRITE_H - -namespace Mangle -{ - namespace Rend2D - { - /** - A pointer to sprite data for direct drawing. Only to be used - while the corresponding sprite is locked. - */ - struct SpriteData - { - void *pixels; // Pixel data - int w, h; // Width and height - int pitch, bypp; // Pitch (bytes) and bytes per pixel - }; - - /** - A Sprite is either a bitmap to be drawn or an output of area - for blitting other bitmaps, or both. They are created by the - Driver. - */ - struct Sprite - { - /// Draw a sprite in the given position - virtual void draw(Sprite *s, // The sprite to draw - int x, int y, // Destination position - int sx=0, int sy=0, // Source position - int w=-1, int h=-1 // Amount to draw. -1 means remainder. - ) = 0; - - virtual ~Sprite() {} - - // Information retrieval - virtual int width() = 0; - virtual int height() = 0; - - /// Fill the sprite with the given pixel value. The pixel format - /// depends on the format of the sprite. - virtual void fill(int value) = 0; - - /// Set one pixel value. The pixel format depends on the sprite - /// format. This is not expected to be fast, and in some - /// implementations may not work at all. - virtual void pixel(int x, int y, int value) {} - - /// Lock sprite for direct drawing, and return a struct - /// containing the necessary pointer. When finished, unlock the - /// sprite with unlock(). May return NULL, if so then direct - /// drawing is not possible. - virtual const SpriteData *lock() { return NULL; } - virtual void unlock() {} - }; - } -} -#endif diff --git a/libs/mangle/rend2d/tests/.gitignore b/libs/mangle/rend2d/tests/.gitignore deleted file mode 100644 index 814490404..000000000 --- a/libs/mangle/rend2d/tests/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*_test diff --git a/libs/mangle/rend2d/tests/Makefile b/libs/mangle/rend2d/tests/Makefile deleted file mode 100644 index d430f60a9..000000000 --- a/libs/mangle/rend2d/tests/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -GCC=g++ -Wall -Werror - -all: sdl_test sdl_move_test sdlgl_move_test - -sdl_test: sdl_test.cpp - $(GCC) $< ../servers/sdl_driver.cpp -o $@ -I/usr/include/SDL/ -lSDL -lSDL_image - -sdl_move_test: sdl_move_test.cpp ../servers/sdl_driver.cpp - $(GCC) $^ -o $@ -I/usr/include/SDL/ -lSDL -lSDL_image - -sdlgl_move_test: sdlgl_move_test.cpp ../servers/sdl_gl_driver.cpp - $(GCC) $^ -o $@ -I/usr/include/SDL/ -lSDL -lSDL_image -lGL - -clean: - rm *_test diff --git a/libs/mangle/rend2d/tests/output/sdl_move_test.out b/libs/mangle/rend2d/tests/output/sdl_move_test.out deleted file mode 100644 index e69de29bb..000000000 diff --git a/libs/mangle/rend2d/tests/output/sdl_test.out b/libs/mangle/rend2d/tests/output/sdl_test.out deleted file mode 100644 index 4528e1a98..000000000 --- a/libs/mangle/rend2d/tests/output/sdl_test.out +++ /dev/null @@ -1,11 +0,0 @@ -Loading SDL driver. -Creating window. -Current mode: 640x480 -Setting fancy title, cause we like fancy titles. -Loading tile1-blue.png from file. -Loading tile1-yellow.png from memory. -Going bananas. -Taking a breather. -WOW DID YOU SEE THAT!? -Mucking about with the gamma settings -Done. diff --git a/libs/mangle/rend2d/tests/output/sdlgl_move_test.out b/libs/mangle/rend2d/tests/output/sdlgl_move_test.out deleted file mode 100644 index e69de29bb..000000000 diff --git a/libs/mangle/rend2d/tests/sdl_move_test.cpp b/libs/mangle/rend2d/tests/sdl_move_test.cpp deleted file mode 100644 index bfbca98fa..000000000 --- a/libs/mangle/rend2d/tests/sdl_move_test.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include - -using namespace std; - -#include "../servers/sdl_driver.hpp" - -using namespace Mangle::Rend2D; - -int main() -{ - SDLDriver sdl; - - sdl.setVideoMode(640,480,0,false); - sdl.setWindowTitle("Testing 123"); - Sprite *screen = sdl.getScreen(); - const char* imgName = "tile1-blue.png"; - Sprite *image = sdl.loadImage(imgName); - - for(int frames=0; frames<170; frames++) - { - screen->fill(0); - for(int j=0; j<10; j++) - for(int i=0; i<25; i++) - screen->draw(image, 2*frames+30*j, 20*i); - sdl.update(); - sdl.sleep(10); - } - return 0; -} diff --git a/libs/mangle/rend2d/tests/sdl_test.cpp b/libs/mangle/rend2d/tests/sdl_test.cpp deleted file mode 100644 index 0355112e6..000000000 --- a/libs/mangle/rend2d/tests/sdl_test.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include - -using namespace std; - -#include "../servers/sdl_driver.hpp" - -using namespace Mangle::Rend2D; - -int main() -{ - cout << "Loading SDL driver.\n"; - SDLDriver sdl; - - cout << "Creating window.\n"; - sdl.setVideoMode(640,480); - cout << "Current mode: " << sdl.width() << "x" << sdl.height() << endl; - - cout << "Setting fancy title, cause we like fancy titles.\n"; - sdl.setWindowTitle("Chief executive window"); - - // Display surface - Sprite *screen = sdl.getScreen(); - - const char* imgName = "tile1-blue.png"; - cout << "Loading " << imgName << " from file.\n"; - Sprite *image = sdl.loadImage(imgName); - - const char* imgName2 = "tile1-yellow.png"; - cout << "Loading " << imgName2 << " from memory.\n"; - Sprite *image2; - { - // This is hard-coded for file sizes below 500 bytes, so obviously - // you shouldn't mess with the image files. - ifstream file(imgName2, ios::binary); - char buf[500]; - file.read(buf, 500); - int size = file.gcount(); - image2 = sdl.loadImage(buf, size); - } - - cout << "Going bananas.\n"; - for(int i=1; i<20; i++) - screen->draw(image, 30*i, 20*i); - - cout << "Taking a breather.\n"; - sdl.update(); - for(int i=1; i<20; i++) - screen->draw(image2, 30*(20-i), 20*i); - sdl.sleep(800); - sdl.update(); - cout << "WOW DID YOU SEE THAT!?\n"; - sdl.sleep(800); - - cout << "Mucking about with the gamma settings\n"; - sdl.setGamma(2.0, 0.1, 0.8); - sdl.sleep(100); - sdl.setGamma(0.6, 2.1, 2.1); - sdl.sleep(100); - sdl.setGamma(1.6); - sdl.sleep(100); - - cout << "Done.\n"; - return 0; -} diff --git a/libs/mangle/rend2d/tests/sdlgl_move_test.cpp b/libs/mangle/rend2d/tests/sdlgl_move_test.cpp deleted file mode 100644 index b769ee837..000000000 --- a/libs/mangle/rend2d/tests/sdlgl_move_test.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include - -using namespace std; - -#include "../servers/sdl_gl_driver.hpp" - -using namespace Mangle::Rend2D; - -int main() -{ - SDLGLDriver sdl; - - sdl.setVideoMode(640,480,0,false); - sdl.setWindowTitle("Testing 123"); - Sprite *screen = sdl.getScreen(); - const char* imgName = "tile1-blue.png"; - Sprite *image = sdl.loadImage(imgName); - - for(int frames=0; frames<170; frames++) - { - screen->fill(0); - for(int j=0; j<10; j++) - for(int i=0; i<25; i++) - screen->draw(image, 2*frames+30*j, 20*i); - sdl.update(); - sdl.sleep(5); - } - - return 0; -} diff --git a/libs/mangle/rend2d/tests/test.sh b/libs/mangle/rend2d/tests/test.sh deleted file mode 100755 index 2d07708ad..000000000 --- a/libs/mangle/rend2d/tests/test.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -make || exit - -mkdir -p output - -PROGS=*_test - -for a in $PROGS; do - if [ -f "output/$a.out" ]; then - echo "Running $a:" - ./$a | diff output/$a.out - - else - echo "Creating $a.out" - ./$a > "output/$a.out" - git add "output/$a.out" - fi -done diff --git a/libs/mangle/rend2d/tests/tile1-blue.png b/libs/mangle/rend2d/tests/tile1-blue.png deleted file mode 100644 index 066e6f8eb..000000000 Binary files a/libs/mangle/rend2d/tests/tile1-blue.png and /dev/null differ diff --git a/libs/mangle/rend2d/tests/tile1-yellow.png b/libs/mangle/rend2d/tests/tile1-yellow.png deleted file mode 100644 index 2aaf9015d..000000000 Binary files a/libs/mangle/rend2d/tests/tile1-yellow.png and /dev/null differ diff --git a/libs/mangle/testall.sh b/libs/mangle/testall.sh deleted file mode 100755 index b93fee215..000000000 --- a/libs/mangle/testall.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -function run() -{ - echo "TESTING $1" - cd "$1/tests/" - ./test.sh - cd ../../ -} - -run stream -run vfs -run sound -run input -run rend2d -run . diff --git a/libs/mangle/tests/.gitignore b/libs/mangle/tests/.gitignore deleted file mode 100644 index 814490404..000000000 --- a/libs/mangle/tests/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*_test diff --git a/libs/mangle/tests/Makefile b/libs/mangle/tests/Makefile deleted file mode 100644 index d912c0784..000000000 --- a/libs/mangle/tests/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -GCC=g++ -I../ - -all: ogrevfs_audiere_openal_test - -I_OGRE=$(shell pkg-config --cflags OGRE) -L_OGRE=$(shell pkg-config --libs OGRE) -L_OPENAL=$(shell pkg-config --libs openal) -L_AUDIERE=-laudiere - -ogrevfs_audiere_openal_test: ogrevfs_audiere_openal_test.cpp ../vfs/servers/ogre_vfs.cpp ../sound/sources/audiere_source.cpp ../sound/outputs/openal_out.cpp ../stream/clients/audiere_file.cpp - $(GCC) $^ -o $@ $(I_OGRE) $(L_OGRE) $(L_OPENAL) $(L_AUDIERE) - -clean: - rm *_test diff --git a/libs/mangle/tests/ogrevfs_audiere_openal_test.cpp b/libs/mangle/tests/ogrevfs_audiere_openal_test.cpp deleted file mode 100644 index 4936538c5..000000000 --- a/libs/mangle/tests/ogrevfs_audiere_openal_test.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - This example combines: - - - the OGRE VFS system (to read from zip) - - Audiere (for decoding sound data) - - OpenAL (for sound playback) - - */ - -#include "sound/filters/openal_audiere.hpp" -#include "vfs/servers/ogre_vfs.hpp" -#include -#include - -using namespace Ogre; -using namespace Mangle; -using namespace std; - -int main() -{ - // Disable Ogre logging - new LogManager; - Log *log = LogManager::getSingleton().createLog(""); - log->setDebugOutputEnabled(false); - - // Set up Root - Root *root = new Root("","",""); - - // Add zip file with a sound in it - root->addResourceLocation("sound.zip", "Zip", "General"); - - // Ogre file system - VFS::OgreVFS vfs; - - // The main sound system - Sound::OpenAL_Audiere_Factory mg; - Sound::SoundPtr snd = mg.load(vfs.open("owl.ogg")); - - cout << "Playing 'owl.ogg' from 'sound.zip'\n"; - snd->play(); - - while(snd->isPlaying()) - { - usleep(10000); - if(mg.needsUpdate) mg.update(); - } - - return 0; -} diff --git a/libs/mangle/tests/output/ogrevfs_audiere_openal_test.out b/libs/mangle/tests/output/ogrevfs_audiere_openal_test.out deleted file mode 100644 index 28ea8a71b..000000000 --- a/libs/mangle/tests/output/ogrevfs_audiere_openal_test.out +++ /dev/null @@ -1 +0,0 @@ -Playing 'owl.ogg' from 'sound.zip' diff --git a/libs/mangle/tests/sound.zip b/libs/mangle/tests/sound.zip deleted file mode 100644 index fd32b3529..000000000 Binary files a/libs/mangle/tests/sound.zip and /dev/null differ diff --git a/libs/mangle/tests/test.sh b/libs/mangle/tests/test.sh deleted file mode 100755 index 2d07708ad..000000000 --- a/libs/mangle/tests/test.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -make || exit - -mkdir -p output - -PROGS=*_test - -for a in $PROGS; do - if [ -f "output/$a.out" ]; then - echo "Running $a:" - ./$a | diff output/$a.out - - else - echo "Creating $a.out" - ./$a > "output/$a.out" - git add "output/$a.out" - fi -done diff --git a/libs/mangle/tools/shared_ptr.hpp b/libs/mangle/tools/shared_ptr.hpp deleted file mode 100644 index 3d073fc24..000000000 --- a/libs/mangle/tools/shared_ptr.hpp +++ /dev/null @@ -1,3 +0,0 @@ -// This file should include whatever it needs to define the boost/tr1 -// shared_ptr<> and weak_ptr<> templates. -#include diff --git a/libs/openengine/gui/events.cpp b/libs/openengine/gui/events.cpp deleted file mode 100644 index 35b01158b..000000000 --- a/libs/openengine/gui/events.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include -#include - -#include "events.hpp" - -using namespace OIS; -using namespace OEngine::GUI; - -EventInjector::EventInjector(MyGUI::Gui *g) - : gui(g), enabled(true) - , mMouseX(0) - , mMouseY(0) -{ - assert(gui); - const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - mMouseX = viewSize.width/2; - mMouseY = viewSize.height/2; -} - -void EventInjector::event(Type type, int index, const void *p) -{ - if(!enabled) return; - - if(type & EV_Keyboard) - { - KeyEvent *key = (KeyEvent*)p; - MyGUI::KeyCode code = MyGUI::KeyCode::Enum(key->key); - if(type == EV_KeyDown) - { - /* - This is just a first approximation. Apparently, OIS is - unable to provide reliable unicode characters on all - platforms. At least that's what I surmise from the amount - of workaround that the MyGUI folks have put in place for - this. See Common/Input/OIS/InputManager.cpp in the MyGUI - sources for details. - - If the work they have done there is indeed necessary (I - haven't tested that it is, although I have had dubious - experinces with OIS events in the past), then we should - probably adapt all that code here. Or even better, - directly into the OIS input manager in Mangle. - - Note that all this only affects the 'text' field, and - should thus only affect typed text in input boxes (which - is still pretty significant.) - */ - MyGUI::Char text = (MyGUI::Char)key->text; - MyGUI::InputManager::getInstance().injectKeyPress(code,text); - } - else - { - MyGUI::InputManager::getInstance().injectKeyRelease(code); - } - } - else if(type & EV_Mouse) - { - MouseEvent *mouse = (MouseEvent*)p; - MyGUI::MouseButton id = MyGUI::MouseButton::Enum(index); - - const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - - // Update mouse position - mMouseX += mouse->state.X.rel; - mMouseY += mouse->state.Y.rel; - mMouseX = std::max(0, std::min(mMouseX, viewSize.width)); - mMouseY = std::max(0, std::min(mMouseY, viewSize.height)); - - if(type == EV_MouseDown) - MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, id); - else if(type == EV_MouseUp) - MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, id); - else - MyGUI::InputManager::getInstance().injectMouseMove(mMouseX, mMouseY, mouse->state.Z.abs); - } -} diff --git a/libs/openengine/gui/events.hpp b/libs/openengine/gui/events.hpp deleted file mode 100644 index 10c5309bc..000000000 --- a/libs/openengine/gui/events.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef OENGINE_MYGUI_EVENTS_H -#define OENGINE_MYGUI_EVENTS_H - -#include - -namespace MyGUI -{ - class Gui; -} - -namespace OEngine { -namespace GUI -{ - /** Event handler that injects OIS events into MyGUI - */ - class EventInjector : public Mangle::Input::Event - { - MyGUI::Gui *gui; - - int mMouseX; - int mMouseY; - - public: - bool enabled; - - EventInjector(MyGUI::Gui *g); - void event(Type type, int index, const void *p); - }; - - typedef boost::shared_ptr EventInjectorPtr; -}} -#endif diff --git a/libs/openengine/ogre/mouselook.cpp b/libs/openengine/ogre/mouselook.cpp deleted file mode 100644 index 841bab603..000000000 --- a/libs/openengine/ogre/mouselook.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "mouselook.hpp" - -#include -#include -#include - -using namespace OIS; -using namespace Ogre; -using namespace OEngine::Render; - -void MouseLookEvent::event(Type type, int index, const void *p) -{ - if(type != EV_MouseMove || camera == NULL) return; - - MouseEvent *arg = (MouseEvent*)(p); - - float x = arg->state.X.rel * sensX; - float y = arg->state.Y.rel * sensY; - - camera->getParentSceneNode()->getParentSceneNode()->yaw(Degree(-x)); - camera->getParentSceneNode()->pitch(Degree(-y)); - if(flipProt) - { - // The camera before pitching - /*Quaternion nopitch = camera->getParentSceneNode()->getOrientation(); - - camera->getParentSceneNode()->pitch(Degree(-y)); - - // Apply some failsafe measures against the camera flipping - // upside down. Is the camera close to pointing straight up or - // down? - if(Ogre::Vector3(camera->getParentSceneNode()->getOrientation()*Ogre::Vector3::UNIT_Y)[1] <= 0.1) - // If so, undo the last pitch - camera->getParentSceneNode()->setOrientation(nopitch);*/ - //camera->getU - - // Angle of rotation around the X-axis. - float pitchAngle = (2 * Ogre::Degree(Ogre::Math::ACos(camera->getParentSceneNode()->getOrientation().w)).valueDegrees()); - - // Just to determine the sign of the angle we pick up above, the - // value itself does not interest us. - float pitchAngleSign = camera->getParentSceneNode()->getOrientation().x; - - // Limit the pitch between -90 degress and +90 degrees, Quake3-style. - if (pitchAngle > 90.0f) - { - if (pitchAngleSign > 0) - // Set orientation to 90 degrees on X-axis. - camera->getParentSceneNode()->setOrientation(Ogre::Quaternion(Ogre::Math::Sqrt(0.5f), - Ogre::Math::Sqrt(0.5f), 0, 0)); - else if (pitchAngleSign < 0) - // Sets orientation to -90 degrees on X-axis. - camera->getParentSceneNode()->setOrientation(Ogre::Quaternion(Ogre::Math::Sqrt(0.5f), - -Ogre::Math::Sqrt(0.5f), 0, 0)); - } - } -} diff --git a/libs/openengine/ogre/mouselook.hpp b/libs/openengine/ogre/mouselook.hpp deleted file mode 100644 index 6e09ff4a1..000000000 --- a/libs/openengine/ogre/mouselook.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef OENGINE_OGRE_MOUSELOOK_H -#define OENGINE_OGRE_MOUSELOOK_H - -/* - A mouse-look class for Ogre. Accepts input events from Mangle::Input - and translates them. - - You can adjust the mouse sensibility and switch to a different - camera. The mouselook class also has an optional wrap protection - that keeps the camera from flipping upside down. - - You can disable the mouse looker at any time by calling - setCamera(NULL), and reenable it by setting the camera back. - - NOTE: The current implementation will ONLY work for native OIS - events. - */ - -#include - -namespace Ogre -{ - class Camera; -} - -namespace OEngine { -namespace Render -{ - class MouseLookEvent : public Mangle::Input::Event - { - Ogre::Camera* camera; - float sensX, sensY; // Mouse sensibility - bool flipProt; // Flip protection - - public: - MouseLookEvent(Ogre::Camera *cam=NULL, - float sX=0.2, float sY=0.2, - bool prot=true) - : camera(cam) - , sensX(sX) - , sensY(sY) - , flipProt(prot) - {} - - void setCamera(Ogre::Camera *cam) - { camera = cam; } - void setSens(float sX, float sY) - { sensX = sX; sensY = sY; } - void setProt(bool p) { flipProt = p; } - - void event(Type type, int index, const void *p); - }; - - typedef boost::shared_ptr MouseLookEventPtr; -}} -#endif